feat: tema claro ou escuro
Some checks failed
Deploy QR Rapido / test (push) Successful in 3m45s
Deploy QR Rapido / build-and-push (push) Failing after 7s
Deploy QR Rapido / deploy-staging (push) Has been skipped
Deploy QR Rapido / deploy-production (push) Has been skipped

This commit is contained in:
Ricardo Carneiro 2025-07-29 22:42:39 -03:00
parent b189ea7275
commit a8faf0ef2f
18 changed files with 2410 additions and 250 deletions

View File

@ -117,8 +117,8 @@ namespace QRRapidoApp.Controllers
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity), authProperties); new ClaimsPrincipal(claimsIdentity), authProperties);
var returnUrl = result.Properties?.Items["returnUrl"] ?? "/"; var returnUrl = result.Properties?.Items != null && result.Properties.Items.ContainsKey("returnUrl") ? result.Properties?.Items["returnUrl"] : "/";
return Redirect(returnUrl); return RedirectToAction("Index", "Home");
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -65,7 +65,9 @@ namespace QRRapidoApp.Middleware
var specialRoutes = new[] var specialRoutes = new[]
{ {
"api/", "health", "_framework/", "lib/", "css/", "js/", "images/", "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)); return specialRoutes.Any(route => path.StartsWith(route, StringComparison.OrdinalIgnoreCase));

View File

@ -113,15 +113,37 @@ builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationSc
options.ExpireTimeSpan = TimeSpan.FromDays(30); options.ExpireTimeSpan = TimeSpan.FromDays(30);
options.SlidingExpiration = true; options.SlidingExpiration = true;
}) })
.AddGoogle(GoogleDefaults.AuthenticationScheme, options => .AddGoogle(options =>
{ {
options.ClientId = builder.Configuration["Authentication:Google:ClientId"]; options.ClientId = builder.Configuration["Authentication:Google:ClientId"];
options.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"]; 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.ClientId = builder.Configuration["Authentication:Microsoft:ClientId"];
options.ClientSecret = builder.Configuration["Authentication:Microsoft:ClientSecret"]; 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 // Stripe Configuration
@ -231,6 +253,16 @@ app.UseMiddleware<LastLoginUpdateMiddleware>();
// Health check endpoint // Health check endpoint
app.MapHealthChecks("/health"); 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) // Language routes (must be first)
app.MapControllerRoute( app.MapControllerRoute(
name: "localized", name: "localized",

View File

@ -220,4 +220,476 @@
<data name="Success" xml:space="preserve"> <data name="Success" xml:space="preserve">
<value>QR Code saved to history!</value> <value>QR Code saved to history!</value>
</data> </data>
<data name="CreateQRCodeQuickly" xml:space="preserve">
<value>Create QR Code Quickly</value>
</data>
<data name="PremiumUserActive" xml:space="preserve">
<value>Premium User Active</value>
</data>
<data name="NoAdsHistoryUnlimitedQR" xml:space="preserve">
<value>No Ads • History • Unlimited QR</value>
</data>
<data name="UnlimitedToday" xml:space="preserve">
<value>Unlimited today</value>
</data>
<data name="QRCodesRemaining" xml:space="preserve">
<value>QR codes remaining</value>
</data>
<data name="QRCodeType" xml:space="preserve">
<value>QR Code Type</value>
</data>
<data name="SelectType" xml:space="preserve">
<value>Select type</value>
</data>
<data name="URLLink" xml:space="preserve">
<value>URL/Link</value>
</data>
<data name="SimpleText" xml:space="preserve">
<value>Simple Text</value>
</data>
<data name="VCard" xml:space="preserve">
<value>Business Card</value>
</data>
<data name="DynamicQRPremium" xml:space="preserve">
<value>Dynamic QR (Premium)</value>
</data>
<data name="EnterQRCodeContent" xml:space="preserve">
<value>Enter your QR code content here...</value>
</data>
<data name="ContentHints" xml:space="preserve">
<value>Content hints</value>
</data>
<data name="Classic" xml:space="preserve">
<value>Classic</value>
</data>
<data name="Modern" xml:space="preserve">
<value>Modern</value>
</data>
<data name="Colorful" xml:space="preserve">
<value>Colorful</value>
</data>
<!-- Premium Upgrade Page -->
<data name="PremiumAccelerateProductivity" xml:space="preserve">
<value>Accelerate your productivity with the world's fastest QR generator</value>
</data>
<data name="ThreeTimesFaster" xml:space="preserve">
<value>3x faster than the competition</value>
</data>
<data name="CurrentStatus" xml:space="preserve">
<value>Current Status</value>
</data>
<data name="YouHave" xml:space="preserve">
<value>You have</value>
</data>
<data name="DaysRemainingNoAds" xml:space="preserve">
<value>days remaining without ads.</value>
</data>
<data name="UpgradeNowForever" xml:space="preserve">
<value>Upgrade now and have premium access forever!</value>
</data>
<data name="DaysRemaining" xml:space="preserve">
<value>days remaining</value>
</data>
<data name="MostPopularPlan" xml:space="preserve">
<value>The most popular plan</value>
</data>
<data name="PerMonth" xml:space="preserve">
<value>per month</value>
</data>
<data name="UnlimitedQRCodes" xml:space="preserve">
<value>Unlimited QR codes</value>
</data>
<data name="UltraFastGeneration04s" xml:space="preserve">
<value>Ultra-fast generation (0.4s)</value>
</data>
<data name="NoAdsForever" xml:space="preserve">
<value>No ads forever</value>
</data>
<data name="DynamicQRCodes" xml:space="preserve">
<value>Dynamic QR codes</value>
</data>
<data name="RealTimeAnalytics" xml:space="preserve">
<value>Real-time analytics</value>
</data>
<data name="PrioritySupport" xml:space="preserve">
<value>Priority support</value>
</data>
<data name="DeveloperAPI" xml:space="preserve">
<value>Developer API</value>
</data>
<data name="UpgradeNowButton" xml:space="preserve">
<value>Upgrade Now</value>
</data>
<data name="SecurePaymentStripe" xml:space="preserve">
<value>Secure payment via Stripe</value>
</data>
<data name="CancelAnytime" xml:space="preserve">
<value>Cancel anytime</value>
</data>
<data name="PlanComparison" xml:space="preserve">
<value>Plan Comparison</value>
</data>
<data name="Feature" xml:space="preserve">
<value>Feature</value>
</data>
<data name="QRCodesPerDay" xml:space="preserve">
<value>QR codes per day</value>
</data>
<data name="Unlimited" xml:space="preserve">
<value>Unlimited</value>
</data>
<data name="GenerationSpeed" xml:space="preserve">
<value>Generation speed</value>
</data>
<data name="Ads" xml:space="preserve">
<value>Ads</value>
</data>
<data name="NoAds" xml:space="preserve">
<value>No ads</value>
</data>
<data name="DetailedAnalytics" xml:space="preserve">
<value>Detailed analytics</value>
</data>
<data name="SpeedDemonstration" xml:space="preserve">
<value>Speed Demonstration</value>
</data>
<data name="Competitors" xml:space="preserve">
<value>Competitors</value>
</data>
<data name="AverageTime" xml:space="preserve">
<value>Average time</value>
</data>
<data name="ElevenTimesFaster" xml:space="preserve">
<value>11x faster!</value>
</data>
<data name="FAQ" xml:space="preserve">
<value>Frequently Asked Questions</value>
</data>
<data name="CanCancelAnytime" xml:space="preserve">
<value>Can I cancel anytime?</value>
</data>
<data name="CancelAnytimeAnswer" xml:space="preserve">
<value>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.</value>
</data>
<data name="WhatAreDynamicQR" xml:space="preserve">
<value>What are dynamic QR codes?</value>
</data>
<data name="DynamicQRAnswer" xml:space="preserve">
<value>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.</value>
</data>
<data name="HowPrioritySupport" xml:space="preserve">
<value>How does priority support work?</value>
</data>
<data name="PrioritySupportAnswer" xml:space="preserve">
<value>Premium users receive responses within 2 business hours via email, direct chat access and specialized technical support.</value>
</data>
<data name="PaymentProcessingError" xml:space="preserve">
<value>Payment processing error: </value>
</data>
<data name="PaymentErrorTryAgain" xml:space="preserve">
<value>Payment processing error. Please try again.</value>
</data>
<!-- Ad Space -->
<data name="Advertisement" xml:space="preserve">
<value>Advertisement</value>
</data>
<data name="PremiumUserNoAds" xml:space="preserve">
<value>✨ Premium User - No ads!</value>
</data>
<data name="UpgradePremiumRemoveAds" xml:space="preserve">
<value>Upgrade to Premium and remove ads!</value>
</data>
<data name="PremiumBenefitsShort" xml:space="preserve">
<value>Premium: No ads + History + Unlimited QR</value>
</data>
<!-- Login Page -->
<data name="LoginAndGet" xml:space="preserve">
<value>Login with your account and get:</value>
</data>
<data name="ThirtyDaysNoAds" xml:space="preserve">
<value>30 days without ads</value>
</data>
<data name="FiftyQRCodesPerDay" xml:space="preserve">
<value>50 QR codes/day</value>
</data>
<data name="QRCodeHistory" xml:space="preserve">
<value>QR code history</value>
</data>
<data name="LoginWithGoogle" xml:space="preserve">
<value>Login with Google</value>
</data>
<data name="LoginWithMicrosoft" xml:space="preserve">
<value>Login with Microsoft</value>
</data>
<data name="SpecialOfferLogin" xml:space="preserve">
<value>Special Offer!</value>
</data>
<data name="LoginAutomaticallyGain" xml:space="preserve">
<value>By logging in, you automatically get</value>
</data>
<data name="AndCanGenerate" xml:space="preserve">
<value>and can generate up to</value>
</data>
<data name="ForFree" xml:space="preserve">
<value>for free.</value>
</data>
<data name="NoRegisterWithoutPermission" xml:space="preserve">
<value>We don't register you without your permission.</value>
</data>
<data name="PrivacyPolicy" xml:space="preserve">
<value>Privacy Policy</value>
</data>
<!-- Payment Pages -->
<data name="PaymentSuccessful" xml:space="preserve">
<value>Payment successful!</value>
</data>
<data name="BackToHome" xml:space="preserve">
<value>Back to Home</value>
</data>
<data name="PaymentCanceled" xml:space="preserve">
<value>Payment canceled.</value>
</data>
<data name="ViewPlans" xml:space="preserve">
<value>View Plans</value>
</data>
<data name="UnlockFullPowerQRRapido" xml:space="preserve">
<value>Unlock the Full Power of QRRapido</value>
</data>
<data name="UnlimitedAccessNoAdsExclusive" xml:space="preserve">
<value>Unlimited access, no ads and exclusive features for maximum productivity.</value>
</data>
<data name="MonthlyPlan" xml:space="preserve">
<value>Monthly Plan</value>
</data>
<data name="IdealToStartExploring" xml:space="preserve">
<value>Ideal to start exploring premium features.</value>
</data>
<data name="SubscribeNow" xml:space="preserve">
<value>Subscribe Now</value>
</data>
<data name="AnnualPlan" xml:space="preserve">
<value>Annual Plan</value>
</data>
<data name="Recommended" xml:space="preserve">
<value>Recommended</value>
</data>
<data name="PerYear" xml:space="preserve">
<value>/year</value>
</data>
<data name="SaveMoney" xml:space="preserve">
<value>Save $</value>
</data>
<data name="BestValueFrequentUsers" xml:space="preserve">
<value>Best value for frequent users.</value>
</data>
<data name="SubscribeAnnualPlan" xml:space="preserve">
<value>Subscribe to Annual Plan</value>
</data>
<data name="AllPlansInclude" xml:space="preserve">
<value>All plans include:</value>
</data>
<data name="Redirecting" xml:space="preserve">
<value>Redirecting...</value>
</data>
<data name="PaymentInitializationError" xml:space="preserve">
<value>An error occurred while initializing payment. Please try again.</value>
</data>
<!-- History Page -->
<data name="QRCodesSavedHere" xml:space="preserve">
<value>Your generated QR codes are saved here for future download</value>
</data>
<data name="GenerateNewQRCode" xml:space="preserve">
<value>Generate New QR Code</value>
</data>
<data name="Type" xml:space="preserve">
<value>Type:</value>
</data>
<data name="CreatedOn" xml:space="preserve">
<value>Created on:</value>
</data>
<data name="ShowingRecent50QRCodes" xml:space="preserve">
<value>Showing the 50 most recent QR codes. Older ones are automatically removed.</value>
</data>
<data name="NoQRCodeFound" xml:space="preserve">
<value>No QR Code found</value>
</data>
<data name="QRCodesWillAppearHere" xml:space="preserve">
<value>When you generate QR codes while logged in, they will appear here for future download.</value>
</data>
<data name="GenerateFirstQRCode" xml:space="preserve">
<value>Generate First QR Code</value>
</data>
<data name="ErrorRegeneratingQR" xml:space="preserve">
<value>Error regenerating QR Code. Please try again.</value>
</data>
<!-- Home Page -->
<data name="SmallSize200px" xml:space="preserve">
<value>Small (200px)</value>
</data>
<data name="MediumSize300px" xml:space="preserve">
<value>Medium (300px)</value>
</data>
<data name="LargeSize500px" xml:space="preserve">
<value>Large (500px)</value>
</data>
<data name="XLSize800px" xml:space="preserve">
<value>XL (800px)</value>
</data>
<data name="Minimal" xml:space="preserve">
<value>Minimal</value>
</data>
<data name="Large" xml:space="preserve">
<value>Large</value>
</data>
<data name="LogoIcon" xml:space="preserve">
<value>Logo/Icon</value>
</data>
<data name="PNGJPGUp2MB" xml:space="preserve">
<value>PNG, JPG up to 2MB</value>
</data>
<data name="BorderStyle" xml:space="preserve">
<value>Border Style</value>
</data>
<data name="Square" xml:space="preserve">
<value>Square</value>
</data>
<data name="Rounded" xml:space="preserve">
<value>Rounded</value>
</data>
<data name="Circular" xml:space="preserve">
<value>Circular</value>
</data>
<data name="Leaf" xml:space="preserve">
<value>Leaf</value>
</data>
<data name="GenerateQRCodeQuickly" xml:space="preserve">
<value>Generate QR Code Quickly</value>
</data>
<data name="Generating" xml:space="preserve">
<value>Generating...</value>
</data>
<data name="Availability" xml:space="preserve">
<value>Availability</value>
</data>
<data name="QRsGeneratedToday" xml:space="preserve">
<value>QRs generated today</value>
</data>
<data name="YourQRCodeWillAppear" xml:space="preserve">
<value>Your QR code will appear here in seconds</value>
</data>
<data name="UltraFastGenerationGuaranteed" xml:space="preserve">
<value>Ultra-fast generation guaranteed</value>
</data>
<data name="DownloadSVGVector" xml:space="preserve">
<value>Download SVG (Vector)</value>
</data>
<data name="ShareQRCode" xml:space="preserve">
<value>Share QR Code</value>
</data>
<data name="ShareSystem" xml:space="preserve">
<value>Share (System)</value>
</data>
<data name="ToSaveToHistory" xml:space="preserve">
<value>to save to history</value>
</data>
<data name="PriorityGeneration" xml:space="preserve">
<value>Priority generation (0.4s)</value>
</data>
<data name="AcceleratePrice" xml:space="preserve">
<value>Accelerate for $19.90/month</value>
</data>
<data name="TipsFasterQR" xml:space="preserve">
<value>Tips for Faster QR</value>
</data>
<data name="ShortURLsFaster" xml:space="preserve">
<value>Short URLs generate faster</value>
</data>
<data name="LessTextMoreSpeed" xml:space="preserve">
<value>Less text = higher speed</value>
</data>
<data name="SolidColorsOptimize" xml:space="preserve">
<value>Solid colors optimize the process</value>
</data>
<data name="SmallerSizesAccelerate" xml:space="preserve">
<value>Smaller sizes accelerate download</value>
</data>
<data name="WhyQRRapidoFaster" xml:space="preserve">
<value>Why is QR Rapido faster?</value>
</data>
<data name="ComparisonOtherGenerators" xml:space="preserve">
<value>Comparison with other popular generators</value>
</data>
<data name="OptimizedForSpeed" xml:space="preserve">
<value>Optimized for speed</value>
</data>
<data name="CompetitorA" xml:space="preserve">
<value>Competitor A</value>
</data>
<data name="TraditionalGenerator" xml:space="preserve">
<value>Traditional generator</value>
</data>
<data name="CompetitorB" xml:space="preserve">
<value>Competitor B</value>
</data>
<data name="HeavyInterface" xml:space="preserve">
<value>Heavy interface</value>
</data>
<data name="CompetitorC" xml:space="preserve">
<value>Competitor C</value>
</data>
<data name="ManyAds" xml:space="preserve">
<value>Many ads</value>
</data>
<!-- Layout -->
<data name="Average" xml:space="preserve">
<value>average</value>
</data>
<data name="GenerateQRCode" xml:space="preserve">
<value>Generate QR Code</value>
</data>
<data name="Profile" xml:space="preserve">
<value>Profile</value>
</data>
<data name="History" xml:space="preserve">
<value>History</value>
</data>
<data name="PremiumActive" xml:space="preserve">
<value>Premium Active</value>
</data>
<data name="Logout" xml:space="preserve">
<value>Logout</value>
</data>
<data name="LoginThirtyDaysNoAds" xml:space="preserve">
<value>Login = 30 days without ads!</value>
</data>
<data name="FastestQRGeneratorWeb" xml:space="preserve">
<value>The fastest QR generator on the web</value>
</data>
<data name="AverageTimePrefix" xml:space="preserve">
<value>Average of</value>
</data>
<data name="AverageTimeValue" xml:space="preserve">
<value>1.2 seconds</value>
</data>
<data name="AverageTimeSuffix" xml:space="preserve">
<value>per QR code • Free • No registration required</value>
</data>
<data name="FastestQRGeneratorDescription" xml:space="preserve">
<value>The fastest QR code generator on the web. Free, secure and reliable.</value>
</data>
<data name="UsefulLinks" xml:space="preserve">
<value>Useful Links</value>
</data>
<data name="TermsOfUse" xml:space="preserve">
<value>Terms of Use</value>
</data>
<data name="Support" xml:space="preserve">
<value>Support</value>
</data>
<data name="Help" xml:space="preserve">
<value>Help</value>
</data>
<data name="AllRightsReserved" xml:space="preserve">
<value>All rights reserved.</value>
</data>
</root> </root>

View File

@ -268,4 +268,428 @@
<data name="Colorful" xml:space="preserve"> <data name="Colorful" xml:space="preserve">
<value>Colorido</value> <value>Colorido</value>
</data> </data>
<!-- Premium Upgrade Page -->
<data name="PremiumAccelerateProductivity" xml:space="preserve">
<value>Acelera tu productividad con el generador de QR más rápido del mundo</value>
</data>
<data name="ThreeTimesFaster" xml:space="preserve">
<value>3x más rápido que la competencia</value>
</data>
<data name="CurrentStatus" xml:space="preserve">
<value>Estado Actual</value>
</data>
<data name="YouHave" xml:space="preserve">
<value>Tienes</value>
</data>
<data name="DaysRemainingNoAds" xml:space="preserve">
<value>días restantes sin anuncios.</value>
</data>
<data name="UpgradeNowForever" xml:space="preserve">
<value>¡Actualiza ahora y ten acceso premium para siempre!</value>
</data>
<data name="DaysRemaining" xml:space="preserve">
<value>días restantes</value>
</data>
<data name="MostPopularPlan" xml:space="preserve">
<value>El plan más popular</value>
</data>
<data name="PerMonth" xml:space="preserve">
<value>por mes</value>
</data>
<data name="UnlimitedQRCodes" xml:space="preserve">
<value>Códigos QR ilimitados</value>
</data>
<data name="UltraFastGeneration04s" xml:space="preserve">
<value>Generación ultra-rápida (0.4s)</value>
</data>
<data name="NoAdsForever" xml:space="preserve">
<value>Sin anuncios para siempre</value>
</data>
<data name="DynamicQRCodes" xml:space="preserve">
<value>Códigos QR dinámicos</value>
</data>
<data name="RealTimeAnalytics" xml:space="preserve">
<value>Analítica en tiempo real</value>
</data>
<data name="PrioritySupport" xml:space="preserve">
<value>Soporte prioritario</value>
</data>
<data name="DeveloperAPI" xml:space="preserve">
<value>API para desarrolladores</value>
</data>
<data name="UpgradeNowButton" xml:space="preserve">
<value>Actualizar Ahora</value>
</data>
<data name="SecurePaymentStripe" xml:space="preserve">
<value>Pago seguro via Stripe</value>
</data>
<data name="CancelAnytime" xml:space="preserve">
<value>Cancela cuando quieras</value>
</data>
<data name="PlanComparison" xml:space="preserve">
<value>Comparación de Planes</value>
</data>
<data name="Feature" xml:space="preserve">
<value>Función</value>
</data>
<data name="QRCodesPerDay" xml:space="preserve">
<value>Códigos QR por día</value>
</data>
<data name="Unlimited" xml:space="preserve">
<value>Ilimitado</value>
</data>
<data name="GenerationSpeed" xml:space="preserve">
<value>Velocidad de generación</value>
</data>
<data name="Ads" xml:space="preserve">
<value>Anuncios</value>
</data>
<data name="NoAds" xml:space="preserve">
<value>Sin anuncios</value>
</data>
<data name="DetailedAnalytics" xml:space="preserve">
<value>Analítica detallada</value>
</data>
<data name="SpeedDemonstration" xml:space="preserve">
<value>Demostración de Velocidad</value>
</data>
<data name="Competitors" xml:space="preserve">
<value>Competidores</value>
</data>
<data name="AverageTime" xml:space="preserve">
<value>Tiempo promedio</value>
</data>
<data name="ElevenTimesFaster" xml:space="preserve">
<value>¡11x más rápido!</value>
</data>
<data name="FAQ" xml:space="preserve">
<value>Preguntas Frecuentes</value>
</data>
<data name="CanCancelAnytime" xml:space="preserve">
<value>¿Puedo cancelar en cualquier momento?</value>
</data>
<data name="CancelAnytimeAnswer" xml:space="preserve">
<value>¡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.</value>
</data>
<data name="WhatAreDynamicQR" xml:space="preserve">
<value>¿Qué son los códigos QR dinámicos?</value>
</data>
<data name="DynamicQRAnswer" xml:space="preserve">
<value>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.</value>
</data>
<data name="HowPrioritySupport" xml:space="preserve">
<value>¿Cómo funciona el soporte prioritario?</value>
</data>
<data name="PrioritySupportAnswer" xml:space="preserve">
<value>Los usuarios premium reciben respuesta en hasta 2 horas hábiles por email, acceso al chat directo y soporte técnico especializado.</value>
</data>
<data name="PaymentProcessingError" xml:space="preserve">
<value>Error al procesar el pago: </value>
</data>
<data name="PaymentErrorTryAgain" xml:space="preserve">
<value>Error al procesar el pago. Inténtalo de nuevo.</value>
</data>
<!-- Ad Space -->
<data name="Advertisement" xml:space="preserve">
<value>Publicidad</value>
</data>
<data name="PremiumUserNoAds" xml:space="preserve">
<value>✨ Usuario Premium - ¡Sin anuncios!</value>
</data>
<data name="UpgradePremiumRemoveAds" xml:space="preserve">
<value>¡Actualiza a Premium y elimina los anuncios!</value>
</data>
<data name="PremiumBenefitsShort" xml:space="preserve">
<value>Premium: Sin anuncios + Historial + QR ilimitados</value>
</data>
<!-- Login Page -->
<data name="LoginAndGet" xml:space="preserve">
<value>Inicia sesión con tu cuenta y obtén:</value>
</data>
<data name="ThirtyDaysNoAds" xml:space="preserve">
<value>30 días sin anuncios</value>
</data>
<data name="FiftyQRCodesPerDay" xml:space="preserve">
<value>50 códigos QR/día</value>
</data>
<data name="QRCodeHistory" xml:space="preserve">
<value>Historial de códigos QR</value>
</data>
<data name="LoginWithGoogle" xml:space="preserve">
<value>Iniciar con Google</value>
</data>
<data name="LoginWithMicrosoft" xml:space="preserve">
<value>Iniciar con Microsoft</value>
</data>
<data name="SpecialOfferLogin" xml:space="preserve">
<value>¡Oferta Especial!</value>
</data>
<data name="LoginAutomaticallyGain" xml:space="preserve">
<value>Al iniciar sesión, obtienes automáticamente</value>
</data>
<data name="AndCanGenerate" xml:space="preserve">
<value>y puedes generar hasta</value>
</data>
<data name="ForFree" xml:space="preserve">
<value>gratuitamente.</value>
</data>
<data name="NoRegisterWithoutPermission" xml:space="preserve">
<value>No te registramos sin tu permiso.</value>
</data>
<data name="PrivacyPolicy" xml:space="preserve">
<value>Política de Privacidad</value>
</data>
<!-- Payment Pages -->
<data name="PaymentSuccessful" xml:space="preserve">
<value>¡Pago exitoso!</value>
</data>
<data name="BackToHome" xml:space="preserve">
<value>Volver al Inicio</value>
</data>
<data name="PaymentCanceled" xml:space="preserve">
<value>Pago cancelado.</value>
</data>
<data name="ViewPlans" xml:space="preserve">
<value>Ver Planes</value>
</data>
<data name="UnlockFullPowerQRRapido" xml:space="preserve">
<value>Desbloquea el Poder Total de QRRápido</value>
</data>
<data name="UnlimitedAccessNoAdsExclusive" xml:space="preserve">
<value>Acceso sin límites, sin anuncios y con recursos exclusivos para máxima productividad.</value>
</data>
<data name="MonthlyPlan" xml:space="preserve">
<value>Plan Mensual</value>
</data>
<data name="IdealToStartExploring" xml:space="preserve">
<value>Ideal para comenzar a explorar las funciones premium.</value>
</data>
<data name="SubscribeNow" xml:space="preserve">
<value>Suscribirse Ahora</value>
</data>
<data name="AnnualPlan" xml:space="preserve">
<value>Plan Anual</value>
</data>
<data name="Recommended" xml:space="preserve">
<value>Recomendado</value>
</data>
<data name="PerYear" xml:space="preserve">
<value>/año</value>
</data>
<data name="SaveMoney" xml:space="preserve">
<value>Ahorra $</value>
</data>
<data name="BestValueFrequentUsers" xml:space="preserve">
<value>La mejor relación calidad-precio para usuarios frecuentes.</value>
</data>
<data name="SubscribeAnnualPlan" xml:space="preserve">
<value>Suscribirse al Plan Anual</value>
</data>
<data name="AllPlansInclude" xml:space="preserve">
<value>Todos los planes incluyen:</value>
</data>
<data name="Redirecting" xml:space="preserve">
<value>Redirigiendo...</value>
</data>
<data name="PaymentInitializationError" xml:space="preserve">
<value>Ocurrió un error al iniciar el pago. Inténtalo de nuevo.</value>
</data>
<!-- History Page -->
<data name="QRCodesSavedHere" xml:space="preserve">
<value>Tus códigos QR generados se guardan aquí para descarga futura</value>
</data>
<data name="GenerateNewQRCode" xml:space="preserve">
<value>Generar Nuevo Código QR</value>
</data>
<data name="Type" xml:space="preserve">
<value>Tipo:</value>
</data>
<data name="CreatedOn" xml:space="preserve">
<value>Creado el:</value>
</data>
<data name="ShowingRecent50QRCodes" xml:space="preserve">
<value>Mostrando los 50 códigos QR más recientes. Los más antiguos se eliminan automáticamente.</value>
</data>
<data name="NoQRCodeFound" xml:space="preserve">
<value>Ningún Código QR encontrado</value>
</data>
<data name="QRCodesWillAppearHere" xml:space="preserve">
<value>Cuando generes códigos QR estando conectado, aparecerán aquí para descarga futura.</value>
</data>
<data name="GenerateFirstQRCode" xml:space="preserve">
<value>Generar Primer Código QR</value>
</data>
<data name="ErrorRegeneratingQR" xml:space="preserve">
<value>Error al regenerar el Código QR. Inténtalo de nuevo.</value>
</data>
<!-- Home Page -->
<data name="SmallSize200px" xml:space="preserve">
<value>Pequeño (200px)</value>
</data>
<data name="MediumSize300px" xml:space="preserve">
<value>Mediano (300px)</value>
</data>
<data name="LargeSize500px" xml:space="preserve">
<value>Grande (500px)</value>
</data>
<data name="XLSize800px" xml:space="preserve">
<value>XL (800px)</value>
</data>
<data name="Minimal" xml:space="preserve">
<value>Mínimo</value>
</data>
<data name="Large" xml:space="preserve">
<value>Grande</value>
</data>
<data name="LogoIcon" xml:space="preserve">
<value>Logo/Icono</value>
</data>
<data name="PNGJPGUp2MB" xml:space="preserve">
<value>PNG, JPG hasta 2MB</value>
</data>
<data name="BorderStyle" xml:space="preserve">
<value>Estilo de Bordes</value>
</data>
<data name="Square" xml:space="preserve">
<value>Cuadrado</value>
</data>
<data name="Rounded" xml:space="preserve">
<value>Redondeado</value>
</data>
<data name="Circular" xml:space="preserve">
<value>Circular</value>
</data>
<data name="Leaf" xml:space="preserve">
<value>Hoja</value>
</data>
<data name="GenerateQRCodeQuickly" xml:space="preserve">
<value>Generar Código QR Rápidamente</value>
</data>
<data name="Generating" xml:space="preserve">
<value>Generando...</value>
</data>
<data name="Availability" xml:space="preserve">
<value>Disponibilidad</value>
</data>
<data name="QRsGeneratedToday" xml:space="preserve">
<value>QRs generados hoy</value>
</data>
<data name="YourQRCodeWillAppear" xml:space="preserve">
<value>Tu código QR aparecerá aquí en segundos</value>
</data>
<data name="UltraFastGenerationGuaranteed" xml:space="preserve">
<value>Generación ultra-rápida garantizada</value>
</data>
<data name="DownloadSVGVector" xml:space="preserve">
<value>Descargar SVG (Vectorial)</value>
</data>
<data name="ShareQRCode" xml:space="preserve">
<value>Compartir Código QR</value>
</data>
<data name="ShareSystem" xml:space="preserve">
<value>Compartir (Sistema)</value>
</data>
<data name="ToSaveToHistory" xml:space="preserve">
<value>para guardar en el historial</value>
</data>
<data name="PriorityGeneration" xml:space="preserve">
<value>Generación prioritaria (0.4s)</value>
</data>
<data name="AcceleratePrice" xml:space="preserve">
<value>Acelerar por $19.90/mes</value>
</data>
<data name="TipsFasterQR" xml:space="preserve">
<value>Consejos para QR Más Rápidos</value>
</data>
<data name="ShortURLsFaster" xml:space="preserve">
<value>URLs cortas se generan más rápido</value>
</data>
<data name="LessTextMoreSpeed" xml:space="preserve">
<value>Menos texto = mayor velocidad</value>
</data>
<data name="SolidColorsOptimize" xml:space="preserve">
<value>Colores sólidos optimizan el proceso</value>
</data>
<data name="SmallerSizesAccelerate" xml:space="preserve">
<value>Tamaños menores aceleran la descarga</value>
</data>
<data name="WhyQRRapidoFaster" xml:space="preserve">
<value>¿Por qué QR Rapido es más rápido?</value>
</data>
<data name="ComparisonOtherGenerators" xml:space="preserve">
<value>Comparación con otros generadores populares</value>
</data>
<data name="OptimizedForSpeed" xml:space="preserve">
<value>Optimizado para velocidad</value>
</data>
<data name="CompetitorA" xml:space="preserve">
<value>Competidor A</value>
</data>
<data name="TraditionalGenerator" xml:space="preserve">
<value>Generador tradicional</value>
</data>
<data name="CompetitorB" xml:space="preserve">
<value>Competidor B</value>
</data>
<data name="HeavyInterface" xml:space="preserve">
<value>Interfaz pesada</value>
</data>
<data name="CompetitorC" xml:space="preserve">
<value>Competidor C</value>
</data>
<data name="ManyAds" xml:space="preserve">
<value>Muchos anuncios</value>
</data>
<!-- Layout -->
<data name="Average" xml:space="preserve">
<value>promedio</value>
</data>
<data name="GenerateQRCode" xml:space="preserve">
<value>Generar Código QR</value>
</data>
<data name="Profile" xml:space="preserve">
<value>Perfil</value>
</data>
<data name="History" xml:space="preserve">
<value>Historial</value>
</data>
<data name="PremiumActive" xml:space="preserve">
<value>Premium Activo</value>
</data>
<data name="Logout" xml:space="preserve">
<value>Salir</value>
</data>
<data name="LoginThirtyDaysNoAds" xml:space="preserve">
<value>¡Iniciar sesión = 30 días sin anuncios!</value>
</data>
<data name="FastestQRGeneratorWeb" xml:space="preserve">
<value>El generador de QR más rápido de la web</value>
</data>
<data name="AverageTimePrefix" xml:space="preserve">
<value>Promedio de</value>
</data>
<data name="AverageTimeValue" xml:space="preserve">
<value>1.2 segundos</value>
</data>
<data name="AverageTimeSuffix" xml:space="preserve">
<value>por código QR • Gratis • Sin registro obligatorio</value>
</data>
<data name="FastestQRGeneratorDescription" xml:space="preserve">
<value>El generador de códigos QR más rápido de la web. Gratis, seguro y confiable.</value>
</data>
<data name="UsefulLinks" xml:space="preserve">
<value>Enlaces Útiles</value>
</data>
<data name="TermsOfUse" xml:space="preserve">
<value>Términos de Uso</value>
</data>
<data name="Support" xml:space="preserve">
<value>Soporte</value>
</data>
<data name="Help" xml:space="preserve">
<value>Ayuda</value>
</data>
<data name="AllRightsReserved" xml:space="preserve">
<value>Todos los derechos reservados.</value>
</data>
</root> </root>

View File

@ -268,4 +268,428 @@
<data name="Colorful" xml:space="preserve"> <data name="Colorful" xml:space="preserve">
<value>Colorido</value> <value>Colorido</value>
</data> </data>
<!-- Premium Upgrade Page -->
<data name="PremiumAccelerateProductivity" xml:space="preserve">
<value>Acelere sua produtividade com o gerador de QR mais rápido do mundo</value>
</data>
<data name="ThreeTimesFaster" xml:space="preserve">
<value>3x mais rápido que a concorrência</value>
</data>
<data name="CurrentStatus" xml:space="preserve">
<value>Status Atual</value>
</data>
<data name="YouHave" xml:space="preserve">
<value>Você tem</value>
</data>
<data name="DaysRemainingNoAds" xml:space="preserve">
<value>dias restantes sem anúncios.</value>
</data>
<data name="UpgradeNowForever" xml:space="preserve">
<value>Upgrade agora e tenha acesso premium para sempre!</value>
</data>
<data name="DaysRemaining" xml:space="preserve">
<value>dias restantes</value>
</data>
<data name="MostPopularPlan" xml:space="preserve">
<value>O plano mais popular</value>
</data>
<data name="PerMonth" xml:space="preserve">
<value>por mês</value>
</data>
<data name="UnlimitedQRCodes" xml:space="preserve">
<value>QR codes ilimitados</value>
</data>
<data name="UltraFastGeneration04s" xml:space="preserve">
<value>Geração ultra-rápida (0.4s)</value>
</data>
<data name="NoAdsForever" xml:space="preserve">
<value>Sem anúncios para sempre</value>
</data>
<data name="DynamicQRCodes" xml:space="preserve">
<value>QR codes dinâmicos</value>
</data>
<data name="RealTimeAnalytics" xml:space="preserve">
<value>Analytics em tempo real</value>
</data>
<data name="PrioritySupport" xml:space="preserve">
<value>Suporte prioritário</value>
</data>
<data name="DeveloperAPI" xml:space="preserve">
<value>API para desenvolvedores</value>
</data>
<data name="UpgradeNowButton" xml:space="preserve">
<value>Fazer Upgrade Agora</value>
</data>
<data name="SecurePaymentStripe" xml:space="preserve">
<value>Pagamento seguro via Stripe</value>
</data>
<data name="CancelAnytime" xml:space="preserve">
<value>Cancele quando quiser</value>
</data>
<data name="PlanComparison" xml:space="preserve">
<value>Comparação de Planos</value>
</data>
<data name="Feature" xml:space="preserve">
<value>Recurso</value>
</data>
<data name="QRCodesPerDay" xml:space="preserve">
<value>QR codes por dia</value>
</data>
<data name="Unlimited" xml:space="preserve">
<value>Ilimitado</value>
</data>
<data name="GenerationSpeed" xml:space="preserve">
<value>Velocidade de geração</value>
</data>
<data name="Ads" xml:space="preserve">
<value>Anúncios</value>
</data>
<data name="NoAds" xml:space="preserve">
<value>Sem anúncios</value>
</data>
<data name="DetailedAnalytics" xml:space="preserve">
<value>Analytics detalhados</value>
</data>
<data name="SpeedDemonstration" xml:space="preserve">
<value>Demonstração de Velocidade</value>
</data>
<data name="Competitors" xml:space="preserve">
<value>Concorrentes</value>
</data>
<data name="AverageTime" xml:space="preserve">
<value>Tempo médio</value>
</data>
<data name="ElevenTimesFaster" xml:space="preserve">
<value>11x mais rápido!</value>
</data>
<data name="FAQ" xml:space="preserve">
<value>Perguntas Frequentes</value>
</data>
<data name="CanCancelAnytime" xml:space="preserve">
<value>Posso cancelar a qualquer momento?</value>
</data>
<data name="CancelAnytimeAnswer" xml:space="preserve">
<value>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.</value>
</data>
<data name="WhatAreDynamicQR" xml:space="preserve">
<value>O que são QR codes dinâmicos?</value>
</data>
<data name="DynamicQRAnswer" xml:space="preserve">
<value>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.</value>
</data>
<data name="HowPrioritySupport" xml:space="preserve">
<value>Como funciona o suporte prioritário?</value>
</data>
<data name="PrioritySupportAnswer" xml:space="preserve">
<value>Usuários premium recebem resposta em até 2 horas úteis por email, acesso ao chat direto e suporte técnico especializado.</value>
</data>
<data name="PaymentProcessingError" xml:space="preserve">
<value>Erro ao processar pagamento: </value>
</data>
<data name="PaymentErrorTryAgain" xml:space="preserve">
<value>Erro ao processar pagamento. Tente novamente.</value>
</data>
<!-- Ad Space -->
<data name="Advertisement" xml:space="preserve">
<value>Publicidade</value>
</data>
<data name="PremiumUserNoAds" xml:space="preserve">
<value>✨ Usuário Premium - Sem anúncios!</value>
</data>
<data name="UpgradePremiumRemoveAds" xml:space="preserve">
<value>Faça upgrade para Premium e remova os anúncios!</value>
</data>
<data name="PremiumBenefitsShort" xml:space="preserve">
<value>Premium: Sem anúncios + Histórico + QR ilimitados</value>
</data>
<!-- Login Page -->
<data name="LoginAndGet" xml:space="preserve">
<value>Entre com sua conta e ganhe:</value>
</data>
<data name="ThirtyDaysNoAds" xml:space="preserve">
<value>30 dias sem anúncios</value>
</data>
<data name="FiftyQRCodesPerDay" xml:space="preserve">
<value>50 QR codes/dia</value>
</data>
<data name="QRCodeHistory" xml:space="preserve">
<value>Histórico de QR codes</value>
</data>
<data name="LoginWithGoogle" xml:space="preserve">
<value>Entrar com Google</value>
</data>
<data name="LoginWithMicrosoft" xml:space="preserve">
<value>Entrar com Microsoft</value>
</data>
<data name="SpecialOfferLogin" xml:space="preserve">
<value>Oferta Especial!</value>
</data>
<data name="LoginAutomaticallyGain" xml:space="preserve">
<value>Ao fazer login, você ganha automaticamente</value>
</data>
<data name="AndCanGenerate" xml:space="preserve">
<value>e pode gerar até</value>
</data>
<data name="ForFree" xml:space="preserve">
<value>gratuitamente.</value>
</data>
<data name="NoRegisterWithoutPermission" xml:space="preserve">
<value>Não cadastramos você sem sua permissão.</value>
</data>
<data name="PrivacyPolicy" xml:space="preserve">
<value>Política de Privacidade</value>
</data>
<!-- Payment Pages -->
<data name="PaymentSuccessful" xml:space="preserve">
<value>Pagamento bem-sucedido!</value>
</data>
<data name="BackToHome" xml:space="preserve">
<value>Voltar ao Início</value>
</data>
<data name="PaymentCanceled" xml:space="preserve">
<value>Pagamento cancelado.</value>
</data>
<data name="ViewPlans" xml:space="preserve">
<value>Ver Planos</value>
</data>
<data name="UnlockFullPowerQRRapido" xml:space="preserve">
<value>Desbloqueie o Poder Total do QRRápido</value>
</data>
<data name="UnlimitedAccessNoAdsExclusive" xml:space="preserve">
<value>Acesso sem limites, sem anúncios e com recursos exclusivos para máxima produtividade.</value>
</data>
<data name="MonthlyPlan" xml:space="preserve">
<value>Plano Mensal</value>
</data>
<data name="IdealToStartExploring" xml:space="preserve">
<value>Ideal para começar a explorar os recursos premium.</value>
</data>
<data name="SubscribeNow" xml:space="preserve">
<value>Assinar Agora</value>
</data>
<data name="AnnualPlan" xml:space="preserve">
<value>Plano Anual</value>
</data>
<data name="Recommended" xml:space="preserve">
<value>Recomendado</value>
</data>
<data name="PerYear" xml:space="preserve">
<value>/ano</value>
</data>
<data name="SaveMoney" xml:space="preserve">
<value>Economize R$</value>
</data>
<data name="BestValueFrequentUsers" xml:space="preserve">
<value>O melhor custo-benefício para usuários frequentes.</value>
</data>
<data name="SubscribeAnnualPlan" xml:space="preserve">
<value>Assinar Plano Anual</value>
</data>
<data name="AllPlansInclude" xml:space="preserve">
<value>Todos os planos incluem:</value>
</data>
<data name="Redirecting" xml:space="preserve">
<value>Redirecionando...</value>
</data>
<data name="PaymentInitializationError" xml:space="preserve">
<value>Ocorreu um erro ao iniciar o pagamento. Tente novamente.</value>
</data>
<!-- History Page -->
<data name="QRCodesSavedHere" xml:space="preserve">
<value>Seus QR codes gerados ficam salvos aqui para download futuro</value>
</data>
<data name="GenerateNewQRCode" xml:space="preserve">
<value>Gerar Novo QRCode</value>
</data>
<data name="Type" xml:space="preserve">
<value>Tipo:</value>
</data>
<data name="CreatedOn" xml:space="preserve">
<value>Criado em:</value>
</data>
<data name="ShowingRecent50QRCodes" xml:space="preserve">
<value>Mostrando os 50 QR codes mais recentes. Os mais antigos são removidos automaticamente.</value>
</data>
<data name="NoQRCodeFound" xml:space="preserve">
<value>Nenhum QR Code encontrado</value>
</data>
<data name="QRCodesWillAppearHere" xml:space="preserve">
<value>Quando você gerar QR codes estando logado, eles aparecerão aqui para download futuro.</value>
</data>
<data name="GenerateFirstQRCode" xml:space="preserve">
<value>Gerar Primeiro QRCode</value>
</data>
<data name="ErrorRegeneratingQR" xml:space="preserve">
<value>Erro ao regenerar QR Code. Tente novamente.</value>
</data>
<!-- Home Page -->
<data name="SmallSize200px" xml:space="preserve">
<value>Pequeno (200px)</value>
</data>
<data name="MediumSize300px" xml:space="preserve">
<value>Médio (300px)</value>
</data>
<data name="LargeSize500px" xml:space="preserve">
<value>Grande (500px)</value>
</data>
<data name="XLSize800px" xml:space="preserve">
<value>XL (800px)</value>
</data>
<data name="Minimal" xml:space="preserve">
<value>Mínima</value>
</data>
<data name="Large" xml:space="preserve">
<value>Grande</value>
</data>
<data name="LogoIcon" xml:space="preserve">
<value>Logo/Ícone</value>
</data>
<data name="PNGJPGUp2MB" xml:space="preserve">
<value>PNG, JPG até 2MB</value>
</data>
<data name="BorderStyle" xml:space="preserve">
<value>Estilo das Bordas</value>
</data>
<data name="Square" xml:space="preserve">
<value>Quadrado</value>
</data>
<data name="Rounded" xml:space="preserve">
<value>Arredondado</value>
</data>
<data name="Circular" xml:space="preserve">
<value>Circular</value>
</data>
<data name="Leaf" xml:space="preserve">
<value>Folha</value>
</data>
<data name="GenerateQRCodeQuickly" xml:space="preserve">
<value>Gerar QR Code Rapidamente</value>
</data>
<data name="Generating" xml:space="preserve">
<value>Gerando...</value>
</data>
<data name="Availability" xml:space="preserve">
<value>Disponibilidade</value>
</data>
<data name="QRsGeneratedToday" xml:space="preserve">
<value>QRs gerados hoje</value>
</data>
<data name="YourQRCodeWillAppear" xml:space="preserve">
<value>Seu QR code aparecerá aqui em segundos</value>
</data>
<data name="UltraFastGenerationGuaranteed" xml:space="preserve">
<value>Geração ultra-rápida garantida</value>
</data>
<data name="DownloadSVGVector" xml:space="preserve">
<value>Download SVG (Vetorial)</value>
</data>
<data name="ShareQRCode" xml:space="preserve">
<value>Compartilhar QR Code</value>
</data>
<data name="ShareSystem" xml:space="preserve">
<value>Compartilhar (Sistema)</value>
</data>
<data name="ToSaveToHistory" xml:space="preserve">
<value>para salvar no histórico</value>
</data>
<data name="PriorityGeneration" xml:space="preserve">
<value>Geração prioritária (0.4s)</value>
</data>
<data name="AcceleratePrice" xml:space="preserve">
<value>Acelerar por R$ 19,90/mês</value>
</data>
<data name="TipsFasterQR" xml:space="preserve">
<value>Dicas para QR Mais Rápidos</value>
</data>
<data name="ShortURLsFaster" xml:space="preserve">
<value>URLs curtas geram mais rápido</value>
</data>
<data name="LessTextMoreSpeed" xml:space="preserve">
<value>Menos texto = maior velocidade</value>
</data>
<data name="SolidColorsOptimize" xml:space="preserve">
<value>Cores sólidas otimizam o processo</value>
</data>
<data name="SmallerSizesAccelerate" xml:space="preserve">
<value>Tamanhos menores aceleram o download</value>
</data>
<data name="WhyQRRapidoFaster" xml:space="preserve">
<value>Por que QR Rapido é mais rápido?</value>
</data>
<data name="ComparisonOtherGenerators" xml:space="preserve">
<value>Comparação com outros geradores populares</value>
</data>
<data name="OptimizedForSpeed" xml:space="preserve">
<value>Otimizado para velocidade</value>
</data>
<data name="CompetitorA" xml:space="preserve">
<value>Concorrente A</value>
</data>
<data name="TraditionalGenerator" xml:space="preserve">
<value>Gerador tradicional</value>
</data>
<data name="CompetitorB" xml:space="preserve">
<value>Concorrente B</value>
</data>
<data name="HeavyInterface" xml:space="preserve">
<value>Interface pesada</value>
</data>
<data name="CompetitorC" xml:space="preserve">
<value>Concorrente C</value>
</data>
<data name="ManyAds" xml:space="preserve">
<value>Muitos anúncios</value>
</data>
<!-- Layout -->
<data name="Average" xml:space="preserve">
<value>médio</value>
</data>
<data name="GenerateQRCode" xml:space="preserve">
<value>Gerar QRCode</value>
</data>
<data name="Profile" xml:space="preserve">
<value>Perfil</value>
</data>
<data name="History" xml:space="preserve">
<value>Histórico</value>
</data>
<data name="PremiumActive" xml:space="preserve">
<value>Premium Ativo</value>
</data>
<data name="Logout" xml:space="preserve">
<value>Sair</value>
</data>
<data name="LoginThirtyDaysNoAds" xml:space="preserve">
<value>Login = 30 dias sem anúncios!</value>
</data>
<data name="FastestQRGeneratorWeb" xml:space="preserve">
<value>O gerador de QR mais rápido da web</value>
</data>
<data name="AverageTimePrefix" xml:space="preserve">
<value>Média de</value>
</data>
<data name="AverageTimeValue" xml:space="preserve">
<value>1.2 segundos</value>
</data>
<data name="AverageTimeSuffix" xml:space="preserve">
<value>por QR code • Grátis • Sem cadastro obrigatório</value>
</data>
<data name="FastestQRGeneratorDescription" xml:space="preserve">
<value>O gerador de QR codes mais rápido da web. Grátis, seguro e confiável.</value>
</data>
<data name="UsefulLinks" xml:space="preserve">
<value>Links Úteis</value>
</data>
<data name="TermsOfUse" xml:space="preserve">
<value>Termos de Uso</value>
</data>
<data name="Support" xml:space="preserve">
<value>Suporte</value>
</data>
<data name="Help" xml:space="preserve">
<value>Ajuda</value>
</data>
<data name="AllRightsReserved" xml:space="preserve">
<value>Todos os direitos reservados.</value>
</data>
</root> </root>

View File

@ -23,14 +23,12 @@ namespace QRRapidoApp.Services
{ {
try try
{ {
// Usuários não logados: sempre mostrar anúncios
if (string.IsNullOrEmpty(userId)) if (string.IsNullOrEmpty(userId))
return true; return true;
var user = await _userService.GetUserAsync(userId); var user = await _userService.GetUserAsync(userId);
if (user == null) return true; if (user == null) return true;
// APENAS Premium users não veem anúncios
return !(user.IsPremium && user.PremiumExpiresAt > DateTime.UtcNow); return !(user.IsPremium && user.PremiumExpiresAt > DateTime.UtcNow);
} }
catch (Exception ex) 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<bool> HasValidPremiumSubscription(string userId) public async Task<bool> HasValidPremiumSubscription(string userId)
{ {
try try

View File

@ -13,12 +13,12 @@
<div class="col-12"> <div class="col-12">
<div class="d-flex justify-content-between align-items-center mb-4"> <div class="d-flex justify-content-between align-items-center mb-4">
<div> <div>
<h2><i class="fas fa-history text-primary"></i> Histórico de QR Codes</h2> <h2><i class="fas fa-history text-primary"></i> @Localizer["QRCodeHistory"]</h2>
<p class="text-muted">Seus QR codes gerados ficam salvos aqui para download futuro</p> <p class="text-muted">@Localizer["QRCodesSavedHere"]</p>
</div> </div>
<div> <div>
<a href="/" class="btn btn-primary"> <a href="/" class="btn btn-primary">
<i class="fas fa-plus"></i> Gerar Novo QRCode <i class="fas fa-plus"></i> @Localizer["GenerateNewQRCode"]
</a> </a>
</div> </div>
</div> </div>
@ -39,12 +39,12 @@
</div> </div>
<div class="mb-2"> <div class="mb-2">
<small class="text-muted">Tipo:</small> <small class="text-muted">@Localizer["Type"]</small>
<span class="badge bg-secondary">@qr.Type</span> <span class="badge bg-secondary">@qr.Type</span>
</div> </div>
<div class="mb-2"> <div class="mb-2">
<small class="text-muted">Conteúdo:</small> <small class="text-muted">@Localizer["Content"]</small>
<p class="small mb-0" style="word-break: break-all;"> <p class="small mb-0" style="word-break: break-all;">
@if (qr.Content.Length > 50) @if (qr.Content.Length > 50)
{ {
@ -58,7 +58,7 @@
</div> </div>
<div class="mb-3"> <div class="mb-3">
<small class="text-muted">Criado em:</small> <small class="text-muted">@Localizer["CreatedOn"]</small>
<br> <br>
<small>@qr.CreatedAt.ToString("dd/MM/yyyy HH:mm")</small> <small>@qr.CreatedAt.ToString("dd/MM/yyyy HH:mm")</small>
</div> </div>
@ -98,7 +98,7 @@
{ {
<div class="alert alert-info text-center"> <div class="alert alert-info text-center">
<i class="fas fa-info-circle"></i> <i class="fas fa-info-circle"></i>
Mostrando os 50 QR codes mais recentes. Os mais antigos são removidos automaticamente. @Localizer["ShowingRecent50QRCodes"]
</div> </div>
} }
} }
@ -106,12 +106,12 @@
{ {
<div class="text-center py-5"> <div class="text-center py-5">
<i class="fas fa-qrcode fa-4x text-muted mb-3"></i> <i class="fas fa-qrcode fa-4x text-muted mb-3"></i>
<h4 class="text-muted">Nenhum QR Code encontrado</h4> <h4 class="text-muted">@Localizer["NoQRCodeFound"]</h4>
<p class="text-muted"> <p class="text-muted">
Quando você gerar QR codes estando logado, eles aparecerão aqui para download futuro. @Localizer["QRCodesWillAppearHere"]
</p> </p>
<a href="/" class="btn btn-primary"> <a href="/" class="btn btn-primary">
<i class="fas fa-plus"></i> Gerar Primeiro QRCode <i class="fas fa-plus"></i> @Localizer["GenerateFirstQRCode"]
</a> </a>
</div> </div>
} }
@ -143,7 +143,7 @@ function regenerateQR(qrId) {
}) })
.catch(error => { .catch(error => {
console.error('Error regenerating QR:', error); console.error('Error regenerating QR:', error);
alert('Erro ao regenerar QR Code. Tente novamente.'); alert('@Localizer["ErrorRegeneratingQR"]');
}); });
} }

View File

@ -1,3 +1,5 @@
@using Microsoft.Extensions.Localization
@inject IStringLocalizer<QRRapidoApp.Resources.SharedResource> Localizer
@{ @{
ViewData["Title"] = "Login"; ViewData["Title"] = "Login";
var returnUrl = ViewBag.ReturnUrl ?? "/"; var returnUrl = ViewBag.ReturnUrl ?? "/";
@ -10,26 +12,26 @@
<div class="card shadow-sm"> <div class="card shadow-sm">
<div class="card-header bg-primary text-white text-center"> <div class="card-header bg-primary text-white text-center">
<h4 class="mb-0"> <h4 class="mb-0">
<i class="fas fa-sign-in-alt"></i> Entrar <i class="fas fa-sign-in-alt"></i> @Localizer["Login"]
</h4> </h4>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="text-center mb-4"> <div class="text-center mb-4">
<p class="text-muted">Entre com sua conta e ganhe:</p> <p class="text-muted">@Localizer["LoginAndGet"]</p>
<div class="row text-center"> <div class="row text-center">
<div class="col-12 mb-2"> <div class="col-12 mb-2">
<div class="badge bg-success p-2 w-100"> <div class="badge bg-success p-2 w-100">
<i class="fas fa-crown"></i> 30 dias sem anúncios <i class="fas fa-crown"></i> @Localizer["ThirtyDaysNoAds"]
</div> </div>
</div> </div>
<div class="col-12 mb-2"> <div class="col-12 mb-2">
<div class="badge bg-primary p-2 w-100"> <div class="badge bg-primary p-2 w-100">
<i class="fas fa-infinity"></i> 50 QR codes/dia <i class="fas fa-infinity"></i> @Localizer["FiftyQRCodesPerDay"]
</div> </div>
</div> </div>
<div class="col-12 mb-2"> <div class="col-12 mb-2">
<div class="badge bg-info p-2 w-100"> <div class="badge bg-info p-2 w-100">
<i class="fas fa-history"></i> Histórico de QR codes <i class="fas fa-history"></i> @Localizer["QRCodeHistory"]
</div> </div>
</div> </div>
</div> </div>
@ -37,11 +39,11 @@
<div class="d-grid gap-3"> <div class="d-grid gap-3">
<a href="/Account/LoginGoogle?returnUrl=@returnUrl" class="btn btn-danger btn-lg"> <a href="/Account/LoginGoogle?returnUrl=@returnUrl" class="btn btn-danger btn-lg">
<i class="fab fa-google"></i> Entrar com Google <i class="fab fa-google"></i> @Localizer["LoginWithGoogle"]
</a> </a>
<a href="/Account/LoginMicrosoft?returnUrl=@returnUrl" class="btn btn-primary btn-lg"> <a href="/Account/LoginMicrosoft?returnUrl=@returnUrl" class="btn btn-primary btn-lg">
<i class="fab fa-microsoft"></i> Entrar com Microsoft <i class="fab fa-microsoft"></i> @Localizer["LoginWithMicrosoft"]
</a> </a>
</div> </div>
@ -49,18 +51,18 @@
<div class="text-center"> <div class="text-center">
<h6 class="text-success"> <h6 class="text-success">
<i class="fas fa-gift"></i> Oferta Especial! <i class="fas fa-gift"></i> @Localizer["SpecialOfferLogin"]
</h6> </h6>
<p class="small text-muted"> <p class="small text-muted">
Ao fazer login, você ganha automaticamente <strong>30 dias sem anúncios</strong> @Localizer["LoginAutomaticallyGain"] <strong>@Localizer["ThirtyDaysNoAds"]</strong>
e pode gerar até <strong>50 QR codes por dia</strong> gratuitamente. @Localizer["AndCanGenerate"] <strong>@Localizer["FiftyQRCodesPerDay"]</strong> @Localizer["ForFree"]
</p> </p>
</div> </div>
<div class="text-center mt-3"> <div class="text-center mt-3">
<small class="text-muted"> <small class="text-muted">
Não cadastramos você sem sua permissão. <br> @Localizer["NoRegisterWithoutPermission"] <br>
<a href="/Home/Privacy" class="text-primary">Política de Privacidade</a> <a href="/Home/Privacy" class="text-primary">@Localizer["PrivacyPolicy"]</a>
</small> </small>
</div> </div>
</div> </div>
@ -68,7 +70,7 @@
<div class="text-center mt-3"> <div class="text-center mt-3">
<a href="/" class="text-muted"> <a href="/" class="text-muted">
<i class="fas fa-arrow-left"></i> Voltar ao gerador <i class="fas fa-arrow-left"></i> @Localizer["BackToGenerator"]
</a> </a>
</div> </div>
</div> </div>

View File

@ -139,18 +139,18 @@
<div class="col-md-3 mb-3"> <div class="col-md-3 mb-3">
<label class="form-label">@Localizer["Size"]</label> <label class="form-label">@Localizer["Size"]</label>
<select id="qr-size" class="form-select"> <select id="qr-size" class="form-select">
<option value="200">Pequeno (200px)</option> <option value="200">@Localizer["SmallSize200px"]</option>
<option value="300" selected>Médio (300px)</option> <option value="300" selected>@Localizer["MediumSize300px"]</option>
<option value="500">Grande (500px)</option> <option value="500">@Localizer["LargeSize500px"]</option>
<option value="800">XL (800px)</option> <option value="800">@Localizer["XLSize800px"]</option>
</select> </select>
</div> </div>
<div class="col-md-3 mb-3"> <div class="col-md-3 mb-3">
<label class="form-label">Margem</label> <label class="form-label">@Localizer["Margin"]</label>
<select id="qr-margin" class="form-select"> <select id="qr-margin" class="form-select">
<option value="1">Mínima</option> <option value="1">@Localizer["Minimal"]</option>
<option value="2" selected>Normal</option> <option value="2" selected>@Localizer["Normal"]</option>
<option value="4">Grande</option> <option value="4">@Localizer["Large"]</option>
</select> </select>
</div> </div>
</div> </div>
@ -159,17 +159,17 @@
{ {
<div class="row"> <div class="row">
<div class="col-md-6 mb-3"> <div class="col-md-6 mb-3">
<label class="form-label">Logo/Ícone</label> <label class="form-label">@Localizer["LogoIcon"]</label>
<input type="file" id="logo-upload" class="form-control" accept="image/*"> <input type="file" id="logo-upload" class="form-control" accept="image/*">
<div class="form-text">PNG, JPG até 2MB</div> <div class="form-text">@Localizer["PNGJPGUp2MB"]</div>
</div> </div>
<div class="col-md-6 mb-3"> <div class="col-md-6 mb-3">
<label class="form-label">Estilo das Bordas</label> <label class="form-label">@Localizer["BorderStyle"]</label>
<select id="corner-style" class="form-select"> <select id="corner-style" class="form-select">
<option value="square">Quadrado</option> <option value="square">@Localizer["Square"]</option>
<option value="rounded">Arredondado</option> <option value="rounded">@Localizer["Rounded"]</option>
<option value="circle">Circular</option> <option value="circle">@Localizer["Circular"]</option>
<option value="leaf">Folha</option> <option value="leaf">@Localizer["Leaf"]</option>
</select> </select>
</div> </div>
</div> </div>
@ -181,9 +181,9 @@
<div class="d-grid"> <div class="d-grid">
<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> Gerar QR Code Rapidamente <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">
<span class="visually-hidden">Gerando...</span> <span class="visually-hidden">@Localizer["Generating"]</span>
</div> </div>
</button> </button>
</div> </div>
@ -199,7 +199,7 @@
<h5 class="text-success"> <h5 class="text-success">
<i class="fas fa-stopwatch"></i> 1.2s <i class="fas fa-stopwatch"></i> 1.2s
</h5> </h5>
<small class="text-muted">Tempo médio</small> <small class="text-muted">@Localizer["AverageTime"]</small>
</div> </div>
</div> </div>
</div> </div>
@ -209,7 +209,7 @@
<h5 class="text-primary"> <h5 class="text-primary">
<i class="fas fa-chart-line"></i> 99.9% <i class="fas fa-chart-line"></i> 99.9%
</h5> </h5>
<small class="text-muted">Disponibilidade</small> <small class="text-muted">@Localizer["Availability"]</small>
</div> </div>
</div> </div>
</div> </div>
@ -219,7 +219,7 @@
<h5 class="text-warning"> <h5 class="text-warning">
<i class="fas fa-users"></i> <span id="total-qrs">10.5K</span> <i class="fas fa-users"></i> <span id="total-qrs">10.5K</span>
</h5> </h5>
<small class="text-muted">QRs gerados hoje</small> <small class="text-muted">@Localizer["QRsGeneratedToday"]</small>
</div> </div>
</div> </div>
</div> </div>
@ -247,9 +247,9 @@
<div id="qr-preview" class="mb-3"> <div id="qr-preview" class="mb-3">
<div class="placeholder-qr p-5"> <div class="placeholder-qr p-5">
<i class="fas fa-qrcode fa-4x text-muted mb-3"></i> <i class="fas fa-qrcode fa-4x text-muted mb-3"></i>
<p class="text-muted">Seu QR code aparecerá aqui em segundos</p> <p class="text-muted">@Localizer["YourQRCodeWillAppear"]</p>
<small class="text-muted"> <small class="text-muted">
<i class="fas fa-bolt"></i> Geração ultra-rápida garantida <i class="fas fa-bolt"></i> @Localizer["UltraFastGenerationGuaranteed"]
</small> </small>
</div> </div>
</div> </div>
@ -257,26 +257,26 @@
<div id="download-section" style="display: none;"> <div id="download-section" style="display: none;">
<div class="btn-group-vertical w-100 mb-3"> <div class="btn-group-vertical w-100 mb-3">
<button id="download-png" class="btn btn-success"> <button id="download-png" class="btn btn-success">
<i class="fas fa-download"></i> Download PNG <i class="fas fa-download"></i> @Localizer["DownloadPNG"]
</button> </button>
<button id="download-svg" class="btn btn-outline-success"> <button id="download-svg" class="btn btn-outline-success">
<i class="fas fa-vector-square"></i> Download SVG (Vetorial) <i class="fas fa-vector-square"></i> @Localizer["DownloadSVGVector"]
</button> </button>
<button id="download-pdf" class="btn btn-outline-success"> <button id="download-pdf" class="btn btn-outline-success">
<i class="fas fa-file-pdf"></i> Download PDF <i class="fas fa-file-pdf"></i> @Localizer["DownloadPDF"]
</button> </button>
</div> </div>
<!-- Share Button with Dropdown --> <!-- Share Button with Dropdown -->
<div class="dropdown w-100 mb-3"> <div class="dropdown w-100 mb-3">
<button class="btn btn-primary dropdown-toggle w-100" type="button" id="share-qr-btn" data-bs-toggle="dropdown" aria-expanded="false"> <button class="btn btn-primary dropdown-toggle w-100" type="button" id="share-qr-btn" data-bs-toggle="dropdown" aria-expanded="false">
<i class="fas fa-share-alt"></i> Compartilhar QR Code <i class="fas fa-share-alt"></i> @Localizer["ShareQRCode"]
</button> </button>
<ul class="dropdown-menu w-100" aria-labelledby="share-qr-btn" id="share-dropdown"> <ul class="dropdown-menu w-100" aria-labelledby="share-qr-btn" id="share-dropdown">
<!-- Native share option (mobile only) --> <!-- Native share option (mobile only) -->
<li class="d-none" id="native-share-option"> <li class="d-none" id="native-share-option">
<a class="dropdown-item" href="#" id="native-share"> <a class="dropdown-item" href="#" id="native-share">
<i class="fas fa-mobile-alt text-primary"></i> Compartilhar (Sistema) <i class="fas fa-mobile-alt text-primary"></i> @Localizer["ShareSystem"]
</a> </a>
</li> </li>
<!-- WhatsApp --> <!-- WhatsApp -->
@ -315,15 +315,15 @@
@if (User.Identity.IsAuthenticated) @if (User.Identity.IsAuthenticated)
{ {
<button id="save-to-history" class="btn btn-outline-primary w-100"> <button id="save-to-history" class="btn btn-outline-primary w-100">
<i class="fas fa-save"></i> Salvar no Histórico <i class="fas fa-save"></i> @Localizer["SaveToHistory"]
</button> </button>
} }
else else
{ {
<div class="text-center"> <div class="text-center">
<small class="text-muted"> <small class="text-muted">
<a href="/Account/Login" class="text-primary">Faça login</a> <a href="/Account/Login" class="text-primary">@Localizer["Login"]</a>
para salvar no histórico @Localizer["ToSaveToHistory"]
</small> </small>
</div> </div>
} }
@ -342,21 +342,21 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="text-center mb-3"> <div class="text-center mb-3">
<div class="badge bg-success mb-2">⚡ 3x Mais Rápido</div> <div class="badge bg-success mb-2">@Localizer["ThreeTimesFaster"]</div>
</div> </div>
<ul class="list-unstyled"> <ul class="list-unstyled">
<li><i class="fas fa-check text-success"></i> Sem anúncios para sempre</li> <li><i class="fas fa-check text-success"></i> @Localizer["NoAdsForever"]</li>
<li><i class="fas fa-check text-success"></i> QR codes ilimitados</li> <li><i class="fas fa-check text-success"></i> @Localizer["UnlimitedQRCodes"]</li>
<li><i class="fas fa-check text-success"></i> Geração prioritária (0.4s)</li> <li><i class="fas fa-check text-success"></i> @Localizer["PriorityGeneration"]</li>
<li><i class="fas fa-check text-success"></i> QR codes dinâmicos</li> <li><i class="fas fa-check text-success"></i> @Localizer["DynamicQRCodes"]</li>
<li><i class="fas fa-check text-success"></i> Analytics em tempo real</li> <li><i class="fas fa-check text-success"></i> @Localizer["RealTimeAnalytics"]</li>
<li><i class="fas fa-check text-success"></i> API para desenvolvedores</li> <li><i class="fas fa-check text-success"></i> @Localizer["DeveloperAPI"]</li>
</ul> </ul>
<div class="text-center"> <div class="text-center">
<a href="/Premium/Upgrade" class="btn btn-warning w-100"> <a href="/Premium/Upgrade" class="btn btn-warning w-100">
<i class="fas fa-bolt"></i> Acelerar por R$ 19,90/mês <i class="fas fa-bolt"></i> @Localizer["AcceleratePrice"]
</a> </a>
<small class="text-muted d-block mt-1">Cancele quando quiser</small> <small class="text-muted d-block mt-1">@Localizer["CancelAnytime"]</small>
</div> </div>
</div> </div>
</div> </div>
@ -366,15 +366,15 @@
<div class="card bg-light mb-4"> <div class="card bg-light mb-4">
<div class="card-header"> <div class="card-header">
<h6 class="mb-0"> <h6 class="mb-0">
<i class="fas fa-lightbulb text-warning"></i> Dicas para QR Mais Rápidos <i class="fas fa-lightbulb text-warning"></i> @Localizer["TipsFasterQR"]
</h6> </h6>
</div> </div>
<div class="card-body"> <div class="card-body">
<ul class="list-unstyled small"> <ul class="list-unstyled small">
<li><i class="fas fa-arrow-right text-primary"></i> URLs curtas geram mais rápido</li> <li><i class="fas fa-arrow-right text-primary"></i> @Localizer["ShortURLsFaster"]</li>
<li><i class="fas fa-arrow-right text-primary"></i> Menos texto = maior velocidade</li> <li><i class="fas fa-arrow-right text-primary"></i> @Localizer["LessTextMoreSpeed"]</li>
<li><i class="fas fa-arrow-right text-primary"></i> Cores sólidas otimizam o processo</li> <li><i class="fas fa-arrow-right text-primary"></i> @Localizer["SolidColorsOptimize"]</li>
<li><i class="fas fa-arrow-right text-primary"></i> Tamanhos menores aceleram o download</li> <li><i class="fas fa-arrow-right text-primary"></i> @Localizer["SmallerSizesAccelerate"]</li>
</ul> </ul>
</div> </div>
</div> </div>
@ -389,8 +389,8 @@
<section class="mt-5 mb-4"> <section class="mt-5 mb-4">
<div class="container"> <div class="container">
<div class="text-center mb-4"> <div class="text-center mb-4">
<h3><i class="fas fa-tachometer-alt text-primary"></i> Por que QR Rapido é mais rápido?</h3> <h3><i class="fas fa-tachometer-alt text-primary"></i> @Localizer["WhyQRRapidoFaster"]</h3>
<p class="text-muted">Comparação com outros geradores populares</p> <p class="text-muted">@Localizer["ComparisonOtherGenerators"]</p>
</div> </div>
<div class="row"> <div class="row">
@ -399,7 +399,7 @@
<div class="card-body text-center"> <div class="card-body text-center">
<h5 class="text-success">QR Rapido</h5> <h5 class="text-success">QR Rapido</h5>
<div class="display-4 text-success fw-bold">1.2s</div> <div class="display-4 text-success fw-bold">1.2s</div>
<p class="text-muted">Otimizado para velocidade</p> <p class="text-muted">@Localizer["OptimizedForSpeed"]</p>
<i class="fas fa-crown text-warning"></i> <i class="fas fa-crown text-warning"></i>
</div> </div>
</div> </div>
@ -407,27 +407,27 @@
<div class="col-md-3"> <div class="col-md-3">
<div class="card h-100"> <div class="card h-100">
<div class="card-body text-center"> <div class="card-body text-center">
<h5 class="text-muted">Concorrente A</h5> <h5 class="text-muted">@Localizer["CompetitorA"]</h5>
<div class="display-4 text-muted">3.5s</div> <div class="display-4 text-muted">3.5s</div>
<p class="text-muted">Gerador tradicional</p> <p class="text-muted">@Localizer["TraditionalGenerator"]</p>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<div class="card h-100"> <div class="card h-100">
<div class="card-body text-center"> <div class="card-body text-center">
<h5 class="text-muted">Concorrente B</h5> <h5 class="text-muted">@Localizer["CompetitorB"]</h5>
<div class="display-4 text-muted">4.8s</div> <div class="display-4 text-muted">4.8s</div>
<p class="text-muted">Interface pesada</p> <p class="text-muted">@Localizer["HeavyInterface"]</p>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<div class="card h-100"> <div class="card h-100">
<div class="card-body text-center"> <div class="card-body text-center">
<h5 class="text-muted">Concorrente C</h5> <h5 class="text-muted">@Localizer["CompetitorC"]</h5>
<div class="display-4 text-muted">6.2s</div> <div class="display-4 text-muted">6.2s</div>
<p class="text-muted">Muitos anúncios</p> <p class="text-muted">@Localizer["ManyAds"]</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,12 +1,13 @@
@using Microsoft.Extensions.Localization
@inject IStringLocalizer<QRRapidoApp.Resources.SharedResource> Localizer
@{ @{
ViewData["Title"] = "Pagamento Cancelado"; ViewData["Title"] = "Pagamento Cancelado";
} }
<div class="container text-center mt-5"> <div class="container text-center mt-5">
<div class="alert alert-warning"> <div class="alert alert-warning">
<h4 class="alert-heading">Pagamento cancelado.</h4> <h4 class="alert-heading">@Localizer["PaymentCanceled"]</h4>
<p>@ViewBag.CancelMessage</p> <p>@ViewBag.CancelMessage</p>
</div> </div>
<a href="/Pagamento/SelecaoPlano" class="btn btn-primary">Ver Planos</a> <a href="/Pagamento/SelecaoPlano" class="btn btn-primary">@Localizer["ViewPlans"]</a>
</div> </div>

View File

@ -1,5 +1,6 @@
@using Microsoft.Extensions.Localization
@model QRRapidoApp.Models.ViewModels.SelecaoPlanoViewModel @model QRRapidoApp.Models.ViewModels.SelecaoPlanoViewModel
@inject IStringLocalizer<QRRapidoApp.Resources.SharedResource> Localizer
@{ @{
ViewData["Title"] = "Escolha seu Plano Premium"; ViewData["Title"] = "Escolha seu Plano Premium";
Layout = "~/Views/Shared/_Layout.cshtml"; Layout = "~/Views/Shared/_Layout.cshtml";
@ -12,8 +13,8 @@
<div class="container mt-5"> <div class="container mt-5">
<div class="text-center mb-5"> <div class="text-center mb-5">
<h1 class="display-4">Desbloqueie o Poder Total do QRRápido</h1> <h1 class="display-4">@Localizer["UnlockFullPowerQRRapido"]</h1>
<p class="lead text-muted">Acesso sem limites, sem anúncios e com recursos exclusivos para máxima produtividade.</p> <p class="lead text-muted">@Localizer["UnlimitedAccessNoAdsExclusive"]</p>
</div> </div>
<div class="row justify-content-center g-4"> <div class="row justify-content-center g-4">
@ -23,13 +24,13 @@
<div class="col-lg-4 col-md-6"> <div class="col-lg-4 col-md-6">
<div class="card h-100 shadow-sm"> <div class="card h-100 shadow-sm">
<div class="card-body d-flex flex-column"> <div class="card-body d-flex flex-column">
<h3 class="card-title text-center">Plano Mensal</h3> <h3 class="card-title text-center">@Localizer["MonthlyPlan"]</h3>
<div class="text-center my-4"> <div class="text-center my-4">
<span class="display-4 fw-bold">R$ @monthlyPrice.ToString("0.00")</span> <span class="display-4 fw-bold">R$ @monthlyPrice.ToString("0.00")</span>
<span class="text-muted">/mês</span> <span class="text-muted">@Localizer["PerMonth"]</span>
</div> </div>
<p class="text-center text-muted">Ideal para começar a explorar os recursos premium.</p> <p class="text-center text-muted">@Localizer["IdealToStartExploring"]</p>
<button class="btn btn-outline-primary mt-auto checkout-btn" data-plan-id="@monthlyPlan.Id">Assinar Agora</button> <button class="btn btn-outline-primary mt-auto checkout-btn" data-plan-id="@monthlyPlan.Id">@Localizer["SubscribeNow"]</button>
</div> </div>
</div> </div>
</div> </div>
@ -41,22 +42,22 @@
<div class="col-lg-4 col-md-6"> <div class="col-lg-4 col-md-6">
<div class="card h-100 shadow border-primary"> <div class="card h-100 shadow border-primary">
<div class="card-header bg-primary text-white text-center"> <div class="card-header bg-primary text-white text-center">
<h3 class="card-title mb-0">Plano Anual</h3> <h3 class="card-title mb-0">@Localizer["AnnualPlan"]</h3>
<p class="mb-0">Recomendado</p> <p class="mb-0">@Localizer["Recommended"]</p>
</div> </div>
<div class="card-body d-flex flex-column"> <div class="card-body d-flex flex-column">
<div class="text-center my-4"> <div class="text-center my-4">
<span class="display-4 fw-bold">R$ @yearlyPrice.ToString("0.00")</span> <span class="display-4 fw-bold">R$ @yearlyPrice.ToString("0.00")</span>
<span class="text-muted">/ano</span> <span class="text-muted">@Localizer["PerYear"]</span>
</div> </div>
@if (yearlySavings > 0) @if (yearlySavings > 0)
{ {
<div class="text-center mb-3"> <div class="text-center mb-3">
<span class="badge bg-success">Economize R$ @yearlySavings.ToString("0.00")!</span> <span class="badge bg-success">@Localizer["SaveMoney"] @yearlySavings.ToString("0.00")!</span>
</div> </div>
} }
<p class="text-center text-muted">O melhor custo-benefício para usuários frequentes.</p> <p class="text-center text-muted">@Localizer["BestValueFrequentUsers"]</p>
<button class="btn btn-primary mt-auto checkout-btn" data-plan-id="@yearlyPlan.Id">Assinar Plano Anual</button> <button class="btn btn-primary mt-auto checkout-btn" data-plan-id="@yearlyPlan.Id">@Localizer["SubscribeAnnualPlan"]</button>
</div> </div>
</div> </div>
</div> </div>
@ -66,13 +67,13 @@
<!-- Lista de Recursos --> <!-- Lista de Recursos -->
<div class="row justify-content-center mt-5"> <div class="row justify-content-center mt-5">
<div class="col-lg-8"> <div class="col-lg-8">
<h3 class="text-center mb-4">Todos os planos incluem:</h3> <h3 class="text-center mb-4">@Localizer["AllPlansInclude"]</h3>
<ul class="list-group list-group-flush"> <ul class="list-group list-group-flush">
<li class="list-group-item border-0"><i class="fas fa-check-circle text-success me-2"></i>QR codes ilimitados</li> <li class="list-group-item border-0"><i class="fas fa-check-circle text-success me-2"></i>@Localizer["UnlimitedQRCodes"]</li>
<li class="list-group-item border-0"><i class="fas fa-check-circle text-success me-2"></i>Sem anúncios</li> <li class="list-group-item border-0"><i class="fas fa-check-circle text-success me-2"></i>@Localizer["NoAds"]</li>
<li class="list-group-item border-0"><i class="fas fa-check-circle text-success me-2"></i>QR codes dinâmicos</li> <li class="list-group-item border-0"><i class="fas fa-check-circle text-success me-2"></i>@Localizer["DynamicQRCodes"]</li>
<li class="list-group-item border-0"><i class="fas fa-check-circle text-success me-2"></i>Analytics em tempo real</li> <li class="list-group-item border-0"><i class="fas fa-check-circle text-success me-2"></i>@Localizer["RealTimeAnalytics"]</li>
<li class="list-group-item border-0"><i class="fas fa-check-circle text-success me-2"></i>Suporte prioritário</li> <li class="list-group-item border-0"><i class="fas fa-check-circle text-success me-2"></i>@Localizer["PrioritySupport"]</li>
</ul> </ul>
</div> </div>
</div> </div>
@ -84,7 +85,7 @@
button.addEventListener('click', async function() { button.addEventListener('click', async function() {
const planId = this.dataset.planId; const planId = this.dataset.planId;
this.disabled = true; this.disabled = true;
this.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Redirecionando...'; this.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> @Localizer["Redirecting"]';
try { try {
const response = await fetch('/Pagamento/CreateCheckout', { const response = await fetch('/Pagamento/CreateCheckout', {
@ -100,13 +101,13 @@
if (result.success) { if (result.success) {
window.location.href = result.url; window.location.href = result.url;
} else { } else {
alert('Erro: ' + result.error); alert('@Localizer["Error"] ' + result.error);
this.disabled = false; this.disabled = false;
this.innerHTML = 'Assinar Agora'; // Reset button text this.innerHTML = '@Localizer["SubscribeNow"]'; // Reset button text
} }
} catch (error) { } catch (error) {
console.error('Checkout error:', error); console.error('Checkout error:', error);
alert('Ocorreu um erro ao iniciar o pagamento. Tente novamente.'); alert('@Localizer["PaymentInitializationError"]');
this.disabled = false; this.disabled = false;
this.innerHTML = 'Assinar Agora'; // Reset button text this.innerHTML = 'Assinar Agora'; // Reset button text
} }

View File

@ -1,12 +1,13 @@
@using Microsoft.Extensions.Localization
@inject IStringLocalizer<QRRapidoApp.Resources.SharedResource> Localizer
@{ @{
ViewData["Title"] = "Sucesso"; ViewData["Title"] = "Sucesso";
} }
<div class="container text-center mt-5"> <div class="container text-center mt-5">
<div class="alert alert-success"> <div class="alert alert-success">
<h4 class="alert-heading">Pagamento bem-sucedido!</h4> <h4 class="alert-heading">@Localizer["PaymentSuccessful"]</h4>
<p>@ViewBag.SuccessMessage</p> <p>@ViewBag.SuccessMessage</p>
</div> </div>
<a href="/" class="btn btn-primary">Voltar ao Início</a> <a href="/" class="btn btn-primary">@Localizer["BackToHome"]</a>
</div> </div>

View File

@ -1,4 +1,6 @@
@model QRRapidoApp.Models.ViewModels.UpgradeViewModel @model QRRapidoApp.Models.ViewModels.UpgradeViewModel
@using Microsoft.Extensions.Localization
@inject IStringLocalizer<QRRapidoApp.Resources.SharedResource> Localizer
@{ @{
ViewData["Title"] = "QR Rapido Premium"; ViewData["Title"] = "QR Rapido Premium";
} }
@ -12,10 +14,10 @@
<i class="fas fa-rocket"></i> QR Rapido Premium <i class="fas fa-rocket"></i> QR Rapido Premium
</h1> </h1>
<p class="lead text-muted"> <p class="lead text-muted">
Acelere sua produtividade com o gerador de QR mais rápido do mundo @Localizer["PremiumAccelerateProductivity"]
</p> </p>
<div class="badge bg-success fs-6 p-2"> <div class="badge bg-success fs-6 p-2">
<i class="fas fa-bolt"></i> 3x mais rápido que a concorrência <i class="fas fa-bolt"></i> @Localizer["ThreeTimesFaster"]
</div> </div>
</div> </div>
@ -25,15 +27,15 @@
<div class="alert alert-info border-0 shadow-sm mb-4"> <div class="alert alert-info border-0 shadow-sm mb-4">
<div class="row align-items-center"> <div class="row align-items-center">
<div class="col-md-8"> <div class="col-md-8">
<h6><i class="fas fa-info-circle"></i> Status Atual</h6> <h6><i class="fas fa-info-circle"></i> @Localizer["CurrentStatus"]</h6>
<p class="mb-0"> <p class="mb-0">
Você tem <strong>@Model.DaysUntilAdExpiry dias</strong> restantes sem anúncios. @Localizer["YouHave"] <strong>@Model.DaysUntilAdExpiry @Localizer["DaysRemainingNoAds"]</strong>
Upgrade agora e tenha acesso premium para sempre! @Localizer["UpgradeNowForever"]
</p> </p>
</div> </div>
<div class="col-md-4 text-end"> <div class="col-md-4 text-end">
<div class="badge bg-success p-2"> <div class="badge bg-success p-2">
@Model.DaysUntilAdExpiry dias restantes @Model.DaysUntilAdExpiry @Localizer["DaysRemaining"]
</div> </div>
</div> </div>
</div> </div>
@ -48,54 +50,54 @@
<h3 class="mb-0"> <h3 class="mb-0">
<i class="fas fa-crown"></i> QR Rapido Premium <i class="fas fa-crown"></i> QR Rapido Premium
</h3> </h3>
<small>O plano mais popular</small> <small>@Localizer["MostPopularPlan"]</small>
</div> </div>
<div class="card-body text-center"> <div class="card-body text-center">
<div class="display-3 text-warning fw-bold mb-2"> <div class="display-3 text-warning fw-bold mb-2">
R$ @Model.PremiumPrice.ToString("0.00") R$ @Model.PremiumPrice.ToString("0.00")
</div> </div>
<p class="text-muted">por mês</p> <p class="text-muted">@Localizer["PerMonth"]</p>
<div class="list-group list-group-flush mb-4"> <div class="list-group list-group-flush mb-4">
<div class="list-group-item border-0"> <div class="list-group-item border-0">
<i class="fas fa-infinity text-success me-2"></i> <i class="fas fa-infinity text-success me-2"></i>
<strong>QR codes ilimitados</strong> <strong>@Localizer["UnlimitedQRCodes"]</strong>
</div> </div>
<div class="list-group-item border-0"> <div class="list-group-item border-0">
<i class="fas fa-bolt text-success me-2"></i> <i class="fas fa-bolt text-success me-2"></i>
<strong>Geração ultra-rápida (0.4s)</strong> <strong>@Localizer["UltraFastGeneration04s"]</strong>
</div> </div>
<div class="list-group-item border-0"> <div class="list-group-item border-0">
<i class="fas fa-ban text-success me-2"></i> <i class="fas fa-ban text-success me-2"></i>
<strong>Sem anúncios para sempre</strong> <strong>@Localizer["NoAdsForever"]</strong>
</div> </div>
<div class="list-group-item border-0"> <div class="list-group-item border-0">
<i class="fas fa-magic text-success me-2"></i> <i class="fas fa-magic text-success me-2"></i>
<strong>QR codes dinâmicos</strong> <strong>@Localizer["DynamicQRCodes"]</strong>
</div> </div>
<div class="list-group-item border-0"> <div class="list-group-item border-0">
<i class="fas fa-chart-line text-success me-2"></i> <i class="fas fa-chart-line text-success me-2"></i>
<strong>Analytics em tempo real</strong> <strong>@Localizer["RealTimeAnalytics"]</strong>
</div> </div>
<div class="list-group-item border-0"> <div class="list-group-item border-0">
<i class="fas fa-headset text-success me-2"></i> <i class="fas fa-headset text-success me-2"></i>
<strong>Suporte prioritário</strong> <strong>@Localizer["PrioritySupport"]</strong>
</div> </div>
<div class="list-group-item border-0"> <div class="list-group-item border-0">
<i class="fas fa-code text-success me-2"></i> <i class="fas fa-code text-success me-2"></i>
<strong>API para desenvolvedores</strong> <strong>@Localizer["DeveloperAPI"]</strong>
</div> </div>
</div> </div>
<button id="upgrade-btn" class="btn btn-warning btn-lg w-100 mb-3"> <button id="upgrade-btn" class="btn btn-warning btn-lg w-100 mb-3">
<i class="fas fa-rocket"></i> Fazer Upgrade Agora <i class="fas fa-rocket"></i> @Localizer["UpgradeNowButton"]
<div class="spinner-border spinner-border-sm ms-2 d-none" role="status"></div> <div class="spinner-border spinner-border-sm ms-2 d-none" role="status"></div>
</button> </button>
<small class="text-muted"> <small class="text-muted">
<i class="fas fa-shield-alt"></i> Pagamento seguro via Stripe <i class="fas fa-shield-alt"></i> @Localizer["SecurePaymentStripe"]
<br> <br>
<i class="fas fa-times-circle"></i> Cancele quando quiser <i class="fas fa-times-circle"></i> @Localizer["CancelAnytime"]
</small> </small>
</div> </div>
</div> </div>
@ -106,7 +108,7 @@
<div class="card shadow-sm mb-5"> <div class="card shadow-sm mb-5">
<div class="card-header"> <div class="card-header">
<h4 class="mb-0"> <h4 class="mb-0">
<i class="fas fa-balance-scale"></i> Comparação de Planos <i class="fas fa-balance-scale"></i> @Localizer["PlanComparison"]
</h4> </h4>
</div> </div>
<div class="card-body"> <div class="card-body">
@ -114,39 +116,39 @@
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr> <tr>
<th>Recurso</th> <th>@Localizer["Feature"]</th>
<th class="text-center">Free</th> <th class="text-center">Free</th>
<th class="text-center bg-warning text-dark">Premium</th> <th class="text-center bg-warning text-dark">Premium</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td>QR codes por dia</td> <td>@Localizer["QRCodesPerDay"]</td>
<td class="text-center">50</td> <td class="text-center">50</td>
<td class="text-center"><i class="fas fa-infinity text-success"></i> Ilimitado</td> <td class="text-center"><i class="fas fa-infinity text-success"></i> @Localizer["Unlimited"]</td>
</tr> </tr>
<tr> <tr>
<td>Velocidade de geração</td> <td>@Localizer["GenerationSpeed"]</td>
<td class="text-center">1.2s</td> <td class="text-center">1.2s</td>
<td class="text-center"><strong class="text-success">0.4s</strong></td> <td class="text-center"><strong class="text-success">0.4s</strong></td>
</tr> </tr>
<tr> <tr>
<td>Anúncios</td> <td>@Localizer["Ads"]</td>
<td class="text-center"><i class="fas fa-times text-danger"></i></td> <td class="text-center"><i class="fas fa-times text-danger"></i></td>
<td class="text-center"><i class="fas fa-check text-success"></i> Sem anúncios</td> <td class="text-center"><i class="fas fa-check text-success"></i> @Localizer["NoAds"]</td>
</tr> </tr>
<tr> <tr>
<td>QR codes dinâmicos</td> <td>@Localizer["DynamicQRCodes"]</td>
<td class="text-center"><i class="fas fa-times text-danger"></i></td> <td class="text-center"><i class="fas fa-times text-danger"></i></td>
<td class="text-center"><i class="fas fa-check text-success"></i></td> <td class="text-center"><i class="fas fa-check text-success"></i></td>
</tr> </tr>
<tr> <tr>
<td>Analytics detalhados</td> <td>@Localizer["DetailedAnalytics"]</td>
<td class="text-center"><i class="fas fa-times text-danger"></i></td> <td class="text-center"><i class="fas fa-times text-danger"></i></td>
<td class="text-center"><i class="fas fa-check text-success"></i></td> <td class="text-center"><i class="fas fa-check text-success"></i></td>
</tr> </tr>
<tr> <tr>
<td>Suporte prioritário</td> <td>@Localizer["PrioritySupport"]</td>
<td class="text-center"><i class="fas fa-times text-danger"></i></td> <td class="text-center"><i class="fas fa-times text-danger"></i></td>
<td class="text-center"><i class="fas fa-check text-success"></i></td> <td class="text-center"><i class="fas fa-check text-success"></i></td>
</tr> </tr>
@ -165,7 +167,7 @@
<div class="card shadow-sm mb-5"> <div class="card shadow-sm mb-5">
<div class="card-header bg-primary text-white"> <div class="card-header bg-primary text-white">
<h4 class="mb-0"> <h4 class="mb-0">
<i class="fas fa-stopwatch"></i> Demonstração de Velocidade <i class="fas fa-stopwatch"></i> @Localizer["SpeedDemonstration"]
</h4> </h4>
</div> </div>
<div class="card-body"> <div class="card-body">
@ -173,9 +175,9 @@
<div class="col-md-4"> <div class="col-md-4">
<div class="card border-danger"> <div class="card border-danger">
<div class="card-body"> <div class="card-body">
<h5 class="text-danger">Concorrentes</h5> <h5 class="text-danger">@Localizer["Competitors"]</h5>
<div class="display-4 text-danger">4.5s</div> <div class="display-4 text-danger">4.5s</div>
<p class="text-muted">Tempo médio</p> <p class="text-muted">@Localizer["AverageTime"]</p>
</div> </div>
</div> </div>
</div> </div>
@ -184,7 +186,7 @@
<div class="card-body"> <div class="card-body">
<h5 class="text-primary">QR Rapido Free</h5> <h5 class="text-primary">QR Rapido Free</h5>
<div class="display-4 text-primary">1.2s</div> <div class="display-4 text-primary">1.2s</div>
<p class="text-muted">3x mais rápido</p> <p class="text-muted">@Localizer["ThreeTimesFaster"]</p>
</div> </div>
</div> </div>
</div> </div>
@ -193,7 +195,7 @@
<div class="card-body"> <div class="card-body">
<h5 class="text-success">QR Rapido Premium</h5> <h5 class="text-success">QR Rapido Premium</h5>
<div class="display-4 text-success">0.4s</div> <div class="display-4 text-success">0.4s</div>
<p class="text-muted">11x mais rápido!</p> <p class="text-muted">@Localizer["ElevenTimesFaster"]</p>
</div> </div>
</div> </div>
</div> </div>
@ -205,7 +207,7 @@
<div class="card shadow-sm"> <div class="card shadow-sm">
<div class="card-header"> <div class="card-header">
<h4 class="mb-0"> <h4 class="mb-0">
<i class="fas fa-question-circle"></i> Perguntas Frequentes <i class="fas fa-question-circle"></i> @Localizer["FAQ"]
</h4> </h4>
</div> </div>
<div class="card-body"> <div class="card-body">
@ -213,39 +215,36 @@
<div class="accordion-item"> <div class="accordion-item">
<h2 class="accordion-header"> <h2 class="accordion-header">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#faq1"> <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#faq1">
Posso cancelar a qualquer momento? @Localizer["CanCancelAnytime"]
</button> </button>
</h2> </h2>
<div id="faq1" class="accordion-collapse collapse show"> <div id="faq1" class="accordion-collapse collapse show">
<div class="accordion-body"> <div class="accordion-body">
Sim! Você pode cancelar sua assinatura a qualquer momento. Não há taxas de cancelamento @Localizer["CancelAnytimeAnswer"]
e você manterá o acesso premium até o final do período já pago.
</div> </div>
</div> </div>
</div> </div>
<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="#faq2"> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faq2">
O que são QR codes dinâmicos? @Localizer["WhatAreDynamicQR"]
</button> </button>
</h2> </h2>
<div id="faq2" class="accordion-collapse collapse"> <div id="faq2" class="accordion-collapse collapse">
<div class="accordion-body"> <div class="accordion-body">
QR codes dinâmicos permitem que você altere o conteúdo do QR após ele ter sido criado, @Localizer["DynamicQRAnswer"]
sem precisar gerar um novo código. Perfeito para campanhas de marketing e uso empresarial.
</div> </div>
</div> </div>
</div> </div>
<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="#faq3"> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faq3">
Como funciona o suporte prioritário? @Localizer["HowPrioritySupport"]
</button> </button>
</h2> </h2>
<div id="faq3" class="accordion-collapse collapse"> <div id="faq3" class="accordion-collapse collapse">
<div class="accordion-body"> <div class="accordion-body">
Usuários premium recebem resposta em até 2 horas úteis por email, @Localizer["PrioritySupportAnswer"]
acesso ao chat direto e suporte técnico especializado.
</div> </div>
</div> </div>
</div> </div>
@ -287,11 +286,11 @@
window.location.href = result.url; window.location.href = result.url;
} else { } else {
alert('Erro ao processar pagamento: ' + result.error); alert('@Localizer["PaymentProcessingError"]' + result.error);
} }
} catch (error) { } catch (error) {
console.error('Erro:', error); console.error('Erro:', error);
alert('Erro ao processar pagamento. Tente novamente.'); alert('@Localizer["PaymentErrorTryAgain"]');
} finally { } finally {
btn.disabled = false; btn.disabled = false;
spinner.classList.add('d-none'); spinner.classList.add('d-none');

View File

@ -1,6 +1,8 @@
@using QRRapidoApp.Services @using QRRapidoApp.Services
@using Microsoft.Extensions.Localization
@model dynamic @model dynamic
@inject AdDisplayService AdService @inject AdDisplayService AdService
@inject IStringLocalizer<QRRapidoApp.Resources.SharedResource> Localizer
@{ @{
var userId = User?.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value; var userId = User?.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
var showAds = await AdService.ShouldShowAds(userId); var showAds = await AdService.ShouldShowAds(userId);
@ -13,7 +15,7 @@
{ {
case "header": case "header":
<div class="ad-container ad-header mb-4"> <div class="ad-container ad-header mb-4">
<div class="ad-label">Publicidade</div> <div class="ad-label">@Localizer["Advertisement"]</div>
<ins class="adsbygoogle" <ins class="adsbygoogle"
style="display:inline-block;width:728px;height:90px" style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-XXXXXXXXXX" data-ad-client="ca-pub-XXXXXXXXXX"
@ -23,7 +25,7 @@
case "sidebar": case "sidebar":
<div class="ad-container ad-sidebar mb-4"> <div class="ad-container ad-sidebar mb-4">
<div class="ad-label">Publicidade</div> <div class="ad-label">@Localizer["Advertisement"]</div>
<ins class="adsbygoogle" <ins class="adsbygoogle"
style="display:inline-block;width:300px;height:250px" style="display:inline-block;width:300px;height:250px"
data-ad-client="ca-pub-XXXXXXXXXX" data-ad-client="ca-pub-XXXXXXXXXX"
@ -33,7 +35,7 @@
case "footer": case "footer":
<div class="ad-container ad-footer mt-5 mb-4"> <div class="ad-container ad-footer mt-5 mb-4">
<div class="ad-label">Publicidade</div> <div class="ad-label">@Localizer["Advertisement"]</div>
<ins class="adsbygoogle" <ins class="adsbygoogle"
style="display:inline-block;width:728px;height:90px" style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-XXXXXXXXXX" data-ad-client="ca-pub-XXXXXXXXXX"
@ -43,7 +45,7 @@
case "content": case "content":
<div class="ad-container ad-content my-4"> <div class="ad-container ad-content my-4">
<div class="ad-label">Publicidade</div> <div class="ad-label">@Localizer["Advertisement"]</div>
<ins class="adsbygoogle" <ins class="adsbygoogle"
style="display:block" style="display:block"
data-ad-client="ca-pub-XXXXXXXXXX" data-ad-client="ca-pub-XXXXXXXXXX"
@ -66,7 +68,7 @@ else if (User.Identity.IsAuthenticated)
<!-- Premium User Message --> <!-- Premium User Message -->
<div class="alert alert-success ad-free-notice mb-3"> <div class="alert alert-success ad-free-notice mb-3">
<i class="fas fa-crown text-warning"></i> <i class="fas fa-crown text-warning"></i>
<span><strong>✨ Usuário Premium - Sem anúncios!</strong></span> <span><strong>@Localizer["PremiumUserNoAds"]</strong></span>
</div> </div>
} }
else else
@ -74,9 +76,9 @@ else if (User.Identity.IsAuthenticated)
<!-- Upgrade to Premium Message --> <!-- Upgrade to Premium Message -->
<div class="alert alert-info upgrade-notice mb-3"> <div class="alert alert-info upgrade-notice mb-3">
<i class="fas fa-star text-warning"></i> <i class="fas fa-star text-warning"></i>
<span><strong>Faça upgrade para Premium e remova os anúncios!</strong></span> <span><strong>@Localizer["UpgradePremiumRemoveAds"]</strong></span>
<a href="/Premium/Upgrade" class="btn btn-sm btn-warning ms-2"> <a href="/Premium/Upgrade" class="btn btn-sm btn-warning ms-2">
<i class="fas fa-crown"></i> Premium: Sem anúncios + Histórico + QR ilimitados <i class="fas fa-crown"></i> @Localizer["PremiumBenefitsShort"]
</a> </a>
</div> </div>
} }

View File

@ -170,11 +170,19 @@
</ul> </ul>
</div> </div>
<!-- Theme Toggle -->
<div class="theme-toggle-container">
<button id="theme-toggle" class="btn btn-outline-secondary btn-sm" type="button" title="Alternar tema">
<i id="theme-icon" class="fas fa-sun"></i>
<span id="theme-text" class="d-none d-md-inline ms-1">Claro</span>
</button>
</div>
<!-- Global speed timer --> <!-- Global speed timer -->
<div class="d-none d-md-block"> <div class="d-none d-md-block">
<small class="text-success fw-bold"> <small class="text-success fw-bold">
<i class="fas fa-stopwatch"></i> <i class="fas fa-stopwatch"></i>
<span id="avg-generation-time">1.2s</span> médio <span id="avg-generation-time">1.2s</span> @Localizer["Average"]
</small> </small>
</div> </div>
@ -186,13 +194,13 @@
</button> </button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a class="dropdown-item" href="/"> <li><a class="dropdown-item" href="/">
<i class="fas fa-qrcode"></i> Gerar QRCode <i class="fas fa-qrcode"></i> @Localizer["GenerateQRCode"]
</a></li> </a></li>
<li><a class="dropdown-item" href="/Account/Profile"> <li><a class="dropdown-item" href="/Account/Profile">
<i class="fas fa-user-cog"></i> Perfil <i class="fas fa-user-cog"></i> @Localizer["Profile"]
</a></li> </a></li>
<li><a class="dropdown-item" href="/Account/History"> <li><a class="dropdown-item" href="/Account/History">
<i class="fas fa-history"></i> Histórico <i class="fas fa-history"></i> @Localizer["History"]
</a></li> </a></li>
@{ @{
var userId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value; var userId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
@ -201,7 +209,7 @@
@if (!shouldShowAds) @if (!shouldShowAds)
{ {
<li><span class="dropdown-item text-success"> <li><span class="dropdown-item text-success">
<i class="fas fa-crown"></i> Premium Ativo <i class="fas fa-crown"></i> @Localizer["PremiumActive"]
</span></li> </span></li>
} }
else else
@ -214,7 +222,7 @@
<li> <li>
<form method="post" action="/Account/Logout" class="d-inline"> <form method="post" action="/Account/Logout" class="d-inline">
<button type="submit" class="dropdown-item"> <button type="submit" class="dropdown-item">
<i class="fas fa-sign-out-alt"></i> Sair <i class="fas fa-sign-out-alt"></i> @Localizer["Logout"]
</button> </button>
</form> </form>
</li> </li>
@ -228,7 +236,7 @@
</a> </a>
<div class="d-none d-md-block"> <div class="d-none d-md-block">
<small class="text-success"> <small class="text-success">
<i class="fas fa-gift"></i> Login = 30 dias sem anúncios! <i class="fas fa-gift"></i> @Localizer["LoginThirtyDaysNoAds"]
</small> </small>
</div> </div>
} }
@ -240,10 +248,10 @@
<section class="bg-gradient-primary text-white py-4 mb-4"> <section class="bg-gradient-primary text-white py-4 mb-4">
<div class="container text-center"> <div class="container text-center">
<h2 class="h5 mb-2"> <h2 class="h5 mb-2">
<i class="fas fa-bolt"></i> O gerador de QR mais rápido da web <i class="fas fa-bolt"></i> @Localizer["FastestQRGeneratorWeb"]
</h2> </h2>
<p class="mb-0 opacity-75"> <p class="mb-0 opacity-75">
Média de <strong>1.2 segundos</strong> por QR code • Grátis • Sem cadastro obrigatório @Localizer["AverageTimePrefix"] <strong>@Localizer["AverageTimeValue"]</strong> @Localizer["AverageTimeSuffix"]
</p> </p>
</div> </div>
</section> </section>
@ -261,27 +269,27 @@
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h5>QR Rapido</h5> <h5>QR Rapido</h5>
<p class="small">O gerador de QR codes mais rápido da web. Grátis, seguro e confiável.</p> <p class="small">@Localizer["FastestQRGeneratorDescription"]</p>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<h6>Links Úteis</h6> <h6>@Localizer["UsefulLinks"]</h6>
<ul class="list-unstyled"> <ul class="list-unstyled">
<li><a href="/Home/Privacy" class="text-light">Privacidade</a></li> <li><a href="/Home/Privacy" class="text-light">@Localizer["Privacy"]</a></li>
<li><a href="/Home/Terms" class="text-light">Termos de Uso</a></li> <li><a href="/Home/Terms" class="text-light">@Localizer["TermsOfUse"]</a></li>
<li><a href="/Premium/Upgrade" class="text-warning">Premium</a></li> <li><a href="/Premium/Upgrade" class="text-warning">Premium</a></li>
</ul> </ul>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<h6>Suporte</h6> <h6>@Localizer["Support"]</h6>
<ul class="list-unstyled"> <ul class="list-unstyled">
<li><a href="mailto:contato@qrrapido.site" class="text-light">Contato</a></li> <li><a href="mailto:contato@qrrapido.site" class="text-light">Contato</a></li>
<li><a href="/Help" class="text-light">Ajuda</a></li> <li><a href="/Help" class="text-light">@Localizer["Help"]</a></li>
</ul> </ul>
</div> </div>
</div> </div>
<hr> <hr>
<div class="text-center"> <div class="text-center">
<small>&copy; 2024 QR Rapido. Todos os direitos reservados.</small> <small>&copy; 2024 QR Rapido. @Localizer["AllRightsReserved"]</small>
</div> </div>
</div> </div>
</footer> </footer>
@ -293,6 +301,40 @@
<script src="~/js/test.js" asp-append-version="true"></script> <script src="~/js/test.js" asp-append-version="true"></script>
<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>
<!-- Fallback inline script for debug -->
<script>
// Fallback inline para garantir funcionamento
document.addEventListener('DOMContentLoaded', function() {
console.log('🔧 Script inline iniciando como fallback...');
const btn = document.getElementById('theme-toggle');
if (btn) {
console.log('✅ Botão encontrado pelo script inline');
btn.onclick = function() {
console.log('🖱️ Clique detectado (inline)');
const html = document.documentElement;
const current = html.getAttribute('data-theme') || 'light';
const newTheme = current === 'light' ? 'dark' : 'light';
html.setAttribute('data-theme', newTheme);
console.log('Theme changed to:', newTheme);
const icon = document.getElementById('theme-icon');
const text = document.getElementById('theme-text');
if (icon) {
icon.className = newTheme === 'dark' ? 'fas fa-moon' : 'fas fa-sun';
}
if (text) {
text.textContent = newTheme === 'dark' ? 'Escuro' : 'Claro';
}
};
console.log('✅ Theme toggle configurado inline!');
} else {
console.error('❌ Botão não encontrado pelo script inline!');
}
});
</script>
@await RenderSectionAsync("Scripts", required: false) @await RenderSectionAsync("Scripts", required: false)
</body> </body>

View File

@ -60,18 +60,7 @@ body {
} }
} }
/* QR Preview Placeholder */ /* QR Preview Placeholder - REMOVIDO: Substituído por versão com melhor contraste */
.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;
}
/* Logo and Branding */ /* Logo and Branding */
.navbar-brand svg { .navbar-brand svg {
@ -155,25 +144,7 @@ body {
animation: slideInRight 0.5s ease-out; animation: slideInRight 0.5s ease-out;
} }
/* Ad Container Styles */ /* Ad Container Styles - REMOVIDO: Substituído por versão com melhor contraste */
.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-free-notice { .ad-free-notice {
text-align: center; text-align: center;
@ -330,6 +301,64 @@ footer a:hover {
background: #0056b3; 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 */ /* Utility Classes */
.text-gradient { .text-gradient {
background: linear-gradient(135deg, var(--qr-primary) 0%, var(--qr-accent) 100%); 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 { .card {
background-color: #2d3748; background-color: #2d3748 !important;
color: #e2e8f0; 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 { .placeholder-qr {
background: #4a5568; background: #4a5568 !important;
border-color: #718096; border-color: #4dabf7 !important;
color: #e2e8f0 !important;
} }
.form-control, .placeholder-qr:hover {
.form-select { background: #2d3748;
background-color: #4a5568; border-color: #63b3ed;
border-color: #718096; }
.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; 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;
}
} }

View File

@ -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);
};