fix(ui): remove black bg on hero images, improve dino quality, protect seed from overwriting admin data
- DyvoLisHero: add mix-blend-mode:screen to hero img so JPEG black bg becomes transparent and the orange ellipse shows through - DinoPageContent: add contrast/saturation filter to hero-dino for richer colour rendering - seed.ts: globals (home-page, header, footer, site-settings) now only updated when FORCE_SEED=true; tariffs seeded only when table is empty (never deleted), preventing accidental data loss on redeploy Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
04b28e7620
commit
5f23806a82
3 changed files with 212 additions and 189 deletions
|
|
@ -298,6 +298,7 @@ const DYNO_CSS = `
|
|||
.dino-page .hero-dino{
|
||||
position:absolute;top:12px;right:-60px;height:1096px;width:auto;max-width:none;
|
||||
z-index:0;pointer-events:none;
|
||||
filter:contrast(1.08) saturate(1.12);
|
||||
}
|
||||
.dino-page .hero-text{position:relative;z-index:2;max-width:608px;padding:60px 0 40px;}
|
||||
.dino-page .hero-text h1{
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ export function DyvoLisHero({
|
|||
}}
|
||||
/>
|
||||
</div>
|
||||
{/* Cat */}
|
||||
{/* Cat — screen blend removes black JPEG background, shows ellipse behind */}
|
||||
<img
|
||||
src={heroImg}
|
||||
alt="Топіарна фігура ДивоЛісу"
|
||||
|
|
@ -152,6 +152,7 @@ export function DyvoLisHero({
|
|||
top: '-20.7%',
|
||||
width: '126.9%',
|
||||
height: 'auto',
|
||||
mixBlendMode: 'screen',
|
||||
}}
|
||||
loading="eager"
|
||||
/>
|
||||
|
|
|
|||
397
src/seed.ts
397
src/seed.ts
|
|
@ -5,6 +5,15 @@ import config from '../payload.config.js'
|
|||
async function seed(): Promise<void> {
|
||||
const payload = await getPayload({ config })
|
||||
|
||||
// FORCE_SEED=true is required to overwrite globals that may have been edited in the admin UI.
|
||||
// Without it, only empty collections (users, blog posts, tariffs, locations) are seeded.
|
||||
const force = process.env['FORCE_SEED'] === 'true'
|
||||
|
||||
if (!force) {
|
||||
console.log('Running in safe mode — globals will NOT be overwritten.')
|
||||
console.log('Set FORCE_SEED=true to re-seed all globals (will overwrite admin changes).')
|
||||
}
|
||||
|
||||
// Admin user
|
||||
const { totalDocs } = await payload.find({
|
||||
collection: 'users',
|
||||
|
|
@ -28,115 +37,123 @@ async function seed(): Promise<void> {
|
|||
console.log('Users already exist, skipping user seed.')
|
||||
}
|
||||
|
||||
if (!force) {
|
||||
console.log('Skipping globals seed — run with FORCE_SEED=true to overwrite.')
|
||||
}
|
||||
|
||||
// Home page global with real content
|
||||
await payload.updateGlobal({
|
||||
slug: 'home-page',
|
||||
data: {
|
||||
hero: {
|
||||
title: 'Започаткуйте традицію:',
|
||||
subtitle: 'щороку фотографуйтесь біля улюбленого динозавра',
|
||||
if (force) {
|
||||
await payload.updateGlobal({
|
||||
slug: 'home-page',
|
||||
data: {
|
||||
hero: {
|
||||
title: 'Започаткуйте традицію:',
|
||||
subtitle: 'щороку фотографуйтесь біля улюбленого динозавра',
|
||||
ctaLabel: 'Купити квиток',
|
||||
ctaHref: '/kvytky',
|
||||
},
|
||||
sectionTitles: {
|
||||
locations: 'ЛАСКАВО ПРОСИМО ДО ШУМІЛЕНДУ',
|
||||
whyParents: 'ЧОМУ БАТЬКИ ОБИРАЮТЬ ШУМІЛЕНД',
|
||||
birthday: 'ДЕНЬ НАРОДЖЕННЯ В ШУМІЛЕНДІ',
|
||||
gallery: 'ФОТОГАЛЕРЕЯ',
|
||||
reviews: 'ВІДГУКИ',
|
||||
news: 'НОВИНИ',
|
||||
},
|
||||
locations: [
|
||||
{
|
||||
name: 'ДиноПарк',
|
||||
shortDesc: 'Прогуляйтесь серед реалістичних динозаврів у повний зріст',
|
||||
href: '/lokatsii',
|
||||
},
|
||||
{
|
||||
name: 'Диво Ліс',
|
||||
shortDesc: 'Чарівний ліс з інтерактивними атракціонами та мотузковими парками',
|
||||
href: '/lokatsii',
|
||||
},
|
||||
{
|
||||
name: 'Дзеркальний Лабіринт',
|
||||
shortDesc: 'Захоплюючий лабіринт з дзеркалами та оптичними ілюзіями',
|
||||
href: '/lokatsii',
|
||||
},
|
||||
],
|
||||
features: [
|
||||
{
|
||||
icon: '🦕',
|
||||
title: 'Безпека',
|
||||
description: 'Атракціони сертифіковані, майданчик під постійним наглядом',
|
||||
},
|
||||
{ icon: '🌲', title: 'Природа', description: 'Парк розташований серед живої природи' },
|
||||
{
|
||||
icon: '🎉',
|
||||
title: 'Свята',
|
||||
description: 'Дні народження, корпоративи та шкільні екскурсії',
|
||||
},
|
||||
{
|
||||
icon: '🎟️',
|
||||
title: 'Квитки онлайн',
|
||||
description: 'Купуйте квитки онлайн без черги на касі',
|
||||
},
|
||||
{
|
||||
icon: '🍕',
|
||||
title: 'Кафе та їжа',
|
||||
description: 'Власне кафе з дитячим меню та легкими закусками',
|
||||
},
|
||||
{ icon: '🅿️', title: 'Парковка', description: 'Безкоштовна парковка для відвідувачів' },
|
||||
],
|
||||
news: { title: 'Новини', limit: 3 },
|
||||
} as never,
|
||||
overrideAccess: true,
|
||||
})
|
||||
console.log('Seeded home-page global')
|
||||
}
|
||||
|
||||
if (force) {
|
||||
// Header global
|
||||
await payload.updateGlobal({
|
||||
slug: 'header',
|
||||
data: {
|
||||
navLinks: [
|
||||
{ label: 'Головна', href: '/' },
|
||||
{ label: 'Локації', href: '/lokatsii' },
|
||||
{ label: 'Блог', href: '/blog' },
|
||||
{ label: 'Дні народження', href: '/dni-narodzhennia' },
|
||||
{ label: 'Групові відвідування', href: '/grupovi-vidviduvannia' },
|
||||
],
|
||||
ctaLabel: 'Купити квиток',
|
||||
ctaHref: '/kvytky',
|
||||
},
|
||||
sectionTitles: {
|
||||
locations: 'ЛАСКАВО ПРОСИМО ДО ШУМІЛЕНДУ',
|
||||
whyParents: 'ЧОМУ БАТЬКИ ОБИРАЮТЬ ШУМІЛЕНД',
|
||||
birthday: 'ДЕНЬ НАРОДЖЕННЯ В ШУМІЛЕНДІ',
|
||||
gallery: 'ФОТОГАЛЕРЕЯ',
|
||||
reviews: 'ВІДГУКИ',
|
||||
news: 'НОВИНИ',
|
||||
},
|
||||
locations: [
|
||||
{
|
||||
name: 'ДиноПарк',
|
||||
shortDesc: 'Прогуляйтесь серед реалістичних динозаврів у повний зріст',
|
||||
href: '/lokatsii',
|
||||
},
|
||||
{
|
||||
name: 'Диво Ліс',
|
||||
shortDesc: 'Чарівний ліс з інтерактивними атракціонами та мотузковими парками',
|
||||
href: '/lokatsii',
|
||||
},
|
||||
{
|
||||
name: 'Дзеркальний Лабіринт',
|
||||
shortDesc: 'Захоплюючий лабіринт з дзеркалами та оптичними ілюзіями',
|
||||
href: '/lokatsii',
|
||||
},
|
||||
],
|
||||
features: [
|
||||
{
|
||||
icon: '🦕',
|
||||
title: 'Безпека',
|
||||
description: 'Атракціони сертифіковані, майданчик під постійним наглядом',
|
||||
},
|
||||
{ icon: '🌲', title: 'Природа', description: 'Парк розташований серед живої природи' },
|
||||
{
|
||||
icon: '🎉',
|
||||
title: 'Свята',
|
||||
description: 'Дні народження, корпоративи та шкільні екскурсії',
|
||||
},
|
||||
{
|
||||
icon: '🎟️',
|
||||
title: 'Квитки онлайн',
|
||||
description: 'Купуйте квитки онлайн без черги на касі',
|
||||
},
|
||||
{
|
||||
icon: '🍕',
|
||||
title: 'Кафе та їжа',
|
||||
description: 'Власне кафе з дитячим меню та легкими закусками',
|
||||
},
|
||||
{ icon: '🅿️', title: 'Парковка', description: 'Безкоштовна парковка для відвідувачів' },
|
||||
],
|
||||
news: { title: 'Новини', limit: 3 },
|
||||
} as never,
|
||||
overrideAccess: true,
|
||||
})
|
||||
console.log('Seeded home-page global')
|
||||
} as never,
|
||||
overrideAccess: true,
|
||||
})
|
||||
console.log('Seeded header global')
|
||||
|
||||
// Header global
|
||||
await payload.updateGlobal({
|
||||
slug: 'header',
|
||||
data: {
|
||||
navLinks: [
|
||||
{ label: 'Головна', href: '/' },
|
||||
{ label: 'Локації', href: '/lokatsii' },
|
||||
{ label: 'Блог', href: '/blog' },
|
||||
{ label: 'Дні народження', href: '/dni-narodzhennia' },
|
||||
{ label: 'Групові відвідування', href: '/grupovi-vidviduvannia' },
|
||||
],
|
||||
ctaLabel: 'Купити квиток',
|
||||
ctaHref: '/kvytky',
|
||||
} as never,
|
||||
overrideAccess: true,
|
||||
})
|
||||
console.log('Seeded header global')
|
||||
// Footer global
|
||||
await payload.updateGlobal({
|
||||
slug: 'footer',
|
||||
data: { copyrightText: `© Шуміленд ${new Date().getFullYear()}` } as never,
|
||||
overrideAccess: true,
|
||||
})
|
||||
console.log('Seeded footer global')
|
||||
|
||||
// Footer global
|
||||
await payload.updateGlobal({
|
||||
slug: 'footer',
|
||||
data: { copyrightText: `© Шуміленд ${new Date().getFullYear()}` } as never,
|
||||
overrideAccess: true,
|
||||
})
|
||||
console.log('Seeded footer global')
|
||||
// Site settings
|
||||
await payload.updateGlobal({
|
||||
slug: 'site-settings',
|
||||
data: {
|
||||
siteName: 'Шуміленд',
|
||||
siteURL: process.env['NEXT_PUBLIC_SITE_URL'] ?? 'https://shumiland.ua',
|
||||
} as never,
|
||||
overrideAccess: true,
|
||||
})
|
||||
console.log('Seeded site-settings global')
|
||||
|
||||
// Site settings
|
||||
await payload.updateGlobal({
|
||||
slug: 'site-settings',
|
||||
data: {
|
||||
siteName: 'Шуміленд',
|
||||
siteURL: process.env['NEXT_PUBLIC_SITE_URL'] ?? 'https://shumiland.ua',
|
||||
} as never,
|
||||
overrideAccess: true,
|
||||
})
|
||||
console.log('Seeded site-settings global')
|
||||
|
||||
// Remaining globals — initialize empty
|
||||
for (const slug of ['checkout-page', 'thank-you-page'] as const) {
|
||||
try {
|
||||
await payload.updateGlobal({ slug, data: {} as never, overrideAccess: true })
|
||||
console.log(`Initialized global: ${slug}`)
|
||||
} catch (err) {
|
||||
console.warn(`Could not initialize global ${slug}:`, err)
|
||||
// Remaining globals — initialize empty
|
||||
for (const slug of ['checkout-page', 'thank-you-page'] as const) {
|
||||
try {
|
||||
await payload.updateGlobal({ slug, data: {} as never, overrideAccess: true })
|
||||
console.log(`Initialized global: ${slug}`)
|
||||
} catch (err) {
|
||||
console.warn(`Could not initialize global ${slug}:`, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -180,94 +197,98 @@ async function seed(): Promise<void> {
|
|||
console.log('Blog posts already exist, skipping.')
|
||||
}
|
||||
|
||||
// Tariffs — update to match Figma designs
|
||||
// Tariffs — seed only if none exist (never delete admin-managed tariffs)
|
||||
{
|
||||
// Delete old tariffs and re-seed with correct data
|
||||
const existing = await payload.find({ collection: 'tariffs', limit: 100, overrideAccess: true })
|
||||
for (const t of existing.docs) {
|
||||
await payload.delete({ collection: 'tariffs', id: t.id, overrideAccess: true })
|
||||
}
|
||||
const { totalDocs: tariffCount } = await payload.find({
|
||||
collection: 'tariffs',
|
||||
limit: 1,
|
||||
overrideAccess: true,
|
||||
})
|
||||
|
||||
const tariffs = [
|
||||
// Individual dino-park tickets (shown on both Dino and DyvoLis pages)
|
||||
{
|
||||
ezy_id: 1001,
|
||||
last_synced_name: 'Вхід до Динопарку',
|
||||
display_name: 'Вхід до Динопарку',
|
||||
last_synced_price: 300,
|
||||
category_tag: 'dyno',
|
||||
sort: 1,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
ezy_id: 1002,
|
||||
last_synced_name: 'Звичайна екскурсія',
|
||||
display_name: 'Звичайна екскурсія',
|
||||
last_synced_price: 150,
|
||||
category_tag: 'dyno',
|
||||
sort: 2,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
ezy_id: 1003,
|
||||
last_synced_name: 'Палеонтологічна екскурсія',
|
||||
display_name: 'Палеонтологічна екскурсія',
|
||||
last_synced_price: 300,
|
||||
category_tag: 'dyno',
|
||||
sort: 3,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
ezy_id: 1004,
|
||||
last_synced_name: 'ДиноРодо',
|
||||
display_name: 'ДиноРодо',
|
||||
last_synced_price: 50,
|
||||
category_tag: 'dyno',
|
||||
sort: 4,
|
||||
visible: true,
|
||||
},
|
||||
// Combo tickets
|
||||
{
|
||||
ezy_id: 3001,
|
||||
last_synced_name: 'Комбо на 1 людину',
|
||||
display_name: 'Комбо на 1 людину',
|
||||
last_synced_price: 600,
|
||||
category_tag: 'combo',
|
||||
sort: 1,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
ezy_id: 3002,
|
||||
last_synced_name: 'Комбо на 3 людини',
|
||||
display_name: 'Комбо на 3 людини',
|
||||
last_synced_price: 1500,
|
||||
category_tag: 'combo',
|
||||
sort: 2,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
ezy_id: 3003,
|
||||
last_synced_name: 'Комбо на 4 людини',
|
||||
display_name: 'Комбо на 4 людини',
|
||||
last_synced_price: 1800,
|
||||
category_tag: 'combo',
|
||||
sort: 3,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
ezy_id: 3004,
|
||||
last_synced_name: 'Комбо на 5 людин',
|
||||
display_name: 'Комбо на 5 людин',
|
||||
last_synced_price: 2000,
|
||||
category_tag: 'combo',
|
||||
sort: 4,
|
||||
visible: true,
|
||||
},
|
||||
]
|
||||
for (const t of tariffs) {
|
||||
await payload.create({ collection: 'tariffs', data: t as never, overrideAccess: true })
|
||||
if (tariffCount > 0) {
|
||||
console.log('Tariffs already exist, skipping.')
|
||||
} else {
|
||||
const tariffs = [
|
||||
// Individual dino-park tickets (shown on both Dino and DyvoLis pages)
|
||||
{
|
||||
ezy_id: 1001,
|
||||
last_synced_name: 'Вхід до Динопарку',
|
||||
display_name: 'Вхід до Динопарку',
|
||||
last_synced_price: 300,
|
||||
category_tag: 'dyno',
|
||||
sort: 1,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
ezy_id: 1002,
|
||||
last_synced_name: 'Звичайна екскурсія',
|
||||
display_name: 'Звичайна екскурсія',
|
||||
last_synced_price: 150,
|
||||
category_tag: 'dyno',
|
||||
sort: 2,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
ezy_id: 1003,
|
||||
last_synced_name: 'Палеонтологічна екскурсія',
|
||||
display_name: 'Палеонтологічна екскурсія',
|
||||
last_synced_price: 300,
|
||||
category_tag: 'dyno',
|
||||
sort: 3,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
ezy_id: 1004,
|
||||
last_synced_name: 'ДиноРодо',
|
||||
display_name: 'ДиноРодо',
|
||||
last_synced_price: 50,
|
||||
category_tag: 'dyno',
|
||||
sort: 4,
|
||||
visible: true,
|
||||
},
|
||||
// Combo tickets
|
||||
{
|
||||
ezy_id: 3001,
|
||||
last_synced_name: 'Комбо на 1 людину',
|
||||
display_name: 'Комбо на 1 людину',
|
||||
last_synced_price: 600,
|
||||
category_tag: 'combo',
|
||||
sort: 1,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
ezy_id: 3002,
|
||||
last_synced_name: 'Комбо на 3 людини',
|
||||
display_name: 'Комбо на 3 людини',
|
||||
last_synced_price: 1500,
|
||||
category_tag: 'combo',
|
||||
sort: 2,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
ezy_id: 3003,
|
||||
last_synced_name: 'Комбо на 4 людини',
|
||||
display_name: 'Комбо на 4 людини',
|
||||
last_synced_price: 1800,
|
||||
category_tag: 'combo',
|
||||
sort: 3,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
ezy_id: 3004,
|
||||
last_synced_name: 'Комбо на 5 людин',
|
||||
display_name: 'Комбо на 5 людин',
|
||||
last_synced_price: 2000,
|
||||
category_tag: 'combo',
|
||||
sort: 4,
|
||||
visible: true,
|
||||
},
|
||||
]
|
||||
for (const t of tariffs) {
|
||||
await payload.create({ collection: 'tariffs', data: t as never, overrideAccess: true })
|
||||
}
|
||||
console.log('Seeded tariffs')
|
||||
}
|
||||
console.log('Seeded tariffs (updated to match Figma)')
|
||||
}
|
||||
|
||||
// Locations
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue