Replace tiny JPEG stubs with per-slot Unsplash editorial placeholders, align public type scale to DESIGN.md display/headline tokens, add final-cta on all subpages, about_image_path on site settings, and harden visual regression with solid-color VisualContentSeeder fixtures.
209 lines
9.1 KiB
PHP
209 lines
9.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Database\Seeders;
|
|
|
|
use App\Models\PortfolioCase;
|
|
use App\Models\PortfolioImage;
|
|
use App\Models\Service;
|
|
use App\Models\SiteSetting;
|
|
use App\Models\Testimonial;
|
|
use Illuminate\Database\Seeder;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
/**
|
|
* Deterministic content for visual regression. Keep separate from ContentSeeder demo data.
|
|
*/
|
|
class VisualContentSeeder extends Seeder
|
|
{
|
|
public const FROZEN_NOW = '2026-03-15T12:00:00-03:00';
|
|
|
|
private const SEED_TIMESTAMP = '2026-03-15 12:00:00';
|
|
|
|
public function run(): void
|
|
{
|
|
Carbon::setTestNow(Carbon::parse(self::FROZEN_NOW));
|
|
|
|
$this->seedSiteSettings();
|
|
$this->seedServices();
|
|
$this->seedPortfolioCases();
|
|
$this->seedTestimonials();
|
|
}
|
|
|
|
private function seedSiteSettings(): void
|
|
{
|
|
SiteSetting::query()->updateOrCreate([], [
|
|
'brand_name' => 'Amare Assessoria',
|
|
'hero_eyebrow' => 'Assessoria e produção de eventos · São Paulo',
|
|
'hero_title' => 'Celebrações com propósito',
|
|
'hero_subtitle' => 'Planejamento completo para casamentos e eventos corporativos em São Paulo.',
|
|
'hero_cta_label' => 'Solicitar proposta',
|
|
'hero_secondary_cta_label' => 'Conheça nosso olhar',
|
|
'hero_note' => 'Planejamento cuidadoso, comunicação clara e execução segura — do primeiro encontro ao último detalhe.',
|
|
'about_summary' => 'Assessoria boutique especializada em experiências memoráveis em São Paulo.',
|
|
'about_image_path' => $this->writeSolidJpeg('visual/about/about-image.jpg', 1200, 900, [232, 228, 218]),
|
|
'about_image_alt' => 'Imagem editorial da página Sobre',
|
|
'manifesto_title' => 'Sofisticação que também se traduz em organização.',
|
|
'manifesto_lead' => 'Um evento memorável não nasce apenas de uma boa estética. Ele depende de decisões bem conduzidas, fornecedores alinhados e atenção constante ao que realmente importa.',
|
|
'manifesto_body' => 'A Amare combina sensibilidade e precisão para criar encontros coerentes com cada cliente, marca e ocasião — sem fórmulas prontas, excessos ou ruído.',
|
|
'method_intro' => 'Clareza em cada etapa. Tranquilidade durante todo o processo.',
|
|
'method_steps' => SiteSetting::defaultMethodSteps(),
|
|
'principles' => SiteSetting::defaultPrinciples(),
|
|
'email' => 'amareassessoriaeventos@gmail.com',
|
|
'phone' => '(11) 99999-9999',
|
|
'city' => 'São Paulo - SP',
|
|
'social_links' => [
|
|
'instagram' => 'https://instagram.com/amare',
|
|
],
|
|
'default_meta_title' => 'Amare Assessoria de Eventos',
|
|
'default_meta_description' => 'Assessoria premium para casamentos e eventos corporativos em São Paulo.',
|
|
'default_og_image_path' => $this->writeSolidJpeg('visual/og/og-default.jpg', 1600, 1067, [85, 107, 47]),
|
|
'default_og_image_alt' => 'Identidade visual da Amare Assessoria de Eventos',
|
|
'analytics_enabled' => false,
|
|
'analytics_script' => null,
|
|
]);
|
|
}
|
|
|
|
private function seedServices(): void
|
|
{
|
|
foreach ([
|
|
[
|
|
'title' => 'Casamentos',
|
|
'slug' => 'casamentos',
|
|
'summary' => 'Planejamento completo do grande dia.',
|
|
'description' => 'Do briefing ao último brinde, cuidamos de cada detalhe do casamento.',
|
|
'sort_order' => 1,
|
|
'is_featured' => true,
|
|
],
|
|
[
|
|
'title' => 'Eventos corporativos',
|
|
'slug' => 'eventos-corporativos',
|
|
'summary' => 'Experiências alinhadas à marca.',
|
|
'description' => 'Lançamentos, convenções e encontros corporativos com operação impecável.',
|
|
'sort_order' => 2,
|
|
'is_featured' => true,
|
|
],
|
|
] as $service) {
|
|
Service::query()->updateOrCreate(
|
|
['slug' => $service['slug']],
|
|
[
|
|
...$service,
|
|
'cover_image_path' => $this->writeSolidJpeg('visual/services/'.$service['slug'].'.jpg', 1600, 1000, [196, 200, 184]),
|
|
'cover_image_alt' => 'Capa do serviço '.$service['title'],
|
|
'published_at' => Carbon::parse(self::SEED_TIMESTAMP),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
private function seedPortfolioCases(): void
|
|
{
|
|
$cases = [
|
|
[
|
|
'title' => 'Casamento Ana e Lucas',
|
|
'slug' => 'casamento-ana-lucas',
|
|
'summary' => 'Cerimônia ao ar livre em São Paulo.',
|
|
'event_type' => 'Casamento',
|
|
'city' => 'São Paulo',
|
|
'venue' => 'Espaço Jardim Atlântico',
|
|
'event_date' => '2025-11-20',
|
|
'challenge' => 'Integrar cerimônia e recepção em áreas distintas.',
|
|
'solution' => 'Operação sincronizada com sinalização e timing detalhado.',
|
|
'result' => 'Experiência fluida para 180 convidados.',
|
|
'sort_order' => 1,
|
|
],
|
|
[
|
|
'title' => 'Lançamento Verano',
|
|
'slug' => 'lancamento-verano',
|
|
'summary' => 'Evento corporativo de lançamento de coleção.',
|
|
'event_type' => 'Corporativo',
|
|
'city' => 'São Paulo',
|
|
'venue' => 'Centro de Convenções',
|
|
'event_date' => '2025-09-10',
|
|
'challenge' => 'Ativar marca em ambiente multiestação.',
|
|
'solution' => 'Fluxo de convidados e fornecedores com cronograma minuto a minuto.',
|
|
'result' => 'Alta percepção de marca e cobertura de imprensa.',
|
|
'sort_order' => 2,
|
|
],
|
|
];
|
|
|
|
foreach ($cases as $caseData) {
|
|
$case = PortfolioCase::query()->updateOrCreate(
|
|
['slug' => $caseData['slug']],
|
|
[
|
|
...$caseData,
|
|
'cover_image_path' => $this->writeSolidJpeg('visual/portfolio/'.$caseData['slug'].'-cover.jpg', 1600, 1200, [240, 238, 233]),
|
|
'cover_image_alt' => 'Capa do caso '.$caseData['title'],
|
|
'is_featured' => true,
|
|
'published_at' => Carbon::parse(self::SEED_TIMESTAMP),
|
|
],
|
|
);
|
|
|
|
PortfolioImage::query()->where('portfolio_case_id', $case->id)->delete();
|
|
|
|
PortfolioImage::query()->create([
|
|
'portfolio_case_id' => $case->id,
|
|
'path' => $this->writeSolidJpeg('visual/portfolio/'.$caseData['slug'].'-gallery-1.jpg', 1600, 1200, [228, 226, 221]),
|
|
'alt_text' => 'Galeria '.$caseData['title'].' 1',
|
|
'caption' => 'Detalhe da decoração',
|
|
'sort_order' => 1,
|
|
]);
|
|
}
|
|
}
|
|
|
|
private function seedTestimonials(): void
|
|
{
|
|
Testimonial::query()->whereNotIn('author_name', [
|
|
'Jeniffer e Maick',
|
|
'Quesia e Jhonata',
|
|
])->delete();
|
|
|
|
foreach ([
|
|
[
|
|
'quote' => "Mi, quero agradecer você e a sua equipe por todo empenho, atenção, vocês são abençoadas.\n\nEra nítida sua preocupação em garantir que todos os detalhes planejados desta comemoração, fossem atendidos.\n\nQue você possa transformar o grande dia das noivinhas sempre com essa sua leveza!!!\n\nMuito obrigada!",
|
|
'author_name' => 'Jeniffer e Maick',
|
|
'context' => 'Casamento · 06/12/2025',
|
|
'sort_order' => 1,
|
|
],
|
|
[
|
|
'quote' => "Mi, eu não tenho palavras pra agradecer você e tudo que você fez por mim e por nós na realização desse sonho. Eu tô ainda extasiada com tudo que aconteceu hoje; mas tenho certeza que sem a sua ajuda, muita coisa não aconteceria.\n\nObrigada por tudo !",
|
|
'author_name' => 'Quesia e Jhonata',
|
|
'context' => 'Casamento · 21/12/2025',
|
|
'sort_order' => 2,
|
|
],
|
|
] as $testimonial) {
|
|
Testimonial::query()->updateOrCreate(
|
|
['author_name' => $testimonial['author_name']],
|
|
[
|
|
...$testimonial,
|
|
'is_featured' => true,
|
|
'photo_path' => null,
|
|
'photo_alt' => null,
|
|
'published_at' => Carbon::parse(self::SEED_TIMESTAMP),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array{0: int, 1: int, 2: int} $rgb
|
|
*/
|
|
private function writeSolidJpeg(string $destination, int $width, int $height, array $rgb): string
|
|
{
|
|
$image = imagecreatetruecolor($width, $height);
|
|
$color = imagecolorallocate($image, $rgb[0], $rgb[1], $rgb[2]);
|
|
imagefilledrectangle($image, 0, 0, $width, $height, $color);
|
|
|
|
ob_start();
|
|
imagejpeg($image, null, 90);
|
|
$binary = (string) ob_get_clean();
|
|
imagedestroy($image);
|
|
|
|
Storage::disk('public')->put($destination, $binary);
|
|
|
|
return $destination;
|
|
}
|
|
}
|