feat: remover createpage
All checks were successful
BCards Multi-Tenant Deployment Pipeline / Run Tests (push) Successful in 9s
BCards Multi-Tenant Deployment Pipeline / PR Validation (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Build and Push Image (push) Successful in 7m44s
BCards Multi-Tenant Deployment Pipeline / Deploy bcards.site (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Deploy spicylinks.site (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Deploy luzlinks.site (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Deploy to Release Swarm (ARM) (push) Successful in 16s
BCards Multi-Tenant Deployment Pipeline / Cleanup Old Resources (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Deployment Summary (push) Successful in 0s
All checks were successful
BCards Multi-Tenant Deployment Pipeline / Run Tests (push) Successful in 9s
BCards Multi-Tenant Deployment Pipeline / PR Validation (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Build and Push Image (push) Successful in 7m44s
BCards Multi-Tenant Deployment Pipeline / Deploy bcards.site (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Deploy spicylinks.site (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Deploy luzlinks.site (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Deploy to Release Swarm (ARM) (push) Successful in 16s
BCards Multi-Tenant Deployment Pipeline / Cleanup Old Resources (push) Has been skipped
BCards Multi-Tenant Deployment Pipeline / Deployment Summary (push) Successful in 0s
This commit is contained in:
parent
cff7962cc5
commit
acb5bbf74b
@ -53,7 +53,9 @@
|
|||||||
"Bash(git log:*)",
|
"Bash(git log:*)",
|
||||||
"Bash(git mv:*)",
|
"Bash(git mv:*)",
|
||||||
"Bash(python3 -c \"import sys,json; [print\\(json.loads\\(l\\).get\\('MessageTemplate',''\\) + ' ' + str\\(json.loads\\(l\\).get\\('Level',''\\)\\)\\) for l in sys.stdin if 'categ' in l.lower\\(\\) or 'Error' in l or 'error' in l.lower\\(\\)]\")",
|
"Bash(python3 -c \"import sys,json; [print\\(json.loads\\(l\\).get\\('MessageTemplate',''\\) + ' ' + str\\(json.loads\\(l\\).get\\('Level',''\\)\\)\\) for l in sys.stdin if 'categ' in l.lower\\(\\) or 'Error' in l or 'error' in l.lower\\(\\)]\")",
|
||||||
"Bash(python3 -c \" import sys, json for line in sys.stdin: line = line.strip\\(\\).rstrip\\(','\\) try: obj = json.loads\\(line\\) lvl = obj.get\\('Level',''\\) msg = obj.get\\('MessageTemplate',''\\) or obj.get\\('message',''\\) if lvl in \\('Error','Warning','Fatal'\\) or 'categ' in msg.lower\\(\\) or 'initial' in msg.lower\\(\\): print\\(f'[{lvl}] {msg}'\\) except: pass \")"
|
"Bash(python3 -c \" import sys, json for line in sys.stdin: line = line.strip\\(\\).rstrip\\(','\\) try: obj = json.loads\\(line\\) lvl = obj.get\\('Level',''\\) msg = obj.get\\('MessageTemplate',''\\) or obj.get\\('message',''\\) if lvl in \\('Error','Warning','Fatal'\\) or 'categ' in msg.lower\\(\\) or 'initial' in msg.lower\\(\\): print\\(f'[{lvl}] {msg}'\\) except: pass \")",
|
||||||
|
"Bash(grep -E \"\\\\.\\(cs|csproj\\)$\")",
|
||||||
|
"Bash(git -C /c/vscode/bcards log --oneline --follow src/BCards.Web/Views/Admin/CreatePage.cshtml)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"enableAllProjectMcpServers": false
|
"enableAllProjectMcpServers": false
|
||||||
|
|||||||
@ -482,185 +482,10 @@ public class AdminController : Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
[Route("CreatePage")]
|
[Route("CreatePage")]
|
||||||
public async Task<IActionResult> CreatePage(CreatePageViewModel model)
|
public IActionResult CreatePage()
|
||||||
{
|
{
|
||||||
var user = await _authService.GetCurrentUserAsync(User);
|
return RedirectToAction("ManagePage", new { id = "new" });
|
||||||
if (user == null)
|
|
||||||
return RedirectToAction("Login", "Auth");
|
|
||||||
|
|
||||||
// Check if user already has a page
|
|
||||||
var existingPage = await _userPageService.GetUserPageAsync(user.Id);
|
|
||||||
if (existingPage != null)
|
|
||||||
return RedirectToAction("EditPage");
|
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
{
|
|
||||||
var categories = await _categoryService.GetAllCategoriesAsync();
|
|
||||||
var themes = await _themeService.GetAvailableThemesAsync();
|
|
||||||
ViewBag.Categories = categories;
|
|
||||||
ViewBag.Themes = themes;
|
|
||||||
return View(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate slug if not provided
|
|
||||||
if (string.IsNullOrEmpty(model.Slug))
|
|
||||||
{
|
|
||||||
model.Slug = await _userPageService.GenerateSlugAsync(model.Category, model.DisplayName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if slug is available
|
|
||||||
if (!await _userPageService.ValidateSlugAsync(model.Category, model.Slug))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("Slug", "Esta URL já está em uso. Tente outra.");
|
|
||||||
var categories = await _categoryService.GetAllCategoriesAsync();
|
|
||||||
var themes = await _themeService.GetAvailableThemesAsync();
|
|
||||||
ViewBag.Categories = categories;
|
|
||||||
ViewBag.Themes = themes;
|
|
||||||
return View(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user can create the requested number of links
|
|
||||||
var activeLinksCount = model.Links?.Count ?? 0;
|
|
||||||
if (!await _userPageService.CanCreateLinksAsync(user.Id, activeLinksCount))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("", "Você excedeu o limite de links do seu plano atual.");
|
|
||||||
var categories = await _categoryService.GetAllCategoriesAsync();
|
|
||||||
var themes = await _themeService.GetAvailableThemesAsync();
|
|
||||||
ViewBag.Categories = categories;
|
|
||||||
ViewBag.Themes = themes;
|
|
||||||
return View(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert ViewModel to UserPage
|
|
||||||
var userPage = new UserPage
|
|
||||||
{
|
|
||||||
UserId = user.Id,
|
|
||||||
DisplayName = model.DisplayName,
|
|
||||||
Category = model.Category,
|
|
||||||
BusinessType = model.BusinessType,
|
|
||||||
Bio = model.Bio,
|
|
||||||
Slug = model.Slug,
|
|
||||||
Theme = await _themeService.GetThemeByNameAsync(model.SelectedTheme) ?? _themeService.GetDefaultTheme(),
|
|
||||||
Links = model.Links?.Select(l => new LinkItem
|
|
||||||
{
|
|
||||||
Title = l.Title,
|
|
||||||
Url = l.Url,
|
|
||||||
Description = l.Description,
|
|
||||||
Icon = l.Icon,
|
|
||||||
IsActive = true,
|
|
||||||
Order = model.Links.IndexOf(l)
|
|
||||||
}).ToList() ?? new List<LinkItem>()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add social media links
|
|
||||||
var socialLinks = new List<LinkItem>();
|
|
||||||
if (!string.IsNullOrEmpty(model.WhatsAppNumber))
|
|
||||||
{
|
|
||||||
var whatsappDigits = model.WhatsAppNumber
|
|
||||||
.Replace("https://wa.me/", "").Replace("whatsapp://", "")
|
|
||||||
.Replace("+", "").Replace(" ", "").Replace("-", "").Replace("(", "").Replace(")", "");
|
|
||||||
socialLinks.Add(new LinkItem
|
|
||||||
{
|
|
||||||
Title = "WhatsApp",
|
|
||||||
Url = $"https://wa.me/{whatsappDigits}",
|
|
||||||
Icon = "fab fa-whatsapp",
|
|
||||||
IsActive = true,
|
|
||||||
Order = userPage.Links.Count + socialLinks.Count
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(model.FacebookUrl))
|
|
||||||
{
|
|
||||||
socialLinks.Add(new LinkItem
|
|
||||||
{
|
|
||||||
Title = "Facebook",
|
|
||||||
Url = model.FacebookUrl,
|
|
||||||
Icon = "fab fa-facebook",
|
|
||||||
IsActive = true,
|
|
||||||
Order = userPage.Links.Count + socialLinks.Count
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(model.TwitterUrl))
|
|
||||||
{
|
|
||||||
socialLinks.Add(new LinkItem
|
|
||||||
{
|
|
||||||
Title = "X / Twitter",
|
|
||||||
Url = model.TwitterUrl,
|
|
||||||
Icon = "fab fa-x-twitter",
|
|
||||||
IsActive = true,
|
|
||||||
Order = userPage.Links.Count + socialLinks.Count
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(model.InstagramUrl))
|
|
||||||
{
|
|
||||||
socialLinks.Add(new LinkItem
|
|
||||||
{
|
|
||||||
Title = "Instagram",
|
|
||||||
Url = model.InstagramUrl,
|
|
||||||
Icon = "fab fa-instagram",
|
|
||||||
IsActive = true,
|
|
||||||
Order = userPage.Links.Count + socialLinks.Count
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(model.TiktokUrl))
|
|
||||||
{
|
|
||||||
socialLinks.Add(new LinkItem
|
|
||||||
{
|
|
||||||
Title = "TikTok",
|
|
||||||
Url = model.TiktokUrl,
|
|
||||||
Icon = "fab fa-tiktok",
|
|
||||||
IsActive = true,
|
|
||||||
Order = userPage.Links.Count + socialLinks.Count
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(model.PinterestUrl))
|
|
||||||
{
|
|
||||||
socialLinks.Add(new LinkItem
|
|
||||||
{
|
|
||||||
Title = "Pinterest",
|
|
||||||
Url = model.PinterestUrl,
|
|
||||||
Icon = "fab fa-pinterest",
|
|
||||||
IsActive = true,
|
|
||||||
Order = userPage.Links.Count + socialLinks.Count
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(model.DiscordUrl))
|
|
||||||
{
|
|
||||||
socialLinks.Add(new LinkItem
|
|
||||||
{
|
|
||||||
Title = "Discord",
|
|
||||||
Url = model.DiscordUrl,
|
|
||||||
Icon = "fab fa-discord",
|
|
||||||
IsActive = true,
|
|
||||||
Order = userPage.Links.Count + socialLinks.Count
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(model.KawaiUrl))
|
|
||||||
{
|
|
||||||
socialLinks.Add(new LinkItem
|
|
||||||
{
|
|
||||||
Title = "Kawai",
|
|
||||||
Url = model.KawaiUrl,
|
|
||||||
Icon = "fas fa-heart",
|
|
||||||
IsActive = true,
|
|
||||||
Order = userPage.Links.Count + socialLinks.Count
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
userPage.Links.AddRange(socialLinks);
|
|
||||||
|
|
||||||
await _userPageService.CreatePageAsync(userPage);
|
|
||||||
|
|
||||||
TempData["Success"] = "Página criada com sucesso!";
|
|
||||||
return RedirectToAction("Dashboard");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
|||||||
@ -1,58 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
|
|
||||||
namespace BCards.Web.ViewModels;
|
|
||||||
|
|
||||||
public class CreatePageViewModel
|
|
||||||
{
|
|
||||||
[Required(ErrorMessage = "Nome é obrigatório")]
|
|
||||||
[StringLength(50, ErrorMessage = "Nome deve ter no máximo 50 caracteres")]
|
|
||||||
public string DisplayName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[Required(ErrorMessage = "Categoria é obrigatória")]
|
|
||||||
public string Category { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[Required(ErrorMessage = "Tipo de negócio é obrigatório")]
|
|
||||||
public string BusinessType { get; set; } = "individual";
|
|
||||||
|
|
||||||
[StringLength(3000, ErrorMessage = "Bio deve ter no máximo 3000 caracteres")]
|
|
||||||
public string Bio { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[Required(ErrorMessage = "Tema é obrigatório")]
|
|
||||||
public string SelectedTheme { get; set; } = "minimalist";
|
|
||||||
|
|
||||||
public string WhatsAppNumber { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string FacebookUrl { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string TwitterUrl { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string InstagramUrl { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string TiktokUrl { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string PinterestUrl { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string DiscordUrl { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string KawaiUrl { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public List<CreateLinkViewModel> Links { get; set; } = new();
|
|
||||||
|
|
||||||
public string Slug { get; set; } = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CreateLinkViewModel
|
|
||||||
{
|
|
||||||
[Required(ErrorMessage = "Título é obrigatório")]
|
|
||||||
[StringLength(50, ErrorMessage = "Título deve ter no máximo 50 caracteres")]
|
|
||||||
public string Title { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[Required(ErrorMessage = "URL é obrigatória")]
|
|
||||||
[Url(ErrorMessage = "URL inválida")]
|
|
||||||
public string Url { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[StringLength(100, ErrorMessage = "Descrição deve ter no máximo 100 caracteres")]
|
|
||||||
public string Description { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string Icon { get; set; } = string.Empty;
|
|
||||||
}
|
|
||||||
@ -1,672 +0,0 @@
|
|||||||
@model BCards.Web.ViewModels.CreatePageViewModel
|
|
||||||
@{
|
|
||||||
ViewData["Title"] = "Criar Página";
|
|
||||||
Layout = "_Layout";
|
|
||||||
}
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12 col-lg-8 mx-auto">
|
|
||||||
<div class="card shadow-sm">
|
|
||||||
<div class="card-header bg-primary text-white">
|
|
||||||
<h4 class="mb-0">
|
|
||||||
<i class="fas fa-magic"></i>
|
|
||||||
Criar Sua Página de Links
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-body">
|
|
||||||
<!-- Progress Bar -->
|
|
||||||
<div class="progress mb-4" style="height: 8px;">
|
|
||||||
<div class="progress-bar" role="progressbar" style="width: 20%" id="wizardProgress"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form asp-action="CreatePage" method="post" id="createPageForm">
|
|
||||||
|
|
||||||
<!-- Step 1: Informações Básicas -->
|
|
||||||
<div class="wizard-step" id="step1">
|
|
||||||
<h5 class="step-title">
|
|
||||||
<span class="step-number">1</span>
|
|
||||||
Informações Básicas
|
|
||||||
</h5>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label asp-for="DisplayName" class="form-label">Nome da Página</label>
|
|
||||||
<input asp-for="DisplayName" class="form-control" placeholder="Ex: João Silva">
|
|
||||||
<span asp-validation-for="DisplayName" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label asp-for="Category" class="form-label">Categoria</label>
|
|
||||||
<select asp-for="Category" class="form-select">
|
|
||||||
<option value="">Selecione uma categoria</option>
|
|
||||||
@foreach (var category in ViewBag.Categories as List<BCards.Web.Models.Category> ?? new List<BCards.Web.Models.Category>())
|
|
||||||
{
|
|
||||||
<option value="@category.Name">@category.Name</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
<span asp-validation-for="Category" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label asp-for="BusinessType" class="form-label">Tipo</label>
|
|
||||||
<select asp-for="BusinessType" class="form-select">
|
|
||||||
<option value="individual">Pessoa Física</option>
|
|
||||||
<option value="company">Empresa</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="slugPreview" class="form-label">URL da Página</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<span class="input-group-text">page/</span>
|
|
||||||
<span class="input-group-text" id="categorySlug">categoria</span>
|
|
||||||
<span class="input-group-text">/</span>
|
|
||||||
<input type="text" class="form-control" id="slugPreview" readonly>
|
|
||||||
<input asp-for="Slug" type="hidden">
|
|
||||||
</div>
|
|
||||||
<small class="form-text text-muted">URL gerada automaticamente</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label asp-for="Bio" class="form-label">Bio/Descrição</label>
|
|
||||||
<div class="md-toolbar border rounded-top border-bottom-0 bg-light px-2 py-1 d-flex gap-1">
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary md-btn" data-target="Bio" data-wrap="**" title="Negrito"><b>B</b></button>
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary md-btn" data-target="Bio" data-wrap="*" title="Itálico"><i>I</i></button>
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary md-list-btn" data-target="Bio" title="Lista">• Lista</button>
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary md-link-btn" data-target="Bio" title="Link">🔗 Link</button>
|
|
||||||
</div>
|
|
||||||
<textarea asp-for="Bio" id="Bio" class="form-control rounded-0 rounded-bottom" rows="5" maxlength="3000" placeholder="Uma breve descrição sobre você ou sua empresa..." style="font-family: monospace; font-size: 0.9rem;"></textarea>
|
|
||||||
<span asp-validation-for="Bio" class="text-danger"></span>
|
|
||||||
<div class="form-text">Máximo 3000 caracteres. Use **negrito**, *itálico*, - item para listas.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Step 2: Seleção de Tema -->
|
|
||||||
<div class="wizard-step d-none" id="step2">
|
|
||||||
<h5 class="step-title">
|
|
||||||
<span class="step-number">2</span>
|
|
||||||
Escolha Seu Tema Visual
|
|
||||||
</h5>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
@foreach (var theme in ViewBag.Themes as List<BCards.Web.Models.PageTheme> ?? new List<BCards.Web.Models.PageTheme>())
|
|
||||||
{
|
|
||||||
<div class="col-md-4 mb-3">
|
|
||||||
<div class="theme-card" data-theme="@theme.Name.ToLower()">
|
|
||||||
<div class="theme-preview" style="background: @theme.BackgroundColor; color: @theme.TextColor;">
|
|
||||||
<div class="theme-header" style="background-color: @theme.PrimaryColor;">
|
|
||||||
<div class="theme-avatar"></div>
|
|
||||||
<h6>@theme.Name</h6>
|
|
||||||
</div>
|
|
||||||
<div class="theme-links">
|
|
||||||
<div class="theme-link" style="background-color: @theme.PrimaryColor;"></div>
|
|
||||||
<div class="theme-link" style="background-color: @theme.SecondaryColor;"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="theme-name">
|
|
||||||
@theme.Name
|
|
||||||
@if (theme.IsPremium)
|
|
||||||
{
|
|
||||||
<span class="badge bg-warning">Premium</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input asp-for="SelectedTheme" type="hidden">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Step 3: Links Principais -->
|
|
||||||
<div class="wizard-step d-none" id="step3">
|
|
||||||
<h5 class="step-title">
|
|
||||||
<span class="step-number">3</span>
|
|
||||||
Links Principais
|
|
||||||
</h5>
|
|
||||||
|
|
||||||
<div id="linksContainer">
|
|
||||||
<!-- Links will be added dynamically -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-outline-primary" id="addLinkBtn">
|
|
||||||
<i class="fas fa-plus"></i> Adicionar Link
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Step 4: Redes Sociais -->
|
|
||||||
<div class="wizard-step d-none" id="step4">
|
|
||||||
<h5 class="step-title">
|
|
||||||
<span class="step-number">4</span>
|
|
||||||
Redes Sociais
|
|
||||||
</h5>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label asp-for="WhatsAppNumber" class="form-label">
|
|
||||||
<i class="fab fa-whatsapp text-success"></i>
|
|
||||||
WhatsApp
|
|
||||||
</label>
|
|
||||||
<input asp-for="WhatsAppNumber" class="form-control" placeholder="+55 11 99999-9999">
|
|
||||||
<span asp-validation-for="WhatsAppNumber" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label asp-for="FacebookUrl" class="form-label">
|
|
||||||
<i class="fab fa-facebook text-primary"></i>
|
|
||||||
Facebook
|
|
||||||
</label>
|
|
||||||
<input asp-for="FacebookUrl" class="form-control" placeholder="https://facebook.com/seu-perfil">
|
|
||||||
<span asp-validation-for="FacebookUrl" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label asp-for="TwitterUrl" class="form-label">
|
|
||||||
<i class="fab fa-x-twitter"></i>
|
|
||||||
X / Twitter
|
|
||||||
</label>
|
|
||||||
<input asp-for="TwitterUrl" class="form-control" placeholder="https://x.com/seu-perfil">
|
|
||||||
<span asp-validation-for="TwitterUrl" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label asp-for="InstagramUrl" class="form-label">
|
|
||||||
<i class="fab fa-instagram text-danger"></i>
|
|
||||||
Instagram
|
|
||||||
</label>
|
|
||||||
<input asp-for="InstagramUrl" class="form-control" placeholder="https://instagram.com/seu-perfil">
|
|
||||||
<span asp-validation-for="InstagramUrl" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Step 5: Preview e Finalização -->
|
|
||||||
<div class="wizard-step d-none" id="step5">
|
|
||||||
<h5 class="step-title">
|
|
||||||
<span class="step-number">5</span>
|
|
||||||
Preview e Finalização
|
|
||||||
</h5>
|
|
||||||
|
|
||||||
<div class="preview-container">
|
|
||||||
<div class="preview-phone">
|
|
||||||
<div class="preview-screen" id="previewScreen">
|
|
||||||
<!-- Preview will be generated here -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-center mt-4">
|
|
||||||
<p class="text-muted">Sua página estará disponível em:</p>
|
|
||||||
<strong id="finalUrl">page/categoria/seu-slug</strong>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Navigation Buttons -->
|
|
||||||
<div class="wizard-navigation mt-4">
|
|
||||||
<button type="button" class="btn btn-secondary" id="prevBtn" style="display: none;">
|
|
||||||
<i class="fas fa-arrow-left"></i> Anterior
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-primary float-end" id="nextBtn">
|
|
||||||
Próximo <i class="fas fa-arrow-right"></i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button type="submit" class="btn btn-success float-end d-none" id="submitBtn">
|
|
||||||
<i class="fas fa-check"></i> Criar Página
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.wizard-step {
|
|
||||||
min-height: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-title {
|
|
||||||
color: #495057;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
padding-bottom: 1rem;
|
|
||||||
border-bottom: 2px solid #e9ecef;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step-number {
|
|
||||||
display: inline-block;
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
line-height: 30px;
|
|
||||||
background-color: #007bff;
|
|
||||||
color: white;
|
|
||||||
border-radius: 50%;
|
|
||||||
text-align: center;
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-card {
|
|
||||||
cursor: pointer;
|
|
||||||
border: 2px solid transparent;
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-card:hover,
|
|
||||||
.theme-card.selected {
|
|
||||||
border-color: #007bff;
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 123, 255, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-preview {
|
|
||||||
height: 120px;
|
|
||||||
position: relative;
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.5rem;
|
|
||||||
padding: 0.5rem;
|
|
||||||
border-radius: 4px;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-avatar {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: rgba(255, 255, 255, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-header h6 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-links {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-link {
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 4px;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-name {
|
|
||||||
padding: 0.75rem;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: 500;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-input-group {
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
border: 1px solid #dee2e6;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 1rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
min-height: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-phone {
|
|
||||||
width: 300px;
|
|
||||||
height: 400px;
|
|
||||||
border: 8px solid #333;
|
|
||||||
border-radius: 20px;
|
|
||||||
background-color: #000;
|
|
||||||
padding: 20px 10px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-screen {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 12px;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wizard-navigation {
|
|
||||||
border-top: 1px solid #dee2e6;
|
|
||||||
padding-top: 1rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
let currentStep = 1;
|
|
||||||
const totalSteps = 5;
|
|
||||||
let linkCount = 0;
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
initializeWizard();
|
|
||||||
|
|
||||||
// Generate slug when name or category changes
|
|
||||||
$('#DisplayName, #Category').on('input change', function() {
|
|
||||||
generateSlug();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Theme selection
|
|
||||||
$('.theme-card').on('click', function() {
|
|
||||||
$('.theme-card').removeClass('selected');
|
|
||||||
$(this).addClass('selected');
|
|
||||||
const themeName = $(this).data('theme');
|
|
||||||
$('#SelectedTheme').val(themeName);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Navigation
|
|
||||||
$('#nextBtn').on('click', function() {
|
|
||||||
if (validateCurrentStep()) {
|
|
||||||
nextStep();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#prevBtn').on('click', function() {
|
|
||||||
prevStep();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add link functionality
|
|
||||||
$('#addLinkBtn').on('click', function() {
|
|
||||||
addLinkInput();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Form submission
|
|
||||||
$('#createPageForm').on('submit', function(e) {
|
|
||||||
generateLinksData();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function initializeWizard() {
|
|
||||||
updateProgressBar();
|
|
||||||
updateNavigationButtons();
|
|
||||||
addLinkInput(); // Add first link input
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextStep() {
|
|
||||||
if (currentStep < totalSteps) {
|
|
||||||
$(`#step${currentStep}`).addClass('d-none');
|
|
||||||
currentStep++;
|
|
||||||
$(`#step${currentStep}`).removeClass('d-none');
|
|
||||||
|
|
||||||
if (currentStep === 5) {
|
|
||||||
generatePreview();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateProgressBar();
|
|
||||||
updateNavigationButtons();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function prevStep() {
|
|
||||||
if (currentStep > 1) {
|
|
||||||
$(`#step${currentStep}`).addClass('d-none');
|
|
||||||
currentStep--;
|
|
||||||
$(`#step${currentStep}`).removeClass('d-none');
|
|
||||||
updateProgressBar();
|
|
||||||
updateNavigationButtons();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateProgressBar() {
|
|
||||||
const progress = (currentStep / totalSteps) * 100;
|
|
||||||
$('#wizardProgress').css('width', progress + '%');
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateNavigationButtons() {
|
|
||||||
$('#prevBtn').toggle(currentStep > 1);
|
|
||||||
|
|
||||||
if (currentStep === totalSteps) {
|
|
||||||
$('#nextBtn').addClass('d-none');
|
|
||||||
$('#submitBtn').removeClass('d-none');
|
|
||||||
} else {
|
|
||||||
$('#nextBtn').removeClass('d-none');
|
|
||||||
$('#submitBtn').addClass('d-none');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateCurrentStep() {
|
|
||||||
let isValid = true;
|
|
||||||
|
|
||||||
switch (currentStep) {
|
|
||||||
case 1:
|
|
||||||
if (!$('#DisplayName').val() || !$('#Category').val()) {
|
|
||||||
alert('Por favor, preencha o nome e a categoria.');
|
|
||||||
isValid = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (!$('#SelectedTheme').val()) {
|
|
||||||
alert('Por favor, selecione um tema.');
|
|
||||||
isValid = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateSlug() {
|
|
||||||
const name = $('#DisplayName').val();
|
|
||||||
const category = $('#Category').val();
|
|
||||||
|
|
||||||
if (name && category) {
|
|
||||||
$.post('/Admin/GenerateSlug', { category: category, name: name })
|
|
||||||
.done(function(data) {
|
|
||||||
$('#Slug').val(data.slug);
|
|
||||||
$('#slugPreview').val(data.slug);
|
|
||||||
$('#categorySlug').text(category);
|
|
||||||
$('#finalUrl').text(`page/${category}/${data.slug}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addLinkInput() {
|
|
||||||
linkCount++;
|
|
||||||
const linkHtml = `
|
|
||||||
<div class="link-input-group" data-link="${linkCount}">
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
||||||
<h6 class="mb-0">Link ${linkCount}</h6>
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-danger remove-link-btn">
|
|
||||||
<i class="fas fa-trash"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-2">
|
|
||||||
<label class="form-label">Título</label>
|
|
||||||
<input type="text" class="form-control link-title" placeholder="Ex: Meu Site">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-2">
|
|
||||||
<label class="form-label">URL</label>
|
|
||||||
<input type="url" class="form-control link-url" placeholder="https://exemplo.com">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mb-2">
|
|
||||||
<label class="form-label">Descrição (opcional)</label>
|
|
||||||
<input type="text" class="form-control link-description" placeholder="Breve descrição do link">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
$('#linksContainer').append(linkHtml);
|
|
||||||
|
|
||||||
// Add remove functionality
|
|
||||||
$('.remove-link-btn').off('click').on('click', function() {
|
|
||||||
$(this).closest('.link-input-group').remove();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateLinksData() {
|
|
||||||
const links = [];
|
|
||||||
$('.link-input-group').each(function() {
|
|
||||||
const title = $(this).find('.link-title').val();
|
|
||||||
const url = $(this).find('.link-url').val();
|
|
||||||
const description = $(this).find('.link-description').val();
|
|
||||||
|
|
||||||
if (title && url) {
|
|
||||||
links.push({
|
|
||||||
Title: title,
|
|
||||||
Url: url,
|
|
||||||
Description: description,
|
|
||||||
Icon: ''
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Remove existing hidden link inputs
|
|
||||||
$('input[name^="Links["]').remove();
|
|
||||||
|
|
||||||
// Create hidden inputs for links directly in the form
|
|
||||||
links.forEach((link, index) => {
|
|
||||||
$('#createPageForm').append(`
|
|
||||||
<input type="hidden" name="Links[${index}].Title" value="${link.Title}" />
|
|
||||||
<input type="hidden" name="Links[${index}].Url" value="${link.Url}" />
|
|
||||||
<input type="hidden" name="Links[${index}].Description" value="${link.Description}" />
|
|
||||||
<input type="hidden" name="Links[${index}].Icon" value="${link.Icon}" />
|
|
||||||
`);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Debug: Log what we're sending
|
|
||||||
console.log('=== DEBUG GENERATELINKSDATA ===');
|
|
||||||
console.log('Links found:', links.length);
|
|
||||||
links.forEach((link, index) => {
|
|
||||||
console.log(`Link ${index}:`, link);
|
|
||||||
});
|
|
||||||
console.log('=== FIM DEBUG ===');
|
|
||||||
}
|
|
||||||
|
|
||||||
function generatePreview() {
|
|
||||||
const name = $('#DisplayName').val();
|
|
||||||
const bio = $('#Bio').val();
|
|
||||||
const selectedTheme = $('#SelectedTheme').val();
|
|
||||||
|
|
||||||
let previewHtml = `
|
|
||||||
<div class="text-center">
|
|
||||||
<div class="mb-3">
|
|
||||||
<div style="width: 60px; height: 60px; background-color: #ddd; border-radius: 50%; margin: 0 auto;"></div>
|
|
||||||
</div>
|
|
||||||
<h5 class="mb-2">${name}</h5>
|
|
||||||
<p class="text-muted small mb-3">${bio}</p>
|
|
||||||
<div class="d-grid gap-2">
|
|
||||||
`;
|
|
||||||
|
|
||||||
// Add links preview
|
|
||||||
$('.link-input-group').each(function() {
|
|
||||||
const title = $(this).find('.link-title').val();
|
|
||||||
if (title) {
|
|
||||||
previewHtml += `<div class="btn btn-primary btn-sm">${title}</div>`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add social media preview
|
|
||||||
if ($('#WhatsAppNumber').val()) {
|
|
||||||
previewHtml += `<div class="btn btn-success btn-sm"><i class="fab fa-whatsapp"></i> WhatsApp</div>`;
|
|
||||||
}
|
|
||||||
if ($('#FacebookUrl').val()) {
|
|
||||||
previewHtml += `<div class="btn btn-primary btn-sm"><i class="fab fa-facebook"></i> Facebook</div>`;
|
|
||||||
}
|
|
||||||
if ($('#TwitterUrl').val()) {
|
|
||||||
previewHtml += `<div class="btn btn-dark btn-sm"><i class="fab fa-x-twitter"></i> X / Twitter</div>`;
|
|
||||||
}
|
|
||||||
if ($('#InstagramUrl').val()) {
|
|
||||||
previewHtml += `<div class="btn btn-danger btn-sm"><i class="fab fa-instagram"></i> Instagram</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
previewHtml += `</div></div>`;
|
|
||||||
|
|
||||||
$('#previewScreen').html(previewHtml);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
@section Scripts {
|
|
||||||
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
|
|
||||||
<script>
|
|
||||||
$(document).ready(function() {
|
|
||||||
document.querySelectorAll('.md-btn').forEach(function(btn) {
|
|
||||||
btn.addEventListener('click', function() {
|
|
||||||
var targetId = this.dataset.target;
|
|
||||||
var wrap = this.dataset.wrap;
|
|
||||||
var ta = document.getElementById(targetId);
|
|
||||||
var start = ta.selectionStart, end = ta.selectionEnd;
|
|
||||||
var sel = ta.value.substring(start, end) || 'texto';
|
|
||||||
var before = ta.value.substring(0, start);
|
|
||||||
var after = ta.value.substring(end);
|
|
||||||
ta.value = before + wrap + sel + wrap + after;
|
|
||||||
ta.selectionStart = start + wrap.length;
|
|
||||||
ta.selectionEnd = start + wrap.length + sel.length;
|
|
||||||
ta.focus();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
document.querySelectorAll('.md-list-btn').forEach(function(btn) {
|
|
||||||
btn.addEventListener('click', function() {
|
|
||||||
var targetId = this.dataset.target;
|
|
||||||
var ta = document.getElementById(targetId);
|
|
||||||
var start = ta.selectionStart;
|
|
||||||
var lineStart = ta.value.lastIndexOf('\n', start - 1) + 1;
|
|
||||||
var before = ta.value.substring(0, lineStart);
|
|
||||||
var after = ta.value.substring(lineStart);
|
|
||||||
ta.value = before + '- ' + after;
|
|
||||||
ta.selectionStart = ta.selectionEnd = start + 2;
|
|
||||||
ta.focus();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
document.querySelectorAll('.md-link-btn').forEach(function(btn) {
|
|
||||||
btn.addEventListener('click', function() {
|
|
||||||
var targetId = this.dataset.target;
|
|
||||||
var ta = document.getElementById(targetId);
|
|
||||||
var start = ta.selectionStart, end = ta.selectionEnd;
|
|
||||||
var sel = ta.value.substring(start, end) || 'texto do link';
|
|
||||||
var url = prompt('URL do link:') || 'https://';
|
|
||||||
var before = ta.value.substring(0, start);
|
|
||||||
var after = ta.value.substring(end);
|
|
||||||
var md = '[' + sel + '](' + url + ')';
|
|
||||||
ta.value = before + md + after;
|
|
||||||
ta.selectionStart = ta.selectionEnd = start + md.length;
|
|
||||||
ta.focus();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
}
|
|
||||||
@ -115,11 +115,50 @@
|
|||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label asp-for="Bio" class="form-label">Bio/Descrição</label>
|
<label asp-for="Bio" class="form-label">Bio/Descrição</label>
|
||||||
<div class="md-toolbar border rounded-top border-bottom-0 bg-light px-2 py-1 d-flex gap-1">
|
<div class="md-toolbar border rounded-top border-bottom-0 bg-light px-2 py-1 d-flex gap-1 flex-wrap position-relative">
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary md-btn" data-target="Bio" data-wrap="**" title="Negrito"><b>B</b></button>
|
<button type="button" class="btn btn-sm btn-outline-secondary md-btn" data-target="Bio" data-wrap="**" title="Negrito"><b>B</b></button>
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary md-btn" data-target="Bio" data-wrap="*" title="Itálico"><i>I</i></button>
|
<button type="button" class="btn btn-sm btn-outline-secondary md-btn" data-target="Bio" data-wrap="*" title="Itálico"><i>I</i></button>
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary md-btn md-list-btn" data-target="Bio" title="Lista">• Lista</button>
|
<button type="button" class="btn btn-sm btn-outline-secondary md-list-btn" data-target="Bio" title="Lista">• Lista</button>
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary md-link-btn" data-target="Bio" title="Link">🔗 Link</button>
|
<button type="button" class="btn btn-sm btn-outline-secondary md-link-btn" data-target="Bio" title="Link">🔗 Link</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary md-icon-picker-btn" data-target="Bio" title="Inserir ícone">⚙ Ícone</button>
|
||||||
|
<div class="md-icon-picker-panel shadow border rounded bg-white p-2" style="display:none; position:absolute; top:100%; left:0; z-index:9999; width:300px; max-height:260px; overflow-y:auto;">
|
||||||
|
<div class="md-icon-section mb-2">
|
||||||
|
<div class="text-muted small mb-1 fw-semibold">Status</div>
|
||||||
|
<div class="d-flex flex-wrap gap-1">
|
||||||
|
<span class="md-icon-item" title="OK">✅</span><span class="md-icon-item" title="Erro">❌</span><span class="md-icon-item" title="Atenção">⚠️</span><span class="md-icon-item" title="Info">ℹ️</span><span class="md-icon-item" title="Check">✔</span><span class="md-icon-item" title="X">✘</span><span class="md-icon-item" title="Seta">➤</span><span class="md-icon-item" title="Seta direita">→</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="md-icon-section mb-2">
|
||||||
|
<div class="text-muted small mb-1 fw-semibold">Formas & Bullets</div>
|
||||||
|
<div class="d-flex flex-wrap gap-1">
|
||||||
|
<span class="md-icon-item" title="Bullet">•</span><span class="md-icon-item" title="Círculo vazio">○</span><span class="md-icon-item" title="Círculo cheio">●</span><span class="md-icon-item" title="Quadrado cheio">■</span><span class="md-icon-item" title="Quadrado vazio">□</span><span class="md-icon-item" title="Quadrado com check">☑</span><span class="md-icon-item" title="Losango cheio">◆</span><span class="md-icon-item" title="Losango vazio">◇</span><span class="md-icon-item" title="Triângulo">▶</span><span class="md-icon-item" title="Estrela">★</span><span class="md-icon-item" title="Estrela vazia">☆</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="md-icon-section mb-2">
|
||||||
|
<div class="text-muted small mb-1 fw-semibold">Círculos coloridos</div>
|
||||||
|
<div class="d-flex flex-wrap gap-1">
|
||||||
|
<span class="md-icon-item" title="Vermelho">🔴</span><span class="md-icon-item" title="Laranja">🟠</span><span class="md-icon-item" title="Amarelo">🟡</span><span class="md-icon-item" title="Verde">🟢</span><span class="md-icon-item" title="Azul">🔵</span><span class="md-icon-item" title="Roxo">🟣</span><span class="md-icon-item" title="Preto">⚫</span><span class="md-icon-item" title="Branco">⚪</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="md-icon-section mb-2">
|
||||||
|
<div class="text-muted small mb-1 fw-semibold">Negócios & Escritório</div>
|
||||||
|
<div class="d-flex flex-wrap gap-1">
|
||||||
|
<span class="md-icon-item" title="Gráfico barras">📊</span><span class="md-icon-item" title="Gráfico alta">📈</span><span class="md-icon-item" title="Gráfico baixa">📉</span><span class="md-icon-item" title="Prancheta">📋</span><span class="md-icon-item" title="Pin">📌</span><span class="md-icon-item" title="Pasta">📁</span><span class="md-icon-item" title="Maleta">💼</span><span class="md-icon-item" title="Nota">📝</span><span class="md-icon-item" title="Email">📧</span><span class="md-icon-item" title="Telefone">📞</span><span class="md-icon-item" title="Alvo">🎯</span><span class="md-icon-item" title="Troféu">🏆</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="md-icon-section mb-2">
|
||||||
|
<div class="text-muted small mb-1 fw-semibold">Tecnologia</div>
|
||||||
|
<div class="d-flex flex-wrap gap-1">
|
||||||
|
<span class="md-icon-item" title="Notebook">💻</span><span class="md-icon-item" title="Monitor">🖥️</span><span class="md-icon-item" title="Celular">📱</span><span class="md-icon-item" title="Teclado">⌨️</span><span class="md-icon-item" title="Impressora">🖨️</span><span class="md-icon-item" title="Engrenagem">⚙️</span><span class="md-icon-item" title="Lupa">🔍</span><span class="md-icon-item" title="Link">🔗</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="md-icon-section">
|
||||||
|
<div class="text-muted small mb-1 fw-semibold">Finanças & Outros</div>
|
||||||
|
<div class="d-flex flex-wrap gap-1">
|
||||||
|
<span class="md-icon-item" title="Dinheiro">💰</span><span class="md-icon-item" title="Cartão">💳</span><span class="md-icon-item" title="Banco">🏦</span><span class="md-icon-item" title="Chave">🔑</span><span class="md-icon-item" title="Cadeado">🔒</span><span class="md-icon-item" title="Sino">🔔</span><span class="md-icon-item" title="Lâmpada">💡</span><span class="md-icon-item" title="Raio">⚡</span><span class="md-icon-item" title="Pessoa">👤</span><span class="md-icon-item" title="Pessoas">👥</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<textarea asp-for="Bio" id="Bio" class="form-control rounded-0 rounded-bottom" rows="5" maxlength="3000" placeholder="Uma breve descrição sobre você ou sua empresa..." style="font-family: monospace; font-size: 0.9rem;"></textarea>
|
<textarea asp-for="Bio" id="Bio" class="form-control rounded-0 rounded-bottom" rows="5" maxlength="3000" placeholder="Uma breve descrição sobre você ou sua empresa..." style="font-family: monospace; font-size: 0.9rem;"></textarea>
|
||||||
<span asp-validation-for="Bio" class="text-danger"></span>
|
<span asp-validation-for="Bio" class="text-danger"></span>
|
||||||
@ -1953,6 +1992,37 @@
|
|||||||
|
|
||||||
// Markdown Toolbar
|
// Markdown Toolbar
|
||||||
function initMarkdownToolbar() {
|
function initMarkdownToolbar() {
|
||||||
|
// Icon picker toggle
|
||||||
|
document.querySelectorAll('.md-icon-picker-btn').forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
var panel = this.parentElement.querySelector('.md-icon-picker-panel');
|
||||||
|
var isVisible = panel.style.display !== 'none';
|
||||||
|
document.querySelectorAll('.md-icon-picker-panel').forEach(function(p) { p.style.display = 'none'; });
|
||||||
|
if (!isVisible) panel.style.display = 'block';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Insert icon on click
|
||||||
|
document.querySelectorAll('.md-icon-item').forEach(function(item) {
|
||||||
|
item.addEventListener('click', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
var panel = this.closest('.md-icon-picker-panel');
|
||||||
|
var btn = panel.parentElement.querySelector('.md-icon-picker-btn');
|
||||||
|
var targetId = btn ? btn.dataset.target : 'Bio';
|
||||||
|
var ta = document.getElementById(targetId);
|
||||||
|
var icon = this.textContent;
|
||||||
|
var start = ta.selectionStart, end = ta.selectionEnd;
|
||||||
|
ta.value = ta.value.substring(0, start) + icon + ta.value.substring(end);
|
||||||
|
ta.selectionStart = ta.selectionEnd = start + icon.length;
|
||||||
|
ta.focus();
|
||||||
|
panel.style.display = 'none';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Close picker on outside click
|
||||||
|
document.addEventListener('click', function() {
|
||||||
|
document.querySelectorAll('.md-icon-picker-panel').forEach(function(p) { p.style.display = 'none'; });
|
||||||
|
});
|
||||||
|
|
||||||
document.querySelectorAll('.md-btn').forEach(function(btn) {
|
document.querySelectorAll('.md-btn').forEach(function(btn) {
|
||||||
btn.addEventListener('click', function() {
|
btn.addEventListener('click', function() {
|
||||||
var targetId = this.dataset.target;
|
var targetId = this.dataset.target;
|
||||||
@ -2663,6 +2733,16 @@
|
|||||||
|
|
||||||
@section Styles {
|
@section Styles {
|
||||||
<style>
|
<style>
|
||||||
|
.md-icon-item {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
padding: 2px 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
line-height: 1.4;
|
||||||
|
transition: background 0.1s;
|
||||||
|
}
|
||||||
|
.md-icon-item:hover { background: #e9ecef; }
|
||||||
|
|
||||||
/* Estilo customizado para o scroll dos temas */
|
/* Estilo customizado para o scroll dos temas */
|
||||||
.themes-container {
|
.themes-container {
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
|
|||||||
@ -111,7 +111,7 @@
|
|||||||
<div class="card-footer bg-transparent p-4">
|
<div class="card-footer bg-transparent p-4">
|
||||||
@if (User.Identity?.IsAuthenticated == true)
|
@if (User.Identity?.IsAuthenticated == true)
|
||||||
{
|
{
|
||||||
<a asp-controller="Admin" asp-action="CreatePage" class="btn btn-success w-100">Começar Grátis</a>
|
<a asp-controller="Admin" asp-action="ManagePage" asp-route-id="new" class="btn btn-success w-100">Começar Grátis</a>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user