From 127424fc7076ac45679632b6956b7745d0bdccd2 Mon Sep 17 00:00:00 2001 From: Ricardo Carneiro Date: Fri, 3 Apr 2026 20:07:43 -0300 Subject: [PATCH] feat: tema por tenant (cores, gradiente) e categorias SpicyLinks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TenantSettings recebe HeroGradient, PrimaryColor, PrimaryColorDark e DefaultCategories - _Layout injeta CSS custom properties (--tenant-primary, --tenant-gradient) sobrescrevendo Bootstrap - CategoryService usa DefaultCategories do tenant quando configurado - SpicyLinks: gradiente vermelho/rosa, cor primária #e63946, categorias de criadores de conteúdo Co-Authored-By: Claude Sonnet 4.6 --- .../Configuration/TenantSettings.cs | 17 +++++++++++++ src/BCards.Web/Services/CategoryService.cs | 23 ++++++++++++++++- src/BCards.Web/Views/Shared/_Layout.cshtml | 25 ++++++++++++++++++- src/BCards.Web/appsettings.Spicylinks.json | 13 ++++++++++ 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/BCards.Web/Configuration/TenantSettings.cs b/src/BCards.Web/Configuration/TenantSettings.cs index 3f7ae1d..b21da8d 100644 --- a/src/BCards.Web/Configuration/TenantSettings.cs +++ b/src/BCards.Web/Configuration/TenantSettings.cs @@ -29,4 +29,21 @@ public class TenantSettings // SEO / Layout public string MetaKeywords { get; set; } = "cartão digital, página de links, bio links, linktree brasil, página profissional"; public string FooterTagline { get; set; } = "Sua presença online, simplificada."; + + // Branding / Colors + public string HeroGradient { get; set; } = "linear-gradient(135deg, #667eea 0%, #764ba2 100%)"; + public string PrimaryColor { get; set; } = "#0d6efd"; + public string PrimaryColorDark { get; set; } = "#0a58ca"; + + // Category seeding (se vazio, usa os padrões do BCards) + public List DefaultCategories { get; set; } = new(); +} + +public class CategorySeedItem +{ + public string Name { get; set; } = ""; + public string Slug { get; set; } = ""; + public string Icon { get; set; } = ""; + public string Description { get; set; } = ""; + public List SeoKeywords { get; set; } = new(); } diff --git a/src/BCards.Web/Services/CategoryService.cs b/src/BCards.Web/Services/CategoryService.cs index d3207e7..d89de51 100644 --- a/src/BCards.Web/Services/CategoryService.cs +++ b/src/BCards.Web/Services/CategoryService.cs @@ -1,5 +1,7 @@ +using BCards.Web.Configuration; using BCards.Web.Models; using BCards.Web.Repositories; +using Microsoft.Extensions.Options; using System.Text.RegularExpressions; using System.Globalization; using System.Text; @@ -10,10 +12,12 @@ namespace BCards.Web.Services; public class CategoryService : ICategoryService { private readonly ICategoryRepository _categoryRepository; + private readonly TenantSettings _tenant; - public CategoryService(ICategoryRepository categoryRepository) + public CategoryService(ICategoryRepository categoryRepository, IOptions tenantOptions) { _categoryRepository = categoryRepository; + _tenant = tenantOptions.Value; } public async Task> GetAllCategoriesAsync() @@ -57,6 +61,23 @@ public class CategoryService : ICategoryService var categories = await _categoryRepository.GetAllActiveAsync(); if (categories.Any()) return; + // Usa categorias configuradas no tenant se disponíveis + if (_tenant.DefaultCategories.Any()) + { + foreach (var item in _tenant.DefaultCategories) + { + await _categoryRepository.CreateAsync(new Category + { + Name = item.Name, + Slug = string.IsNullOrWhiteSpace(item.Slug) ? GenerateSlug(item.Name) : item.Slug, + Icon = item.Icon, + Description = item.Description, + SeoKeywords = item.SeoKeywords + }); + } + return; + } + var defaultCategories = new[] { new Category diff --git a/src/BCards.Web/Views/Shared/_Layout.cshtml b/src/BCards.Web/Views/Shared/_Layout.cshtml index e31f696..c4e080e 100644 --- a/src/BCards.Web/Views/Shared/_Layout.cshtml +++ b/src/BCards.Web/Views/Shared/_Layout.cshtml @@ -43,7 +43,30 @@ @await RenderSectionAsync("Styles", required: false) - + + +