fix: ajustes gerais
This commit is contained in:
parent
e027026c75
commit
c7ada0119d
3
.claude/settings.local.json
Normal file
3
.claude/settings.local.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"enableAllProjectMcpServers": false
|
||||
}
|
||||
@ -59,6 +59,9 @@ namespace OnlyOneAccessTemplate.Controllers
|
||||
|
||||
protected void SetupSeoViewBag(SiteConfiguration config, string language, string currentUrl)
|
||||
{
|
||||
ViewBag.GoogleAdsPublisher = _configuration.GetValue<string>("GoogleAds:PublisherID");
|
||||
ViewBag.GoogleAdsEnabled = _configuration.GetValue<bool>("GoogleAds:Enabled", true);
|
||||
|
||||
// Basic SEO
|
||||
ViewBag.Language = language;
|
||||
ViewBag.Direction = _languageService.GetLanguageDirection(language);
|
||||
@ -89,6 +92,8 @@ namespace OnlyOneAccessTemplate.Controllers
|
||||
|
||||
protected void SetupContentViewBag(SiteConfiguration config, string language)
|
||||
{
|
||||
ViewBag.GoogleAdsPublisher = _configuration.GetValue<string>("GoogleAds:PublisherID");
|
||||
ViewBag.GoogleAdsEnabled = _configuration.GetValue<bool>("GoogleAds:Enabled", true);
|
||||
// Navigation
|
||||
ViewBag.HomeUrl = language == "pt" ? "/" : $"/{language}";
|
||||
ViewBag.AboutUrl = language == "pt" ? "/about" : $"/{language}/about";
|
||||
|
||||
@ -7,7 +7,7 @@ using OnlyOneAccessTemplate.Models;
|
||||
namespace OnlyOneAccessTemplate.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("converter")] // Adicione esta linha
|
||||
[Route("converter")]
|
||||
public class ConverterController : BaseController
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
31
OnlyOneAccessTemplate/Models/AdsModels.cs
Normal file
31
OnlyOneAccessTemplate/Models/AdsModels.cs
Normal file
@ -0,0 +1,31 @@
|
||||
namespace OnlyOneAccessTemplate.Models
|
||||
{
|
||||
public class AdSettings
|
||||
{
|
||||
public bool Enabled { get; set; } = true;
|
||||
public string PublisherID { get; set; } = "";
|
||||
public bool TestMode { get; set; } = false;
|
||||
public Dictionary<string, string> Slots { get; set; } = new();
|
||||
public AdDisplayRules DisplayRules { get; set; } = new();
|
||||
}
|
||||
|
||||
public class AdDisplayRules
|
||||
{
|
||||
public int MaxAdsPerPage { get; set; } = 7;
|
||||
public int MaxAdsAboveFold { get; set; } = 3;
|
||||
public bool ShowOnMobile { get; set; } = true;
|
||||
public bool AllowStickyAds { get; set; } = true;
|
||||
public List<string> DisabledPositions { get; set; } = new();
|
||||
}
|
||||
|
||||
public class AdPerformanceMetrics
|
||||
{
|
||||
public string Position { get; set; } = "";
|
||||
public int Impressions { get; set; }
|
||||
public int Clicks { get; set; }
|
||||
public double CTR => Impressions > 0 ? (double)Clicks / Impressions * 100 : 0;
|
||||
public decimal Revenue { get; set; }
|
||||
public decimal RPM => Impressions > 0 ? Revenue / Impressions * 1000 : 0;
|
||||
public DateTime LastUpdated { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
104
OnlyOneAccessTemplate/Services/AdsService.cs
Normal file
104
OnlyOneAccessTemplate/Services/AdsService.cs
Normal file
@ -0,0 +1,104 @@
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace OnlyOneAccessTemplate.Services
|
||||
{
|
||||
public class AdsService : IAdsService
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly ILogger<AdsService> _logger;
|
||||
|
||||
public AdsService(IConfiguration configuration, IMemoryCache cache, ILogger<AdsService> logger)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_cache = cache;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public bool IsAdsEnabled()
|
||||
{
|
||||
return _configuration.GetValue<bool>("GoogleAds:Enabled", true);
|
||||
}
|
||||
|
||||
public string GetPublisherID()
|
||||
{
|
||||
return _configuration.GetValue<string>("GoogleAds:PublisherID") ?? "";
|
||||
}
|
||||
|
||||
public AdConfiguration GetAdConfiguration(string adPosition)
|
||||
{
|
||||
var configurations = GetAllAdConfigurations();
|
||||
return configurations.FirstOrDefault(c => c.Position.Equals(adPosition, StringComparison.OrdinalIgnoreCase))
|
||||
?? new AdConfiguration(adPosition, "default-slot", AdSize.Responsive);
|
||||
}
|
||||
|
||||
public string GenerateAdHtml(string position, string adSlot, AdSize size = AdSize.Responsive)
|
||||
{
|
||||
if (!IsAdsEnabled() || string.IsNullOrEmpty(GetPublisherID()))
|
||||
return "";
|
||||
|
||||
var sizeAttributes = GetSizeAttributes(size);
|
||||
var formatAttribute = GetFormatAttribute(size);
|
||||
|
||||
return $@"
|
||||
<ins class=""adsbygoogle""
|
||||
style=""display:block{sizeAttributes.Style}""
|
||||
data-ad-client=""{GetPublisherID()}""
|
||||
data-ad-slot=""{adSlot}""
|
||||
{formatAttribute}
|
||||
{(size == AdSize.Responsive ? "data-full-width-responsive=\"true\"" : "")}></ins>";
|
||||
}
|
||||
|
||||
private List<AdConfiguration> GetAllAdConfigurations()
|
||||
{
|
||||
return _cache.GetOrCreate("ad_configurations", factory =>
|
||||
{
|
||||
factory.SetSlidingExpiration(TimeSpan.FromHours(1));
|
||||
|
||||
return new List<AdConfiguration>
|
||||
{
|
||||
new("banner-top", GetSlotId("BannerTop"), AdSize.Banner_728x90, Priority: 10),
|
||||
new("sidebar-left", GetSlotId("SidebarLeft"), AdSize.Sidebar_300x600, IsSticky: true, ShowOnMobile: false, Priority: 8),
|
||||
new("rectangle-pre-converter", GetSlotId("RectanglePre"), AdSize.Rectangle_300x250, Priority: 9),
|
||||
new("rectangle-post-converter", GetSlotId("RectanglePost"), AdSize.Rectangle_300x250, Priority: 7),
|
||||
new("sidebar-right", GetSlotId("SidebarRight"), AdSize.Sidebar_300x600, IsSticky: true, ShowOnMobile: false, Priority: 6),
|
||||
new("mobile-bottom", GetSlotId("MobileBottom"), AdSize.Mobile_320x50, ShowOnDesktop: false, Priority: 5),
|
||||
new("in-feed", GetSlotId("InFeed"), AdSize.Responsive, Priority: 4),
|
||||
new("multiplex", GetSlotId("Multiplex"), AdSize.Responsive, Priority: 3)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private string GetSlotId(string configKey)
|
||||
{
|
||||
return _configuration.GetValue<string>($"GoogleAds:Slots:{configKey}") ?? "default-slot";
|
||||
}
|
||||
|
||||
private (string Style, string Width, string Height) GetSizeAttributes(AdSize size)
|
||||
{
|
||||
return size switch
|
||||
{
|
||||
AdSize.Banner_728x90 => ("; width: 728px; height: 90px;", "728", "90"),
|
||||
AdSize.Rectangle_300x250 => ("; width: 300px; height: 250px;", "300", "250"),
|
||||
AdSize.Sidebar_160x600 => ("; width: 160px; height: 600px;", "160", "600"),
|
||||
AdSize.Sidebar_300x600 => ("; width: 300px; height: 600px;", "300", "600"),
|
||||
AdSize.Mobile_320x50 => ("; width: 320px; height: 50px;", "320", "50"),
|
||||
AdSize.Square_250x250 => ("; width: 250px; height: 250px;", "250", "250"),
|
||||
_ => ("", "auto", "auto")
|
||||
};
|
||||
}
|
||||
|
||||
private string GetFormatAttribute(AdSize size)
|
||||
{
|
||||
return size switch
|
||||
{
|
||||
AdSize.Responsive => "data-ad-format=\"auto\"",
|
||||
AdSize.Banner_728x90 => "data-ad-format=\"banner\"",
|
||||
AdSize.Rectangle_300x250 => "data-ad-format=\"rectangle\"",
|
||||
AdSize.Sidebar_160x600 or AdSize.Sidebar_300x600 => "data-ad-format=\"vertical\"",
|
||||
AdSize.Square_250x250 => "data-ad-format=\"square\"",
|
||||
_ => "data-ad-format=\"auto\""
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -104,6 +104,36 @@ namespace OnlyOneAccessTemplate.Services
|
||||
Task<List<string>> GetImagesAsync(string folder = "uploads");
|
||||
bool IsValidImageFile(IFormFile file);
|
||||
}
|
||||
|
||||
public interface IAdsService
|
||||
{
|
||||
bool IsAdsEnabled();
|
||||
string GetPublisherID();
|
||||
AdConfiguration GetAdConfiguration(string adPosition);
|
||||
string GenerateAdHtml(string position, string adSlot, AdSize size = AdSize.Responsive);
|
||||
}
|
||||
|
||||
public enum AdSize
|
||||
{
|
||||
Responsive,
|
||||
Banner_728x90,
|
||||
Rectangle_300x250,
|
||||
Sidebar_160x600,
|
||||
Sidebar_300x600,
|
||||
Mobile_320x50,
|
||||
Square_250x250
|
||||
}
|
||||
|
||||
public record AdConfiguration(
|
||||
string Position,
|
||||
string SlotId,
|
||||
AdSize Size,
|
||||
bool IsSticky = false,
|
||||
bool ShowOnMobile = true,
|
||||
bool ShowOnDesktop = true,
|
||||
int Priority = 1
|
||||
);
|
||||
|
||||
// DTOs e Records
|
||||
public record ConversionData(
|
||||
string Language,
|
||||
|
||||
@ -1,242 +1,306 @@
|
||||
@model PageContent;
|
||||
|
||||
@model OnlyOneAccessTemplate.Models.PageContent
|
||||
@{
|
||||
ViewData["Title"] = ViewBag.Title ?? "Conversor Online";
|
||||
Layout = "~/Views/Shared/_Layout.cshtml";
|
||||
}
|
||||
|
||||
<!-- Seção Principal do Conversor -->
|
||||
<section class="converter-hero bg-light py-5">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-10">
|
||||
<!-- Título e Descrição -->
|
||||
<div class="text-center mb-5">
|
||||
<h1 class="display-4 fw-bold text-primary mb-3">
|
||||
@(ViewBag.ConverterTitle ?? "CONVERSOR ONLINE")
|
||||
</h1>
|
||||
<p class="lead text-muted mb-4">
|
||||
@(ViewBag.ConverterDescription ?? "Converta seus arquivos de forma rápida e segura")
|
||||
</p>
|
||||
</div>
|
||||
<!-- Google AdSense - Script Global -->
|
||||
@section Head {
|
||||
@if (ViewBag.GoogleAdsEnabled == true && !string.IsNullOrEmpty(ViewBag.GoogleAdsPublisher))
|
||||
{
|
||||
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=@ViewBag.GoogleAdsPublisher"
|
||||
crossorigin="anonymous"></script>
|
||||
}
|
||||
|
||||
<style>
|
||||
.ad-container { margin: 15px 0; text-align: center; min-height: 50px; }
|
||||
.ad-banner { min-height: 90px; }
|
||||
.ad-rectangle { min-height: 250px; }
|
||||
.ad-sidebar { min-height: 600px; }
|
||||
.ad-sticky { position: sticky; top: 20px; z-index: 100; }
|
||||
.converter-section { background: #f8f9fa; }
|
||||
|
||||
@@media (max-width: 768px) {
|
||||
.ad-sidebar { display: none !important; }
|
||||
.ad-rectangle { min-height: 200px; }
|
||||
.main-content { padding: 0 10px; }
|
||||
}
|
||||
|
||||
@@media (min-width: 1200px) {
|
||||
.ad-sidebar { min-height: 600px; }
|
||||
}
|
||||
</style>
|
||||
}
|
||||
|
||||
<!-- Card do Conversor -->
|
||||
<div class="card shadow-lg border-0 rounded-3">
|
||||
<div class="card-body p-5">
|
||||
<!-- Steps do Processo -->
|
||||
<div class="row text-center mb-4">
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="step-indicator">
|
||||
<span class="badge bg-primary rounded-circle p-3 fs-5 mb-2">1</span>
|
||||
<h6 class="fw-bold">@(ViewBag.Step1Title ?? "Upload")</h6>
|
||||
<small class="text-muted">@(ViewBag.Step1Description ?? "Selecione seu arquivo")</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="step-indicator">
|
||||
<span class="badge bg-primary rounded-circle p-3 fs-5 mb-2">2</span>
|
||||
<h6 class="fw-bold">@(ViewBag.Step2Title ?? "Processar")</h6>
|
||||
<small class="text-muted">@(ViewBag.Step2Description ?? "Aguarde o processamento")</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="step-indicator">
|
||||
<span class="badge bg-success rounded-circle p-3 fs-5 mb-2">3</span>
|
||||
<h6 class="fw-bold">@(ViewBag.Step3Title ?? "Download")</h6>
|
||||
<small class="text-muted">@(ViewBag.Step3Description ?? "Baixe o resultado")</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Banner Superior -->
|
||||
@{
|
||||
ViewBag.AdPosition = "banner-top";
|
||||
ViewBag.AdSlotId = ViewBag.AdSlots?.BannerTop ?? "1234567890";
|
||||
ViewBag.AdFormat = "auto";
|
||||
ViewBag.AdCssClass = "ad-container ad-banner";
|
||||
ViewBag.ShowOnMobile = true;
|
||||
ViewBag.ShowOnDesktop = true;
|
||||
}
|
||||
@await Html.PartialAsync("_AdUnit")
|
||||
|
||||
<!-- Área do Conversor -->
|
||||
<div id="converter-container">
|
||||
@await Html.PartialAsync("_ConverterWidget")
|
||||
</div>
|
||||
|
||||
<!-- Informações Adicionais -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="fas fa-shield-alt text-success me-2"></i>
|
||||
<small class="text-muted">@(ViewBag.SecurityText ?? "Seus dados estão seguros")</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="fas fa-file-alt text-primary me-2"></i>
|
||||
<small class="text-muted">@(ViewBag.FileInfoText ?? "Processamento rápido e seguro")</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Seção de Benefícios -->
|
||||
<section class="benefits-section py-5">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto text-center mb-5">
|
||||
<h2 class="h3 fw-bold mb-3">@(ViewBag.BenefitsTitle ?? "Por Que Usar Nossa Ferramenta?")</h2>
|
||||
<p class="text-muted">@(ViewBag.BenefitsSubtitle ?? "Descubra os benefícios de nossa solução")</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-4">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Sidebar Esquerda com Anúncios -->
|
||||
<div class="col-xl-2 col-lg-2 d-none d-lg-block">
|
||||
@{
|
||||
bool hasFeatureBlocks = false;
|
||||
if (Model != null && Model.Blocks != null)
|
||||
{
|
||||
var featureBlocks = Model.Blocks.Where(b => b.Type == "features").ToList();
|
||||
if (featureBlocks.Any())
|
||||
{
|
||||
hasFeatureBlocks = true;
|
||||
var firstFeatureBlock = featureBlocks.First();
|
||||
if (firstFeatureBlock.Properties != null && firstFeatureBlock.Properties.ContainsKey("feature_list"))
|
||||
{
|
||||
var featureList = firstFeatureBlock.Properties["feature_list"] as System.Collections.IEnumerable;
|
||||
if (featureList != null)
|
||||
{
|
||||
foreach (var featureObj in featureList)
|
||||
{
|
||||
var featureDict = featureObj as Dictionary<string, object>;
|
||||
if (featureDict != null)
|
||||
{
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="text-center p-3">
|
||||
<div class="feature-icon mb-3">
|
||||
<i class="@(featureDict.GetValueOrDefault("icon", "fas fa-star")) fa-2x text-primary"></i>
|
||||
</div>
|
||||
<h6 class="fw-bold">@(featureDict.GetValueOrDefault("title", "Funcionalidade"))</h6>
|
||||
<small class="text-muted">@(featureDict.GetValueOrDefault("description", "Descrição da funcionalidade"))</small>
|
||||
ViewBag.AdPosition = "sidebar-left";
|
||||
ViewBag.AdSlotId = ViewBag.AdSlots?.SidebarLeft ?? "2345678901";
|
||||
ViewBag.AdFormat = "vertical";
|
||||
ViewBag.AdSize = "; width: 300px; height: 600px;";
|
||||
ViewBag.AdCssClass = "ad-container ad-sidebar";
|
||||
ViewBag.IsSticky = true;
|
||||
ViewBag.ShowOnMobile = false;
|
||||
ViewBag.ShowOnDesktop = true;
|
||||
}
|
||||
@await Html.PartialAsync("_AdUnit")
|
||||
</div>
|
||||
|
||||
<!-- Conteúdo Principal -->
|
||||
<div class="col-xl-8 col-lg-8 col-md-12 main-content">
|
||||
<!-- Seção Principal do Conversor -->
|
||||
<section class="converter-section py-4">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-11">
|
||||
<!-- Título e Descrição -->
|
||||
<div class="text-center mb-4">
|
||||
<h1 class="display-4 fw-bold text-primary mb-3">
|
||||
@(ViewBag.ConverterTitle ?? "CONVERSOR ONLINE")
|
||||
</h1>
|
||||
<p class="lead text-muted mb-4">
|
||||
@(ViewBag.ConverterDescription ?? "Converta seus arquivos de forma rápida e segura")
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Anúncio Retangular Antes do Conversor -->
|
||||
@{
|
||||
ViewBag.AdPosition = "rectangle-pre-converter";
|
||||
ViewBag.AdSlotId = ViewBag.AdSlots?.RectanglePre ?? "3456789012";
|
||||
ViewBag.AdFormat = "rectangle";
|
||||
ViewBag.AdSize = "; width: 300px; height: 250px;";
|
||||
ViewBag.AdCssClass = "ad-container ad-rectangle mb-4";
|
||||
ViewBag.IsSticky = false;
|
||||
ViewBag.ShowOnMobile = true;
|
||||
ViewBag.ShowOnDesktop = true;
|
||||
}
|
||||
@await Html.PartialAsync("_AdUnit")
|
||||
|
||||
<!-- Card do Conversor -->
|
||||
<div class="card shadow-lg border-0 rounded-3">
|
||||
<div class="card-body p-4">
|
||||
<!-- Steps do Processo -->
|
||||
<div class="row text-center mb-4">
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="step-indicator">
|
||||
<span class="badge bg-primary rounded-circle p-3 fs-5 mb-2">1</span>
|
||||
<h6 class="fw-bold">@(ViewBag.Step1Title ?? "Upload")</h6>
|
||||
<small class="text-muted">@(ViewBag.Step1Description ?? "Selecione seu arquivo")</small>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="step-indicator">
|
||||
<span class="badge bg-primary rounded-circle p-3 fs-5 mb-2">2</span>
|
||||
<h6 class="fw-bold">@(ViewBag.Step2Title ?? "Processar")</h6>
|
||||
<small class="text-muted">@(ViewBag.Step2Description ?? "Aguarde o processamento")</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="step-indicator">
|
||||
<span class="badge bg-success rounded-circle p-3 fs-5 mb-2">3</span>
|
||||
<h6 class="fw-bold">@(ViewBag.Step3Title ?? "Download")</h6>
|
||||
<small class="text-muted">@(ViewBag.Step3Description ?? "Baixe o resultado")</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Área do Conversor -->
|
||||
<div id="converter-container">
|
||||
@await Html.PartialAsync("_ConverterWidget")
|
||||
</div>
|
||||
|
||||
<!-- Informações Adicionais -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="fas fa-shield-alt text-success me-2"></i>
|
||||
<small class="text-muted">@(ViewBag.SecurityText ?? "Seus dados estão seguros")</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="fas fa-file-alt text-primary me-2"></i>
|
||||
<small class="text-muted">@(ViewBag.FileInfoText ?? "Processamento rápido e seguro")</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Anúncio Retangular Após o Conversor -->
|
||||
@{
|
||||
ViewBag.AdPosition = "rectangle-post-converter";
|
||||
ViewBag.AdSlotId = ViewBag.AdSlots?.RectanglePost ?? "4567890123";
|
||||
ViewBag.AdFormat = "rectangle";
|
||||
ViewBag.AdSize = "; width: 300px; height: 250px;";
|
||||
ViewBag.AdCssClass = "ad-container ad-rectangle mt-4";
|
||||
ViewBag.IsSticky = false;
|
||||
ViewBag.ShowOnMobile = true;
|
||||
ViewBag.ShowOnDesktop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@await Html.PartialAsync("_AdUnit")
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Anúncio In-Feed Entre Seções -->
|
||||
@{
|
||||
ViewBag.AdPosition = "in-feed";
|
||||
ViewBag.AdSlotId = ViewBag.AdSlots?.InFeed ?? "5678901234";
|
||||
ViewBag.AdFormat = "fluid";
|
||||
ViewBag.AdCssClass = "ad-container";
|
||||
ViewBag.IsSticky = false;
|
||||
ViewBag.ShowOnMobile = true;
|
||||
ViewBag.ShowOnDesktop = true;
|
||||
}
|
||||
@await Html.PartialAsync("_AdUnit")
|
||||
|
||||
<!-- Seção de Benefícios -->
|
||||
<section class="benefits-section py-5">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-10 mx-auto text-center mb-5">
|
||||
<h2 class="h3 fw-bold mb-3">@(ViewBag.BenefitsTitle ?? "Por Que Usar Nossa Ferramenta?")</h2>
|
||||
<p class="text-muted">@(ViewBag.BenefitsSubtitle ?? "Descubra os benefícios de nossa solução")</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4 justify-content-center">
|
||||
<!-- Features (código existente) -->
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="text-center p-3">
|
||||
<div class="feature-icon mb-3">
|
||||
<i class="fas fa-rocket fa-2x text-primary"></i>
|
||||
</div>
|
||||
<h6 class="fw-bold">@(ViewBag.Feature1Title ?? "Rápido e Fácil")</h6>
|
||||
<small class="text-muted">@(ViewBag.Feature1Description ?? "Conversão instantânea")</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="text-center p-3">
|
||||
<div class="feature-icon mb-3">
|
||||
<i class="fas fa-shield-alt fa-2x text-primary"></i>
|
||||
</div>
|
||||
<h6 class="fw-bold">@(ViewBag.Feature2Title ?? "Seguro")</h6>
|
||||
<small class="text-muted">@(ViewBag.Feature2Description ?? "Dados protegidos")</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="text-center p-3">
|
||||
<div class="feature-icon mb-3">
|
||||
<i class="fas fa-users fa-2x text-primary"></i>
|
||||
</div>
|
||||
<h6 class="fw-bold">@(ViewBag.Feature3Title ?? "Confiável")</h6>
|
||||
<small class="text-muted">@(ViewBag.Feature3Description ?? "Resultados precisos")</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="text-center p-3">
|
||||
<div class="feature-icon mb-3">
|
||||
<i class="fas fa-clock fa-2x text-primary"></i>
|
||||
</div>
|
||||
<h6 class="fw-bold">Rápido</h6>
|
||||
<small class="text-muted">Conversão em segundos</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Anúncio Multiplex -->
|
||||
@{
|
||||
ViewBag.AdPosition = "multiplex";
|
||||
ViewBag.AdSlotId = ViewBag.AdSlots?.Multiplex ?? "6789012345";
|
||||
ViewBag.AdFormat = "autorelaxed";
|
||||
ViewBag.AdCssClass = "ad-container";
|
||||
ViewBag.IsSticky = false;
|
||||
ViewBag.ShowOnMobile = true;
|
||||
ViewBag.ShowOnDesktop = true;
|
||||
}
|
||||
@await Html.PartialAsync("_AdUnit")
|
||||
|
||||
<!-- Seção CTA Final -->
|
||||
<section class="final-cta py-5">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto text-center">
|
||||
<h2 class="h3 fw-bold mb-3">@(ViewBag.FinalCtaTitle ?? "Pronto para Converter?")</h2>
|
||||
<p class="text-muted mb-4">@(ViewBag.FinalCtaSubtitle ?? "Use nossa ferramenta gratuita agora mesmo")</p>
|
||||
<a href="#converter-container" class="btn btn-primary btn-lg">
|
||||
@(ViewBag.FinalCtaButtonText ?? "Começar Conversão")
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar Direita com Anúncios -->
|
||||
<div class="col-xl-2 col-lg-2 d-none d-lg-block">
|
||||
@{
|
||||
ViewBag.AdPosition = "sidebar-right";
|
||||
ViewBag.AdSlotId = ViewBag.AdSlots?.SidebarRight ?? "7890123456";
|
||||
ViewBag.AdFormat = "vertical";
|
||||
ViewBag.AdSize = "; width: 300px; height: 600px;";
|
||||
ViewBag.AdCssClass = "ad-container ad-sidebar";
|
||||
ViewBag.IsSticky = true;
|
||||
ViewBag.ShowOnMobile = false;
|
||||
ViewBag.ShowOnDesktop = true;
|
||||
}
|
||||
@await Html.PartialAsync("_AdUnit")
|
||||
|
||||
<!-- Anúncio Quadrado Adicional na Sidebar -->
|
||||
<div class="mt-4">
|
||||
@{
|
||||
ViewBag.AdPosition = "sidebar-square";
|
||||
ViewBag.AdSlotId = ViewBag.AdSlots?.SidebarSquare ?? "8901234567";
|
||||
ViewBag.AdFormat = "square";
|
||||
ViewBag.AdSize = "; width: 250px; height: 250px;";
|
||||
ViewBag.AdCssClass = "ad-container";
|
||||
ViewBag.IsSticky = false;
|
||||
ViewBag.ShowOnMobile = false;
|
||||
ViewBag.ShowOnDesktop = true;
|
||||
}
|
||||
}
|
||||
|
||||
@if (!hasFeatureBlocks)
|
||||
{
|
||||
<!-- Features padrão se não houver dados do modelo -->
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="text-center p-3">
|
||||
<div class="feature-icon mb-3">
|
||||
<i class="fas fa-rocket fa-2x text-primary"></i>
|
||||
</div>
|
||||
<h6 class="fw-bold">@(ViewBag.Feature1Title ?? "Rápido e Fácil")</h6>
|
||||
<small class="text-muted">@(ViewBag.Feature1Description ?? "Conversão instantânea")</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="text-center p-3">
|
||||
<div class="feature-icon mb-3">
|
||||
<i class="fas fa-shield-alt fa-2x text-primary"></i>
|
||||
</div>
|
||||
<h6 class="fw-bold">@(ViewBag.Feature2Title ?? "Seguro")</h6>
|
||||
<small class="text-muted">@(ViewBag.Feature2Description ?? "Dados protegidos")</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="text-center p-3">
|
||||
<div class="feature-icon mb-3">
|
||||
<i class="fas fa-users fa-2x text-primary"></i>
|
||||
</div>
|
||||
<h6 class="fw-bold">@(ViewBag.Feature3Title ?? "Confiável")</h6>
|
||||
<small class="text-muted">@(ViewBag.Feature3Description ?? "Resultados precisos")</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="text-center p-3">
|
||||
<div class="feature-icon mb-3">
|
||||
<i class="fas fa-clock fa-2x text-primary"></i>
|
||||
</div>
|
||||
<h6 class="fw-bold">Rápido</h6>
|
||||
<small class="text-muted">Conversão em segundos</small>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@await Html.PartialAsync("_AdUnit")
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Seção de Depoimentos (Opcional) -->
|
||||
<!-- Banner Inferior Mobile -->
|
||||
@{
|
||||
bool hasTestimonialBlocks = false;
|
||||
if (Model != null && Model.Blocks != null)
|
||||
{
|
||||
var testimonialBlocks = Model.Blocks.Where(b => b.Type == "testimonials").ToList();
|
||||
if (testimonialBlocks.Any())
|
||||
{
|
||||
hasTestimonialBlocks = true;
|
||||
}
|
||||
}
|
||||
ViewBag.AdPosition = "mobile-bottom";
|
||||
ViewBag.AdSlotId = ViewBag.AdSlots?.MobileBottom ?? "9012345678";
|
||||
ViewBag.AdFormat = "banner";
|
||||
ViewBag.AdSize = "; width: 320px; height: 50px;";
|
||||
ViewBag.AdCssClass = "fixed-bottom d-block d-md-none";
|
||||
ViewBag.IsSticky = false;
|
||||
ViewBag.ShowOnMobile = true;
|
||||
ViewBag.ShowOnDesktop = false;
|
||||
}
|
||||
|
||||
@if (hasTestimonialBlocks)
|
||||
{
|
||||
<section class="testimonials-section py-5 bg-light">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto text-center mb-5">
|
||||
<h2 class="h3 fw-bold mb-3">@(ViewBag.DefaultTestimonialsTitle ?? "O Que Nossos Clientes Dizem")</h2>
|
||||
<p class="text-muted">@(ViewBag.TestimonialsCount ?? "Avaliações positivas")</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card border-0 h-100">
|
||||
<div class="card-body text-center">
|
||||
<p class="mb-3">"@(ViewBag.Testimonial1Quote ?? "Excelente ferramenta!")"</p>
|
||||
<h6 class="fw-bold">@(ViewBag.Testimonial1Name ?? "Cliente Satisfeito")</h6>
|
||||
<small class="text-muted">@(ViewBag.Testimonial1Position ?? "Usuário")</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card border-0 h-100">
|
||||
<div class="card-body text-center">
|
||||
<p class="mb-3">"@(ViewBag.Testimonial2Quote ?? "Muito útil e fácil de usar!")"</p>
|
||||
<h6 class="fw-bold">@(ViewBag.Testimonial2Name ?? "Outro Cliente")</h6>
|
||||
<small class="text-muted">@(ViewBag.Testimonial2Position ?? "Usuário")</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card border-0 h-100">
|
||||
<div class="card-body text-center">
|
||||
<p class="mb-3">"@(ViewBag.Testimonial3Quote ?? "Recomendo para todos!")"</p>
|
||||
<h6 class="fw-bold">@(ViewBag.Testimonial3Name ?? "Mais um Cliente")</h6>
|
||||
<small class="text-muted">@(ViewBag.Testimonial3Position ?? "Usuário")</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
|
||||
<!-- Seção CTA Final -->
|
||||
<section class="final-cta py-5">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto text-center">
|
||||
<h2 class="h3 fw-bold mb-3">@(ViewBag.FinalCtaTitle ?? "Pronto para Converter?")</h2>
|
||||
<p class="text-muted mb-4">@(ViewBag.FinalCtaSubtitle ?? "Use nossa ferramenta gratuita agora mesmo")</p>
|
||||
<a href="#converter-container" class="btn btn-primary btn-lg">
|
||||
@(ViewBag.FinalCtaButtonText ?? "Começar Conversão")
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="@ViewBag.AdCssClass bg-white border-top p-2" style="z-index: 1050;" id="mobile-bottom-ad">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
@await Html.PartialAsync("_AdUnit")
|
||||
<button type="button" class="btn-close ms-2" onclick="document.getElementById('mobile-bottom-ad').style.display='none'"></button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Scripts específicos do conversor -->
|
||||
<!-- Scripts específicos -->
|
||||
@section Scripts {
|
||||
<script src="~/js/converter.js"></script>
|
||||
@{
|
||||
@ -244,12 +308,52 @@
|
||||
var jsFileName = $"~/js/converters/{converterType.ToString().ToLower()}-converter.js";
|
||||
}
|
||||
<script src="@jsFileName"></script>
|
||||
|
||||
<!-- Inicialização dos Anúncios -->
|
||||
<script>
|
||||
// Inicializar conversor específico
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Inicializar conversor
|
||||
if (typeof initializeConverter === 'function') {
|
||||
initializeConverter();
|
||||
}
|
||||
|
||||
// Inicializar anúncios do Google
|
||||
@if (ViewBag.GoogleAdsEnabled == true)
|
||||
{
|
||||
@Html.Raw("initializeGoogleAds();")
|
||||
}
|
||||
});
|
||||
|
||||
function initializeGoogleAds() {
|
||||
try {
|
||||
// Encontrar todos os anúncios na página
|
||||
const adElements = document.querySelectorAll('.adsbygoogle');
|
||||
|
||||
// Inicializar cada anúncio
|
||||
adElements.forEach(ad => {
|
||||
if (!ad.dataset.adsbygoogleStatus) {
|
||||
(adsbygoogle = window.adsbygoogle || []).push({});
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`Initialized ${adElements.length} ad units`);
|
||||
} catch (e) {
|
||||
console.log('AdSense initialization error:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh anúncios após conversão bem-sucedida
|
||||
function refreshAdsAfterConversion() {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const adElements = document.querySelectorAll('.adsbygoogle[data-ad-position="rectangle-post-converter"]');
|
||||
adElements.forEach(ad => {
|
||||
(adsbygoogle = window.adsbygoogle || []).push({});
|
||||
});
|
||||
} catch (e) {
|
||||
console.log('Ad refresh error:', e);
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
</script>
|
||||
}
|
||||
43
OnlyOneAccessTemplate/Views/Shared/_AdUnit.cshtml
Normal file
43
OnlyOneAccessTemplate/Views/Shared/_AdUnit.cshtml
Normal file
@ -0,0 +1,43 @@
|
||||
@* Views/Shared/_AdUnit.cshtml *@
|
||||
@{
|
||||
var position = ViewBag.AdPosition?.ToString() ?? "default";
|
||||
var slotId = ViewBag.AdSlotId?.ToString() ?? "default-slot";
|
||||
var adFormat = ViewBag.AdFormat?.ToString() ?? "auto";
|
||||
var adSize = ViewBag.AdSize?.ToString() ?? "";
|
||||
var publisherId = ViewBag.GoogleAdsPublisher?.ToString() ?? "pub-3475956393038764";
|
||||
var isEnabled = ViewBag.GoogleAdsEnabled ?? true;
|
||||
var cssClass = ViewBag.AdCssClass?.ToString() ?? "ad-container";
|
||||
var isSticky = ViewBag.IsSticky ?? false;
|
||||
var showOnMobile = ViewBag.ShowOnMobile ?? true;
|
||||
var showOnDesktop = ViewBag.ShowOnDesktop ?? true;
|
||||
}
|
||||
|
||||
@if (isEnabled && !string.IsNullOrEmpty(publisherId) && publisherId != "pub-3475956393038764")
|
||||
{
|
||||
<div class="@cssClass @(isSticky ? "ad-sticky" : "") @(!showOnMobile ? "d-none d-md-block" : "") @(!showOnDesktop ? "d-block d-md-none" : "")"
|
||||
data-ad-position="@position">
|
||||
|
||||
<ins class="adsbygoogle"
|
||||
style="display:block@(adSize)"
|
||||
data-ad-client="@publisherId"
|
||||
data-ad-slot="@slotId"
|
||||
data-ad-format="@adFormat"
|
||||
@if (adFormat == "auto")
|
||||
{
|
||||
@Html.Raw("data-full-width-responsive=\"true\"")
|
||||
}></ins>
|
||||
|
||||
@if (ViewBag.ShowAdLabel == true)
|
||||
{
|
||||
<small class="text-muted d-block text-center mt-1" style="font-size: 10px;">Publicidade</small>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else if (ViewBag.ShowPlaceholder == true)
|
||||
{
|
||||
<!-- Placeholder para desenvolvimento -->
|
||||
<div class="@cssClass bg-light border rounded d-flex align-items-center justify-content-center"
|
||||
style="min-height: 90px; color: #6c757d;">
|
||||
<small>Anúncio: @position</small>
|
||||
</div>
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
<header class="navbar navbar-expand-lg navbar-light bg-white shadow-sm sticky-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="@ViewBag.HomeUrl">
|
||||
<img src="@ViewBag.LogoUrl" alt="@ViewBag.SiteName" height="40" class="me-2">
|
||||
<img src="@ViewBag.LogoUrl" alt="?" height="40" class="me-2">
|
||||
<span class="fw-bold text-primary">@ViewBag.SiteName</span>
|
||||
</a>
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Exemplo 1: Conversor de Maiúsculas/Minúsculas
|
||||
"Converter": {
|
||||
"Type": "text-case-sentence",
|
||||
"Name": "Conversor de Maiúsculas e Minúsculas"
|
||||
"Name": "Maiúsculas para 1a. minúsculas"
|
||||
},
|
||||
|
||||
// Exemplo 2: Conversor CSV para JSON
|
||||
@ -27,7 +27,7 @@
|
||||
|
||||
"SEO": {
|
||||
"DefaultDomain": "https://maiusculasminusculas.com",
|
||||
"DefaultSiteName": "Conversor de Maiúsculas e Minúsculas Online",
|
||||
"DefaultSiteName": "Maiúsculas para 1a. minúsculas online",
|
||||
"GoogleTagManagerId": "GTM-XXXXXXX",
|
||||
"GoogleAnalyticsId": "GA-XXXXXXXX"
|
||||
},
|
||||
@ -38,6 +38,14 @@
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
|
||||
"GoogleAds": {
|
||||
"PublisherID": "pub-3475956393038764",
|
||||
"Enabled": true,
|
||||
"TestMode": false,
|
||||
"Slots": {
|
||||
"BannerTop": "SEU_SLOT_ID_1",
|
||||
"RectanglePre": "SEU_SLOT_ID_2"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user