fix: hook-based slug with Swedish chars, remove built-in hero from Pages, and more rich text fix
@ -1,2 +0,0 @@
|
|||||||
# Web Paylod CMS testing
|
|
||||||
|
|
||||||
44
Todo - Updates.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Web Paylod CMS testing
|
||||||
|
|
||||||
|
|
||||||
|
## Comments on what to fix
|
||||||
|
|
||||||
|
Hero should default to none, or we should try to remove it!
|
||||||
|
|
||||||
|
Preview thumbnails for blocks ??
|
||||||
|
|
||||||
|
Can we get filler text in blocks as standard ?
|
||||||
|
|
||||||
|
Why is slug defaulting to one letter?
|
||||||
|
|
||||||
|
Fix corners and embed for video block
|
||||||
|
|
||||||
|
Fix posts formatting to be better
|
||||||
|
|
||||||
|
FAQ is not rendering answer text
|
||||||
|
|
||||||
|
Where does the form submission text come from ???
|
||||||
|
|
||||||
|
Skicka förfrågan forms button needs to be updated
|
||||||
|
|
||||||
|
A CTA block without Image
|
||||||
|
|
||||||
|
Change the cookies banner to full screen width instead of rounded corners floating
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Funktionalitet
|
||||||
|
|
||||||
|
#### Subscribe to newsletters, connection to API GANL
|
||||||
|
|
||||||
|
#### Få en offert (Lime, GANL, epost?)
|
||||||
|
|
||||||
|
#### Forms generellt ?
|
||||||
|
|
||||||
|
#### Matomo Tracking
|
||||||
|
|
||||||
|
#### Cookies consent
|
||||||
|
|
||||||
|
#### Lime forms integration
|
||||||
|
|
||||||
|
#### Other code embedding
|
||||||
243
fix-ts-errors.sh
@ -1,243 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Run from the root of your fdweb2 project
|
|
||||||
set -e
|
|
||||||
cd "$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
||||||
|
|
||||||
echo "=== FD TypeScript Error Fix Script ==="
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
# GROUP 1: Remove dead template block imports from RenderBlocks
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
RENDER_BLOCKS="src/app/(frontend)/(pages)/[slug]/RenderBlocks.tsx"
|
|
||||||
# Try alternate path if first doesn't exist
|
|
||||||
if [ ! -f "$RENDER_BLOCKS" ]; then
|
|
||||||
RENDER_BLOCKS=$(find src -name "RenderBlocks.tsx" | head -1)
|
|
||||||
fi
|
|
||||||
echo "→ Fixing RenderBlocks.tsx at: $RENDER_BLOCKS"
|
|
||||||
|
|
||||||
# Remove dead template block imports (leave all FD* blocks intact)
|
|
||||||
sed -i '' \
|
|
||||||
'/^import { ArchiveBlock } from/d' \
|
|
||||||
"$RENDER_BLOCKS"
|
|
||||||
|
|
||||||
sed -i '' \
|
|
||||||
'/^import { CallToActionBlock } from/d' \
|
|
||||||
"$RENDER_BLOCKS"
|
|
||||||
|
|
||||||
sed -i '' \
|
|
||||||
'/^import { ContentBlock } from/d' \
|
|
||||||
"$RENDER_BLOCKS"
|
|
||||||
|
|
||||||
sed -i '' \
|
|
||||||
'/^import { FormBlock } from/d' \
|
|
||||||
"$RENDER_BLOCKS"
|
|
||||||
|
|
||||||
sed -i '' \
|
|
||||||
'/^import { MediaBlock } from/d' \
|
|
||||||
"$RENDER_BLOCKS"
|
|
||||||
|
|
||||||
# Remove corresponding entries from blockComponents object
|
|
||||||
sed -i '' \
|
|
||||||
'/^ archive: ArchiveBlock,/d' \
|
|
||||||
"$RENDER_BLOCKS"
|
|
||||||
|
|
||||||
sed -i '' \
|
|
||||||
'/^ cta: CallToActionBlock,/d' \
|
|
||||||
"$RENDER_BLOCKS"
|
|
||||||
|
|
||||||
sed -i '' \
|
|
||||||
'/^ content: ContentBlock,/d' \
|
|
||||||
"$RENDER_BLOCKS"
|
|
||||||
|
|
||||||
sed -i '' \
|
|
||||||
'/^ formBlock: FormBlock,/d' \
|
|
||||||
"$RENDER_BLOCKS"
|
|
||||||
|
|
||||||
sed -i '' \
|
|
||||||
'/^ mediaBlock: MediaBlock,/d' \
|
|
||||||
"$RENDER_BLOCKS"
|
|
||||||
|
|
||||||
echo " ✓ Removed 5 dead template block imports and blockComponent entries"
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
# GROUP 2: Fix CallToActionBlock import in RichText
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
RICH_TEXT="src/components/RichText/index.tsx"
|
|
||||||
if [ -f "$RICH_TEXT" ]; then
|
|
||||||
# Remove CallToActionBlock from the payload-types import
|
|
||||||
sed -i '' \
|
|
||||||
's/import type { CallToActionBlock } from '\''@\/payload-types'\''/\/\/ CallToActionBlock removed - not in schema/' \
|
|
||||||
"$RICH_TEXT"
|
|
||||||
# More general: remove just the named import if it's part of a multi-import
|
|
||||||
sed -i '' \
|
|
||||||
's/, CallToActionBlock//' \
|
|
||||||
"$RICH_TEXT"
|
|
||||||
sed -i '' \
|
|
||||||
's/CallToActionBlock, //' \
|
|
||||||
"$RICH_TEXT"
|
|
||||||
echo " ✓ Removed CallToActionBlock from RichText"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
# GROUP 3: Fix null safety in FD block components
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
echo ""
|
|
||||||
echo "→ Fixing null safety issues in FD blocks..."
|
|
||||||
|
|
||||||
# FDLocationsGridBlock - cards is possibly null
|
|
||||||
LOCATIONS="src/blocks/FDLocationsGridBlock/Component.tsx"
|
|
||||||
if [ -f "$LOCATIONS" ]; then
|
|
||||||
# Change: cards.map( → (cards ?? []).map(
|
|
||||||
sed -i '' \
|
|
||||||
's/cards\.map(/\(cards ?? []\)\.map(/g' \
|
|
||||||
"$LOCATIONS"
|
|
||||||
echo " ✓ FDLocationsGridBlock: cards null check"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# FDNewsletterBlock - bulletPoints is possibly null
|
|
||||||
NEWSLETTER="src/blocks/FDNewsletterBlock/Component.tsx"
|
|
||||||
if [ -f "$NEWSLETTER" ]; then
|
|
||||||
sed -i '' \
|
|
||||||
's/bulletPoints\.map(/\(bulletPoints ?? []\)\.map(/g' \
|
|
||||||
"$NEWSLETTER"
|
|
||||||
sed -i '' \
|
|
||||||
's/bulletPoints\.length/\(bulletPoints ?? []\)\.length/g' \
|
|
||||||
"$NEWSLETTER"
|
|
||||||
# Fix conditional renders: bulletPoints && → bulletPoints?.length &&
|
|
||||||
sed -i '' \
|
|
||||||
's/bulletPoints &&/bulletPoints?.length \&\&/g' \
|
|
||||||
"$NEWSLETTER"
|
|
||||||
echo " ✓ FDNewsletterBlock: bulletPoints null check"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# FDServiceChooserBlock - categories is possibly null
|
|
||||||
SERVICE_CHOOSER="src/blocks/FDServiceChooserBlock/Component.tsx"
|
|
||||||
if [ -f "$SERVICE_CHOOSER" ]; then
|
|
||||||
sed -i '' \
|
|
||||||
's/categories\.map(/\(categories ?? []\)\.map(/g' \
|
|
||||||
"$SERVICE_CHOOSER"
|
|
||||||
sed -i '' \
|
|
||||||
's/categories\.filter(/\(categories ?? []\)\.filter(/g' \
|
|
||||||
"$SERVICE_CHOOSER"
|
|
||||||
sed -i '' \
|
|
||||||
's/categories\.find(/\(categories ?? []\)\.find(/g' \
|
|
||||||
"$SERVICE_CHOOSER"
|
|
||||||
sed -i '' \
|
|
||||||
's/categories\.length/\(categories ?? []\)\.length/g' \
|
|
||||||
"$SERVICE_CHOOSER"
|
|
||||||
echo " ✓ FDServiceChooserBlock: categories null check"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# FDStatisticsBlock - stats is possibly null
|
|
||||||
STATISTICS="src/blocks/FDStatisticsBlock/Component.tsx"
|
|
||||||
if [ -f "$STATISTICS" ]; then
|
|
||||||
sed -i '' \
|
|
||||||
's/stats\.map(/\(stats ?? []\)\.map(/g' \
|
|
||||||
"$STATISTICS"
|
|
||||||
sed -i '' \
|
|
||||||
's/stats\.length/\(stats ?? []\)\.length/g' \
|
|
||||||
"$STATISTICS"
|
|
||||||
echo " ✓ FDStatisticsBlock: stats null check"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
# GROUP 4: Fix revalidatePath — Next.js now requires 2nd arg
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
echo ""
|
|
||||||
echo "→ Fixing revalidatePath calls (adding 'page' as second argument)..."
|
|
||||||
|
|
||||||
REVALIDATE_FILES=(
|
|
||||||
"src/collections/Pages/hooks/revalidatePage.ts"
|
|
||||||
"src/collections/Posts/hooks/revalidatePost.ts"
|
|
||||||
"src/Footer/hooks/revalidateFooter.ts"
|
|
||||||
"src/Header/hooks/revalidateHeader.ts"
|
|
||||||
"src/globals/PopupAnnouncement/hooks/revalidatePopup.ts"
|
|
||||||
"src/hooks/revalidateRedirects.ts"
|
|
||||||
)
|
|
||||||
|
|
||||||
for FILE in "${REVALIDATE_FILES[@]}"; do
|
|
||||||
if [ -f "$FILE" ]; then
|
|
||||||
# revalidatePath('/some/path') → revalidatePath('/some/path', 'page')
|
|
||||||
# Match revalidatePath with a single string arg (no comma inside the parens)
|
|
||||||
sed -i '' \
|
|
||||||
"s/revalidatePath('\([^']*\)')/revalidatePath('\1', 'page')/g" \
|
|
||||||
"$FILE"
|
|
||||||
sed -i '' \
|
|
||||||
's/revalidatePath("\([^"]*\)")/revalidatePath("\1", "page")/g' \
|
|
||||||
"$FILE"
|
|
||||||
# Handle template literals: revalidatePath(\`...\`) → revalidatePath(\`...\`, 'page')
|
|
||||||
# This one is trickier with backticks, handle separately
|
|
||||||
perl -i '' -pe 's/revalidatePath\(`([^`]*)`\)/revalidatePath(`$1`, '\''page'\'')/g' "$FILE" 2>/dev/null || true
|
|
||||||
echo " ✓ $FILE"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
# GROUP 5: Delete BACKUP file (it's causing compilation errors)
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
echo ""
|
|
||||||
echo "→ Removing backup files from compilation..."
|
|
||||||
|
|
||||||
BACKUP="src/Header/Nav/index BACKUP.tsx"
|
|
||||||
if [ -f "$BACKUP" ]; then
|
|
||||||
rm "$BACKUP"
|
|
||||||
echo " ✓ Deleted 'src/Header/Nav/index BACKUP.tsx'"
|
|
||||||
else
|
|
||||||
echo " - BACKUP file not found (already removed?)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
# GROUP 6: Fix Footer/Header getCachedGlobal type cast
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
echo ""
|
|
||||||
echo "→ Fixing Footer and Header getCachedGlobal type cast..."
|
|
||||||
|
|
||||||
FOOTER_COMPONENT="src/Footer/Component.tsx"
|
|
||||||
if [ -f "$FOOTER_COMPONENT" ]; then
|
|
||||||
# Add 'as Footer' cast to getCachedGlobal call
|
|
||||||
sed -i '' \
|
|
||||||
"s/const \(.*\) = await getCachedGlobal('footer'/const \1 = (await getCachedGlobal('footer'/" \
|
|
||||||
"$FOOTER_COMPONENT"
|
|
||||||
echo " ⚠ Footer/Component.tsx needs manual fix — see note below"
|
|
||||||
fi
|
|
||||||
|
|
||||||
HEADER_COMPONENT="src/Header/Component.tsx"
|
|
||||||
if [ -f "$HEADER_COMPONENT" ]; then
|
|
||||||
echo " ⚠ Header/Component.tsx needs manual fix — see note below"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
# DONE
|
|
||||||
# ─────────────────────────────────────────────────────────────
|
|
||||||
echo ""
|
|
||||||
echo "=== Script complete ==="
|
|
||||||
echo ""
|
|
||||||
echo "MANUAL FIXES STILL NEEDED:"
|
|
||||||
echo ""
|
|
||||||
echo "1. FDTagsBlock and FDTextBlock missing from payload-types:"
|
|
||||||
echo " → Run: npx payload generate:types"
|
|
||||||
echo " → If still missing, check that FDTagsBlock and FDTextBlock"
|
|
||||||
echo " are imported and added to the Pages collection layout field"
|
|
||||||
echo " in src/collections/Pages/index.ts"
|
|
||||||
echo ""
|
|
||||||
echo "2. Footer/Component.tsx and Header/Component.tsx type mismatch:"
|
|
||||||
echo " → Change the getCachedGlobal line to add a type cast, e.g.:"
|
|
||||||
echo " const footerData = await getCachedGlobal('footer', 1) as Footer"
|
|
||||||
echo " const headerData = await getCachedGlobal('header', 1) as Header"
|
|
||||||
echo ""
|
|
||||||
echo "3. Footer/RowLabel.tsx and Header/RowLabel.tsx — 'link' property:"
|
|
||||||
echo " → Change: data.link?.label"
|
|
||||||
echo " To: data.label (the nav item schema changed, link is now flat)"
|
|
||||||
echo ""
|
|
||||||
echo "4. Media.caption doesn't exist — removed from your schema:"
|
|
||||||
echo " → In MediaBlock/Component.tsx line 33: remove the .caption reference"
|
|
||||||
echo " → In heros/MediumImpact/index.tsx lines 36/38: remove .caption"
|
|
||||||
echo " → In src/endpoints/seed/image-*.ts: remove caption field"
|
|
||||||
echo ""
|
|
||||||
echo "5. Seed files (contact-page.ts, home.ts, index.ts):"
|
|
||||||
echo " → These are dev seeds, not used in production."
|
|
||||||
echo " → Quickest fix: add // @ts-ignore above each flagged line,"
|
|
||||||
echo " or delete the seed files if you no longer use them."
|
|
||||||
echo ""
|
|
||||||
echo "After manual fixes, run: npx tsc --noEmit to verify"
|
|
||||||
213
fix2.py
@ -1,213 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""Fix remaining TypeScript errors in fdweb2 project."""
|
|
||||||
import os, re, sys
|
|
||||||
|
|
||||||
def read(path):
|
|
||||||
with open(path, 'r') as f: return f.read()
|
|
||||||
|
|
||||||
def write(path, content):
|
|
||||||
with open(path, 'w') as f: f.write(content)
|
|
||||||
print(f" ✓ {path}")
|
|
||||||
|
|
||||||
def prepend_nocheck(path):
|
|
||||||
if not os.path.exists(path): return
|
|
||||||
content = read(path)
|
|
||||||
if '// @ts-nocheck' not in content:
|
|
||||||
write(path, '// @ts-nocheck\n' + content)
|
|
||||||
|
|
||||||
# ── 1. Add @ts-nocheck to old template blocks we don't use ───────────────
|
|
||||||
print("\n→ Suppressing old template block errors...")
|
|
||||||
for p in [
|
|
||||||
'src/blocks/ArchiveBlock/Component.tsx',
|
|
||||||
'src/blocks/CallToAction/Component.tsx',
|
|
||||||
'src/blocks/Content/Component.tsx',
|
|
||||||
'src/blocks/MediaBlock/Component.tsx',
|
|
||||||
]:
|
|
||||||
prepend_nocheck(p)
|
|
||||||
|
|
||||||
# ── 2. Add @ts-nocheck to seed files ─────────────────────────────────────
|
|
||||||
print("\n→ Suppressing seed file errors...")
|
|
||||||
for p in [
|
|
||||||
'src/endpoints/seed/contact-page.ts',
|
|
||||||
'src/endpoints/seed/home.ts',
|
|
||||||
'src/endpoints/seed/image-1.ts',
|
|
||||||
'src/endpoints/seed/image-2.ts',
|
|
||||||
'src/endpoints/seed/image-3.ts',
|
|
||||||
'src/endpoints/seed/index.ts',
|
|
||||||
]:
|
|
||||||
prepend_nocheck(p)
|
|
||||||
|
|
||||||
# ── 3. Fix revalidatePath — add 'page' second argument ───────────────────
|
|
||||||
print("\n→ Fixing revalidatePath calls...")
|
|
||||||
revalidate_files = [
|
|
||||||
'src/collections/Pages/hooks/revalidatePage.ts',
|
|
||||||
'src/collections/Posts/hooks/revalidatePost.ts',
|
|
||||||
'src/Footer/hooks/revalidateFooter.ts',
|
|
||||||
'src/Header/hooks/revalidateHeader.ts',
|
|
||||||
'src/globals/PopupAnnouncement/hooks/revalidatePopup.ts',
|
|
||||||
'src/hooks/revalidateRedirects.ts',
|
|
||||||
]
|
|
||||||
# Match revalidatePath(anything) where there's no second arg
|
|
||||||
# i.e. revalidatePath( <stuff> ) with no comma at top level inside parens
|
|
||||||
pattern = re.compile(r'revalidatePath\(([^,)]+)\)')
|
|
||||||
def add_page_arg(m):
|
|
||||||
inner = m.group(1).strip()
|
|
||||||
return f"revalidatePath({inner}, 'page')"
|
|
||||||
|
|
||||||
for path in revalidate_files:
|
|
||||||
if not os.path.exists(path): continue
|
|
||||||
content = read(path)
|
|
||||||
new_content = pattern.sub(add_page_arg, content)
|
|
||||||
if new_content != content:
|
|
||||||
write(path, new_content)
|
|
||||||
else:
|
|
||||||
print(f" - No match in {path} (may already be fixed)")
|
|
||||||
|
|
||||||
# ── 4. Fix Pages/index.ts — add FDTagsBlock + FDTextBlock to layout ──────
|
|
||||||
print("\n→ Fixing Pages/index.ts block registrations...")
|
|
||||||
pages_path = 'src/collections/Pages/index.ts'
|
|
||||||
if os.path.exists(pages_path):
|
|
||||||
content = read(pages_path)
|
|
||||||
|
|
||||||
# Add FDTextBlock import if missing
|
|
||||||
if 'FDTextBlock' not in content:
|
|
||||||
content = content.replace(
|
|
||||||
"import { FDTagsBlock } from '../../blocks/FDTagsBlock/config'",
|
|
||||||
"import { FDTagsBlock } from '../../blocks/FDTagsBlock/config'\nimport { FDTextBlock } from '../../blocks/FDTextBlock/config'"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add FDTagsBlock and FDTextBlock to blocks array if missing
|
|
||||||
if 'FDTagsBlock' not in content.split('blocks: [')[1].split(']')[0]:
|
|
||||||
content = content.replace(
|
|
||||||
'FDVpsCalculatorBlock]',
|
|
||||||
'FDVpsCalculatorBlock, FDTagsBlock, FDTextBlock]'
|
|
||||||
)
|
|
||||||
elif 'FDTextBlock' not in content.split('blocks: [')[1].split(']')[0]:
|
|
||||||
content = content.replace(
|
|
||||||
'FDVpsCalculatorBlock]',
|
|
||||||
'FDVpsCalculatorBlock, FDTextBlock]'
|
|
||||||
)
|
|
||||||
|
|
||||||
write(pages_path, content)
|
|
||||||
|
|
||||||
# ── 5. Fix Footer/Component.tsx — add type cast ───────────────────────────
|
|
||||||
print("\n→ Fixing Footer/Component.tsx type cast...")
|
|
||||||
footer_path = 'src/Footer/Component.tsx'
|
|
||||||
if os.path.exists(footer_path):
|
|
||||||
content = read(footer_path)
|
|
||||||
# Add Footer import if needed and cast the getCachedGlobal result
|
|
||||||
# Pattern: const X = await getCachedGlobal('footer', ...)
|
|
||||||
new = re.sub(
|
|
||||||
r"(const\s+\w+\s*=\s*await getCachedGlobal\('footer'[^)]*\))",
|
|
||||||
r"\1 as Footer",
|
|
||||||
content
|
|
||||||
)
|
|
||||||
if new == content:
|
|
||||||
# Try without await
|
|
||||||
new = re.sub(
|
|
||||||
r"(getCachedGlobal\('footer'[^)]*\))",
|
|
||||||
r"(\1 as Footer)",
|
|
||||||
content
|
|
||||||
)
|
|
||||||
if new != content:
|
|
||||||
write(footer_path, new)
|
|
||||||
else:
|
|
||||||
print(f" ⚠ Footer/Component.tsx — pattern not matched, needs manual fix")
|
|
||||||
|
|
||||||
# ── 6. Fix Header/Component.tsx — add type cast ───────────────────────────
|
|
||||||
print("\n→ Fixing Header/Component.tsx type cast...")
|
|
||||||
header_path = 'src/Header/Component.tsx'
|
|
||||||
if os.path.exists(header_path):
|
|
||||||
content = read(header_path)
|
|
||||||
new = re.sub(
|
|
||||||
r"(const\s+\w+\s*=\s*await getCachedGlobal\('header'[^)]*\))",
|
|
||||||
r"\1 as Header",
|
|
||||||
content
|
|
||||||
)
|
|
||||||
if new == content:
|
|
||||||
new = re.sub(
|
|
||||||
r"(getCachedGlobal\('header'[^)]*\))",
|
|
||||||
r"(\1 as Header)",
|
|
||||||
content
|
|
||||||
)
|
|
||||||
if new != content:
|
|
||||||
write(header_path, new)
|
|
||||||
else:
|
|
||||||
print(f" ⚠ Header/Component.tsx — pattern not matched, needs manual fix")
|
|
||||||
|
|
||||||
# ── 7. Fix RowLabel files — .link property doesn't exist ─────────────────
|
|
||||||
print("\n→ Fixing RowLabel files...")
|
|
||||||
for path in ['src/Footer/RowLabel.tsx', 'src/Header/RowLabel.tsx']:
|
|
||||||
if not os.path.exists(path): continue
|
|
||||||
content = read(path)
|
|
||||||
# data.link.label → data.label
|
|
||||||
# data.link.url → data.url
|
|
||||||
new = content.replace('.link.label', '.label').replace('.link.url', '.url').replace('.link?.label', '.label').replace('.link?.url', '.url')
|
|
||||||
if new != content:
|
|
||||||
write(path, new)
|
|
||||||
else:
|
|
||||||
print(f" ⚠ {path} — pattern not matched, needs manual fix")
|
|
||||||
|
|
||||||
# ── 8. Fix MediaBlock caption ─────────────────────────────────────────────
|
|
||||||
print("\n→ Fixing MediaBlock/Component.tsx caption property...")
|
|
||||||
media_block = 'src/blocks/MediaBlock/Component.tsx'
|
|
||||||
if os.path.exists(media_block):
|
|
||||||
content = read(media_block)
|
|
||||||
# Cast media to any to access caption, or just remove it
|
|
||||||
new = re.sub(r'\(media as Media\)\.caption', '(media as any).caption', content)
|
|
||||||
new = re.sub(r'media\.caption', '(media as any).caption', new)
|
|
||||||
if new != content:
|
|
||||||
write(media_block, new)
|
|
||||||
|
|
||||||
# ── 9. Fix heros/MediumImpact caption ────────────────────────────────────
|
|
||||||
print("\n→ Fixing heros/MediumImpact/index.tsx caption property...")
|
|
||||||
medium_impact = 'src/heros/MediumImpact/index.tsx'
|
|
||||||
if os.path.exists(medium_impact):
|
|
||||||
content = read(medium_impact)
|
|
||||||
new = re.sub(r'\(media as Media\)\.caption', '(media as any).caption', content)
|
|
||||||
new = re.sub(r'(?<!\(media as any\))media\.caption', '(media as any).caption', new)
|
|
||||||
if new != content:
|
|
||||||
write(medium_impact, new)
|
|
||||||
|
|
||||||
# ── 10. Fix generateMeta.ts — .og doesn't exist ──────────────────────────
|
|
||||||
print("\n→ Fixing generateMeta.ts og property...")
|
|
||||||
meta_path = 'src/utilities/generateMeta.ts'
|
|
||||||
if os.path.exists(meta_path):
|
|
||||||
content = read(meta_path)
|
|
||||||
# Cast the image to any to access og
|
|
||||||
new = re.sub(r'(\w+)\.og\b', r'(\1 as any).og', content)
|
|
||||||
if new != content:
|
|
||||||
write(meta_path, new)
|
|
||||||
|
|
||||||
# ── 11. Fix FDServiceChooserBlock categories null ────────────────────────
|
|
||||||
print("\n→ Fixing FDServiceChooserBlock categories null...")
|
|
||||||
svc_path = 'src/blocks/FDServiceChooserBlock/Component.tsx'
|
|
||||||
if os.path.exists(svc_path):
|
|
||||||
content = read(svc_path)
|
|
||||||
# Any remaining direct categories. access
|
|
||||||
new = re.sub(r'(?<!\?\? \[\]\))categories\.map\(', '(categories ?? []).map(', content)
|
|
||||||
new = re.sub(r'(?<!\?\? \[\]\))categories\.filter\(', '(categories ?? []).filter(', new)
|
|
||||||
new = re.sub(r'(?<!\?\? \[\]\))categories\.find\(', '(categories ?? []).find(', new)
|
|
||||||
new = re.sub(r'(?<!\?\? \[\]\))categories\.length', '(categories ?? []).length', new)
|
|
||||||
# Handle line 31 which may be something like: if (categories && categories[
|
|
||||||
new = re.sub(r'\bcategories\[', '(categories ?? [])[', new)
|
|
||||||
if new != content:
|
|
||||||
write(svc_path, new)
|
|
||||||
|
|
||||||
# ── 12. Fix RichText CallToActionBlock import ─────────────────────────────
|
|
||||||
print("\n→ Fixing RichText CallToActionBlock import...")
|
|
||||||
richtext = 'src/components/RichText/index.tsx'
|
|
||||||
if os.path.exists(richtext):
|
|
||||||
content = read(richtext)
|
|
||||||
# Remove CallToActionBlock from any import line
|
|
||||||
new = re.sub(r',\s*CallToActionBlock', '', content)
|
|
||||||
new = re.sub(r'CallToActionBlock,\s*', '', new)
|
|
||||||
# If it was the only import, remove the whole import line
|
|
||||||
new = re.sub(r"import type \{ \} from '@/payload-types'\n?", '', new)
|
|
||||||
if new != content:
|
|
||||||
write(richtext, new)
|
|
||||||
|
|
||||||
print("\n=== Done! ===")
|
|
||||||
print("\nNow run:")
|
|
||||||
print(" npx payload generate:types")
|
|
||||||
print(" npx tsc --noEmit 2>&1 | grep 'error TS'")
|
|
||||||
109
fix3.py
@ -1,109 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""Fix all remaining TypeScript errors."""
|
|
||||||
import os, re
|
|
||||||
|
|
||||||
def read(path):
|
|
||||||
with open(path, 'r') as f: return f.read()
|
|
||||||
|
|
||||||
def write(path, content):
|
|
||||||
with open(path, 'w') as f: f.write(content)
|
|
||||||
print(f" ✓ {path}")
|
|
||||||
|
|
||||||
# ── 1. revalidateTag needs 2 args in Next.js 16 — suppress with cast ──────
|
|
||||||
print("\n→ Fixing revalidateTag calls...")
|
|
||||||
revalidate_tag_files = [
|
|
||||||
'src/collections/Pages/hooks/revalidatePage.ts',
|
|
||||||
'src/collections/Posts/hooks/revalidatePost.ts',
|
|
||||||
'src/Footer/hooks/revalidateFooter.ts',
|
|
||||||
'src/Header/hooks/revalidateHeader.ts',
|
|
||||||
'src/globals/PopupAnnouncement/hooks/revalidatePopup.ts',
|
|
||||||
'src/hooks/revalidateRedirects.ts',
|
|
||||||
]
|
|
||||||
for path in revalidate_tag_files:
|
|
||||||
if not os.path.exists(path): continue
|
|
||||||
content = read(path)
|
|
||||||
# Replace revalidateTag('anything') with (revalidateTag as any)('anything')
|
|
||||||
new = re.sub(r'\brevalidateTag\(', '(revalidateTag as any)(', content)
|
|
||||||
if new != content:
|
|
||||||
write(path, new)
|
|
||||||
|
|
||||||
# ── 2. Fix Footer/Component.tsx — python script broke the cast ────────────
|
|
||||||
print("\n→ Fixing Footer/Component.tsx getCachedGlobal cast...")
|
|
||||||
footer_path = 'src/Footer/Component.tsx'
|
|
||||||
if os.path.exists(footer_path):
|
|
||||||
content = read(footer_path)
|
|
||||||
# Fix the broken: await (getCachedGlobal('footer', 1) as Footer)()
|
|
||||||
new = re.sub(
|
|
||||||
r'await \(getCachedGlobal\(([^)]+)\) as Footer\)\(\)',
|
|
||||||
r'await getCachedGlobal(\1) as unknown as Footer',
|
|
||||||
content
|
|
||||||
)
|
|
||||||
# Also fix if it got the type annotation wrong
|
|
||||||
new = re.sub(
|
|
||||||
r'const footerData: Footer =',
|
|
||||||
'const footerData =',
|
|
||||||
new
|
|
||||||
)
|
|
||||||
if new != content:
|
|
||||||
write(footer_path, new)
|
|
||||||
|
|
||||||
# ── 3. Fix Header/Component.tsx — same broken cast ────────────────────────
|
|
||||||
print("\n→ Fixing Header/Component.tsx getCachedGlobal cast...")
|
|
||||||
header_path = 'src/Header/Component.tsx'
|
|
||||||
if os.path.exists(header_path):
|
|
||||||
content = read(header_path)
|
|
||||||
new = re.sub(
|
|
||||||
r'await \(getCachedGlobal\(([^)]+)\) as Header\)\(\)',
|
|
||||||
r'await getCachedGlobal(\1) as unknown as Header',
|
|
||||||
content
|
|
||||||
)
|
|
||||||
new = re.sub(
|
|
||||||
r'const headerData: Header =',
|
|
||||||
'const headerData =',
|
|
||||||
new
|
|
||||||
)
|
|
||||||
if new != content:
|
|
||||||
write(header_path, new)
|
|
||||||
|
|
||||||
# ── 4. Fix RichText — CTABlockProps and CallToActionBlock still referenced ─
|
|
||||||
print("\n→ Fixing RichText/index.tsx...")
|
|
||||||
richtext_path = 'src/components/RichText/index.tsx'
|
|
||||||
if os.path.exists(richtext_path):
|
|
||||||
content = read(richtext_path)
|
|
||||||
# Remove CTABlockProps from the SerializedBlockNode union type
|
|
||||||
new = re.sub(r'CTABlockProps \| ', '', content)
|
|
||||||
new = re.sub(r' \| CTABlockProps', '', new)
|
|
||||||
new = re.sub(r'CTABlockProps', '', new)
|
|
||||||
# Replace <CallToActionBlock ... /> usage with a null render
|
|
||||||
new = re.sub(
|
|
||||||
r"cta: \(\{ node \}\) => <CallToActionBlock \{\.\.\.node\.fields\} />",
|
|
||||||
"cta: () => null",
|
|
||||||
new
|
|
||||||
)
|
|
||||||
# Remove the import line if still present
|
|
||||||
new = re.sub(r"import \{ CallToActionBlock \} from '@/blocks/CallToAction/Component'\n", '', new)
|
|
||||||
if new != content:
|
|
||||||
write(richtext_path, new)
|
|
||||||
|
|
||||||
# ── 5. Fix MediumImpact hero — caption doesn't exist on Media ─────────────
|
|
||||||
print("\n→ Fixing heros/MediumImpact/index.tsx caption...")
|
|
||||||
medium_path = 'src/heros/MediumImpact/index.tsx'
|
|
||||||
if os.path.exists(medium_path):
|
|
||||||
content = read(medium_path)
|
|
||||||
# Cast media to any where .caption is accessed
|
|
||||||
new = re.sub(r'media(\??)\.(caption)', r'(media as any)\1.\2', content)
|
|
||||||
if new != content:
|
|
||||||
write(medium_path, new)
|
|
||||||
|
|
||||||
# ── 6. Fix generateMeta.ts — og size doesn't exist ───────────────────────
|
|
||||||
print("\n→ Fixing utilities/generateMeta.ts og size...")
|
|
||||||
meta_path = 'src/utilities/generateMeta.ts'
|
|
||||||
if os.path.exists(meta_path):
|
|
||||||
content = read(meta_path)
|
|
||||||
# Cast image.sizes to any
|
|
||||||
new = re.sub(r'image\.sizes(\??)\.(og)', r'(image as any).sizes\1.\2', content)
|
|
||||||
if new != content:
|
|
||||||
write(meta_path, new)
|
|
||||||
|
|
||||||
print("\n=== Done! ===")
|
|
||||||
print("\nRun: npx tsc --noEmit")
|
|
||||||
38
fix4.py
@ -1,38 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
import os, re
|
|
||||||
|
|
||||||
def read(path):
|
|
||||||
with open(path, 'r') as f: return f.read()
|
|
||||||
|
|
||||||
def write(path, content):
|
|
||||||
with open(path, 'w') as f: f.write(content)
|
|
||||||
print(f" ✓ {path}")
|
|
||||||
|
|
||||||
# Fix 1: revalidatePath cast to any (Next.js 16 types it as possibly undefined)
|
|
||||||
# Fix 2: logger.info`...`) → logger.info(`...`)
|
|
||||||
files = [
|
|
||||||
'src/collections/Pages/hooks/revalidatePage.ts',
|
|
||||||
'src/collections/Posts/hooks/revalidatePost.ts',
|
|
||||||
'src/Footer/hooks/revalidateFooter.ts',
|
|
||||||
'src/Header/hooks/revalidateHeader.ts',
|
|
||||||
'src/hooks/revalidateRedirects.ts',
|
|
||||||
'src/globals/PopupAnnouncement/hooks/revalidatePopup.ts',
|
|
||||||
]
|
|
||||||
|
|
||||||
for path in files:
|
|
||||||
if not os.path.exists(path): continue
|
|
||||||
content = read(path)
|
|
||||||
|
|
||||||
# Fix revalidatePath(x, 'page') → (revalidatePath as any)(x, 'page')
|
|
||||||
new = re.sub(r'\brevalidatePath\(', '(revalidatePath as any)(', content)
|
|
||||||
|
|
||||||
# Fix broken logger.info`...`) → logger.info(`...`)
|
|
||||||
# Pattern: .info`some text ${var}`) → .info(`some text ${var}`)
|
|
||||||
new = re.sub(r'\.info`([^`]*)`\)', r'.info(`\1`)', new)
|
|
||||||
|
|
||||||
if new != content:
|
|
||||||
write(path, new)
|
|
||||||
else:
|
|
||||||
print(f" - no changes: {path}")
|
|
||||||
|
|
||||||
print("\nDone. Run: npx tsc --noEmit")
|
|
||||||
72
fix_final.py
@ -1,72 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
import re
|
|
||||||
|
|
||||||
# Fix 1: Clean up debug globals in payload.config.ts
|
|
||||||
path = 'src/payload.config.ts'
|
|
||||||
with open(path) as f: c = f.read()
|
|
||||||
|
|
||||||
old = """ globals: (() => {
|
|
||||||
const g = [Header, Footer, AnnouncementBar, PopupAnnouncement]
|
|
||||||
g.forEach((x, i) => { if (!x || !x.slug) console.error('UNDEFINED GLOBAL at index', i, ':', ['Header','Footer','AnnouncementBar','PopupAnnouncement'][i]) })
|
|
||||||
return g.filter(x => x && x.slug)
|
|
||||||
})(),"""
|
|
||||||
|
|
||||||
new = " globals: [Header, Footer, AnnouncementBar, PopupAnnouncement],"
|
|
||||||
|
|
||||||
if old in c:
|
|
||||||
c = c.replace(old, new)
|
|
||||||
with open(path, 'w') as f: f.write(c)
|
|
||||||
print('✓ Cleaned up globals debug code')
|
|
||||||
else:
|
|
||||||
print('⚠ Pattern not found in payload.config.ts - may already be clean')
|
|
||||||
for line in c.split('\n'):
|
|
||||||
if 'globals' in line:
|
|
||||||
print(' ', repr(line))
|
|
||||||
|
|
||||||
# Fix 2: Restore formBuilderPlugin in plugins/index.ts
|
|
||||||
path = 'src/plugins/index.ts'
|
|
||||||
with open(path) as f: c = f.read()
|
|
||||||
|
|
||||||
if 'formBuilderPlugin' not in c:
|
|
||||||
# Add import
|
|
||||||
c = c.replace(
|
|
||||||
"import { nestedDocsPlugin }",
|
|
||||||
"import { formBuilderPlugin } from '@payloadcms/plugin-form-builder'\nimport { FixedToolbarFeature, HeadingFeature, lexicalEditor } from '@payloadcms/richtext-lexical'\nimport { nestedDocsPlugin }"
|
|
||||||
)
|
|
||||||
# Add plugin before searchPlugin
|
|
||||||
c = c.replace(
|
|
||||||
" searchPlugin({",
|
|
||||||
""" formBuilderPlugin({
|
|
||||||
fields: {
|
|
||||||
payment: false,
|
|
||||||
},
|
|
||||||
formOverrides: {
|
|
||||||
fields: ({ defaultFields }) => {
|
|
||||||
return defaultFields.map((field) => {
|
|
||||||
if ('name' in field && field.name === 'confirmationMessage') {
|
|
||||||
return {
|
|
||||||
...field,
|
|
||||||
editor: lexicalEditor({
|
|
||||||
features: ({ rootFeatures }) => {
|
|
||||||
return [
|
|
||||||
...rootFeatures,
|
|
||||||
FixedToolbarFeature(),
|
|
||||||
HeadingFeature({ enabledHeadingSizes: ['h1', 'h2', 'h3', 'h4'] }),
|
|
||||||
]
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return field
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
searchPlugin({"""
|
|
||||||
)
|
|
||||||
with open(path, 'w') as f: f.write(c)
|
|
||||||
print('✓ Restored formBuilderPlugin')
|
|
||||||
else:
|
|
||||||
print('✓ formBuilderPlugin already present')
|
|
||||||
|
|
||||||
print('\nDone. Restart dev server.')
|
|
||||||
BIN
media/Stockholm-1200x671.webp
Normal file
|
After Width: | Height: | Size: 149 KiB |
BIN
media/Stockholm-1920x1073.webp
Normal file
|
After Width: | Height: | Size: 318 KiB |
BIN
media/Stockholm-400x224.webp
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
media/Stockholm-800x447.webp
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
media/Stockholm.png
Normal file
|
After Width: | Height: | Size: 4.3 MiB |
5
media/Text-file-data.csv
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Packages;SLA;Telefontime;Månadspris;Response
|
||||||
|
Fiber Basic 10 000;99,90%;kl 8-17; 1 195,00 kr ;Lots of details
|
||||||
|
Fiber Basic 10 000 Plus;99,90%;kl 8-17; 1 995,00 kr ;
|
||||||
|
Fiber Premium;99,90%;kl 8-17; 2 995,00 kr ;Lots of details
|
||||||
|
Fiber Platina;99,90%;kl 8-17; 4 995,00 kr ;
|
||||||
|
BIN
media/test-1200x671.webp
Normal file
|
After Width: | Height: | Size: 149 KiB |
BIN
media/test-1920x1073.webp
Normal file
|
After Width: | Height: | Size: 318 KiB |
BIN
media/test-400x224.webp
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
media/test-800x447.webp
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
media/test.png
Normal file
|
After Width: | Height: | Size: 4.3 MiB |
@ -60,7 +60,7 @@ export const FDFaqBlockComponent: React.FC<FDFaqBlockProps> = ({
|
|||||||
>
|
>
|
||||||
<div className="overflow-hidden">
|
<div className="overflow-hidden">
|
||||||
<div className={`font-joey text-fd-body pl-7 md:pl-9 fd-prose ${proseColor}`}>
|
<div className={`font-joey text-fd-body pl-7 md:pl-9 fd-prose ${proseColor}`}>
|
||||||
<RichText content={item.answer} />
|
<RichText data={item.answer} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
74
src/blocks/FDFaqBlock/FDFaqBlock-config.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import type { Block } from 'payload'
|
||||||
|
import {
|
||||||
|
lexicalEditor,
|
||||||
|
BoldFeature,
|
||||||
|
ItalicFeature,
|
||||||
|
UnderlineFeature,
|
||||||
|
LinkFeature,
|
||||||
|
UnorderedListFeature,
|
||||||
|
OrderedListFeature,
|
||||||
|
} from '@payloadcms/richtext-lexical'
|
||||||
|
|
||||||
|
const fdRichTextEditor = lexicalEditor({
|
||||||
|
features: ({ defaultFeatures }) => [
|
||||||
|
...defaultFeatures,
|
||||||
|
BoldFeature(),
|
||||||
|
ItalicFeature(),
|
||||||
|
UnderlineFeature(),
|
||||||
|
LinkFeature({ enabledCollections: ['pages', 'posts'] }),
|
||||||
|
UnorderedListFeature(),
|
||||||
|
OrderedListFeature(),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const FDFaqBlock: Block = {
|
||||||
|
slug: 'fdFaq',
|
||||||
|
interfaceName: 'FDFaqBlock',
|
||||||
|
labels: {
|
||||||
|
singular: 'FD FAQ',
|
||||||
|
plural: 'FD FAQs',
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'heading',
|
||||||
|
type: 'text',
|
||||||
|
localized: true,
|
||||||
|
required: true,
|
||||||
|
label: 'Rubrik',
|
||||||
|
defaultValue: 'Vanliga frågor',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'items',
|
||||||
|
type: 'array',
|
||||||
|
label: 'Frågor',
|
||||||
|
minRows: 1,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'question',
|
||||||
|
type: 'text',
|
||||||
|
localized: true,
|
||||||
|
required: true,
|
||||||
|
label: 'Fråga',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'answer',
|
||||||
|
type: 'richText',
|
||||||
|
localized: true,
|
||||||
|
label: 'Svar',
|
||||||
|
editor: fdRichTextEditor,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'theme',
|
||||||
|
type: 'select',
|
||||||
|
label: 'Tema',
|
||||||
|
defaultValue: 'gray',
|
||||||
|
options: [
|
||||||
|
{ label: 'Grå bakgrund', value: 'gray' },
|
||||||
|
{ label: 'Ljust', value: 'light' },
|
||||||
|
{ label: 'Mörkt', value: 'dark' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@ -58,7 +58,7 @@ export const FDTextBlockComponent: React.FC<FDTextBlockProps> = ({
|
|||||||
)}
|
)}
|
||||||
{body && (
|
{body && (
|
||||||
<div className={`font-joey text-fd-body-lg fd-prose ${colors.body}`}>
|
<div className={`font-joey text-fd-body-lg fd-prose ${colors.body}`}>
|
||||||
<RichText content={body} />
|
<RichText data={body} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
102
src/blocks/FDTextBlock/FDTextBlock-config.ts
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import type { Block } from 'payload'
|
||||||
|
import {
|
||||||
|
lexicalEditor,
|
||||||
|
BoldFeature,
|
||||||
|
ItalicFeature,
|
||||||
|
UnderlineFeature,
|
||||||
|
LinkFeature,
|
||||||
|
UnorderedListFeature,
|
||||||
|
OrderedListFeature,
|
||||||
|
HeadingFeature,
|
||||||
|
BlockquoteFeature,
|
||||||
|
} from '@payloadcms/richtext-lexical'
|
||||||
|
|
||||||
|
const fdRichTextEditor = lexicalEditor({
|
||||||
|
features: ({ defaultFeatures }) => [
|
||||||
|
...defaultFeatures,
|
||||||
|
BoldFeature(),
|
||||||
|
ItalicFeature(),
|
||||||
|
UnderlineFeature(),
|
||||||
|
LinkFeature({ enabledCollections: ['pages', 'posts'] }),
|
||||||
|
UnorderedListFeature(),
|
||||||
|
OrderedListFeature(),
|
||||||
|
HeadingFeature({ enabledHeadingSizes: ['h2', 'h3', 'h4'] }),
|
||||||
|
BlockquoteFeature(),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const FDTextBlock: Block = {
|
||||||
|
slug: 'fdText',
|
||||||
|
interfaceName: 'FDTextBlock',
|
||||||
|
labels: {
|
||||||
|
singular: 'FD Textblock',
|
||||||
|
plural: 'FD Textblock',
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'heading',
|
||||||
|
type: 'text',
|
||||||
|
localized: true,
|
||||||
|
label: 'Rubrik',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'subheading',
|
||||||
|
type: 'text',
|
||||||
|
localized: true,
|
||||||
|
label: 'Underrubrik',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'body',
|
||||||
|
type: 'richText',
|
||||||
|
localized: true,
|
||||||
|
label: 'Brödtext',
|
||||||
|
editor: fdRichTextEditor,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'alignment',
|
||||||
|
type: 'select',
|
||||||
|
label: 'Textjustering',
|
||||||
|
defaultValue: 'left',
|
||||||
|
options: [
|
||||||
|
{ label: 'Vänster', value: 'left' },
|
||||||
|
{ label: 'Centrerad', value: 'center' },
|
||||||
|
{ label: 'Höger', value: 'right' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'textColor',
|
||||||
|
type: 'select',
|
||||||
|
label: 'Textfärg',
|
||||||
|
defaultValue: 'navy',
|
||||||
|
options: [
|
||||||
|
{ label: 'Navy', value: 'navy' },
|
||||||
|
{ label: 'Vit', value: 'white' },
|
||||||
|
{ label: 'Gul', value: 'yellow' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sectionBackground',
|
||||||
|
type: 'select',
|
||||||
|
label: 'Bakgrund',
|
||||||
|
defaultValue: 'white',
|
||||||
|
options: [
|
||||||
|
{ label: 'Vit', value: 'white' },
|
||||||
|
{ label: 'Navy', value: 'navy' },
|
||||||
|
{ label: 'Grå', value: 'gray' },
|
||||||
|
{ label: 'Gul', value: 'yellow' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'maxWidth',
|
||||||
|
type: 'select',
|
||||||
|
label: 'Maxbredd',
|
||||||
|
defaultValue: 'wide',
|
||||||
|
options: [
|
||||||
|
{ label: 'Smal (600px)', value: 'narrow' },
|
||||||
|
{ label: 'Medium (800px)', value: 'medium' },
|
||||||
|
{ label: 'Bred (1100px)', value: 'wide' },
|
||||||
|
{ label: 'Full', value: 'full' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@ -65,7 +65,7 @@ export const FDUspTableBlockComponent: React.FC<FDUspTableBlockProps> = ({
|
|||||||
<span className={`font-joey-bold text-fd-h3 ${txt}`}>{row.title}</span>
|
<span className={`font-joey-bold text-fd-h3 ${txt}`}>{row.title}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={`font-joey text-fd-body fd-prose ${txt} ${proseOpacity} md:pl-0 pl-14`}>
|
<div className={`font-joey text-fd-body fd-prose ${txt} ${proseOpacity} md:pl-0 pl-14`}>
|
||||||
<RichText content={row.description} />
|
<RichText data={row.description} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
92
src/blocks/FDUspTableBlock/FDUspTableBlock-config.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import type { Block } from 'payload'
|
||||||
|
import {
|
||||||
|
lexicalEditor,
|
||||||
|
BoldFeature,
|
||||||
|
ItalicFeature,
|
||||||
|
UnderlineFeature,
|
||||||
|
LinkFeature,
|
||||||
|
UnorderedListFeature,
|
||||||
|
} from '@payloadcms/richtext-lexical'
|
||||||
|
|
||||||
|
const fdRichTextEditor = lexicalEditor({
|
||||||
|
features: ({ defaultFeatures }) => [
|
||||||
|
...defaultFeatures,
|
||||||
|
BoldFeature(),
|
||||||
|
ItalicFeature(),
|
||||||
|
UnderlineFeature(),
|
||||||
|
LinkFeature({ enabledCollections: ['pages', 'posts'] }),
|
||||||
|
UnorderedListFeature(),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export const FDUspTableBlock: Block = {
|
||||||
|
slug: 'fdUspTable',
|
||||||
|
interfaceName: 'FDUspTableBlock',
|
||||||
|
labels: {
|
||||||
|
singular: 'FD USP-tabell',
|
||||||
|
plural: 'FD USP-tabeller',
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'heading',
|
||||||
|
type: 'text',
|
||||||
|
localized: true,
|
||||||
|
label: 'Rubrik (valfri)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rows',
|
||||||
|
type: 'array',
|
||||||
|
label: 'Rader',
|
||||||
|
minRows: 1,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
type: 'text',
|
||||||
|
localized: true,
|
||||||
|
required: true,
|
||||||
|
label: 'Rubrik',
|
||||||
|
admin: { description: 'T.ex. "Högsta säkerhet"' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'description',
|
||||||
|
type: 'richText',
|
||||||
|
localized: true,
|
||||||
|
label: 'Beskrivning',
|
||||||
|
editor: fdRichTextEditor,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'checkColor',
|
||||||
|
type: 'select',
|
||||||
|
label: 'Checkikon-färg',
|
||||||
|
defaultValue: 'navy',
|
||||||
|
options: [
|
||||||
|
{ label: 'Navy (vit bock)', value: 'navy' },
|
||||||
|
{ label: 'Gul (navy bock)', value: 'yellow' },
|
||||||
|
{ label: 'Grå (navy bock)', value: 'gray' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'sectionBackground',
|
||||||
|
type: 'select',
|
||||||
|
label: 'Sektionsbakgrund',
|
||||||
|
defaultValue: 'white',
|
||||||
|
options: [
|
||||||
|
{ label: 'Vit', value: 'white' },
|
||||||
|
{ label: 'Grå', value: 'gray' },
|
||||||
|
{ label: 'Navy', value: 'navy' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'textColor',
|
||||||
|
type: 'select',
|
||||||
|
label: 'Textfärg',
|
||||||
|
defaultValue: 'navy',
|
||||||
|
options: [
|
||||||
|
{ label: 'Navy', value: 'navy' },
|
||||||
|
{ label: 'Vit', value: 'white' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@ -2,16 +2,10 @@ import type { CollectionConfig } from 'payload'
|
|||||||
|
|
||||||
import { authenticated } from '../../access/authenticated'
|
import { authenticated } from '../../access/authenticated'
|
||||||
import { authenticatedOrPublished } from '../../access/authenticatedOrPublished'
|
import { authenticatedOrPublished } from '../../access/authenticatedOrPublished'
|
||||||
import { Archive } from '../../blocks/ArchiveBlock/config'
|
|
||||||
import { CallToAction } from '../../blocks/CallToAction/config'
|
|
||||||
import { Content } from '../../blocks/Content/config'
|
|
||||||
import { FormBlock } from '../../blocks/Form/config'
|
|
||||||
import { MediaBlock } from '../../blocks/MediaBlock/config'
|
|
||||||
import { hero } from '@/heros/config'
|
|
||||||
import { slugField } from 'payload'
|
|
||||||
import { populatePublishedAt } from '../../hooks/populatePublishedAt'
|
import { populatePublishedAt } from '../../hooks/populatePublishedAt'
|
||||||
import { generatePreviewPath } from '../../utilities/generatePreviewPath'
|
import { generatePreviewPath } from '../../utilities/generatePreviewPath'
|
||||||
import { revalidateDelete, revalidatePage } from './hooks/revalidatePage'
|
import { revalidateDelete, revalidatePage } from './hooks/revalidatePage'
|
||||||
|
|
||||||
import { FDHeroBlock } from '../../blocks/FDHeroBlock/config'
|
import { FDHeroBlock } from '../../blocks/FDHeroBlock/config'
|
||||||
import { FDCtaSideImageBlock } from '../../blocks/FDCtaSideImageBlock/config'
|
import { FDCtaSideImageBlock } from '../../blocks/FDCtaSideImageBlock/config'
|
||||||
import { FDFeatureAnnouncementBlock } from '../../blocks/FDFeatureAnnouncementBlock/config'
|
import { FDFeatureAnnouncementBlock } from '../../blocks/FDFeatureAnnouncementBlock/config'
|
||||||
@ -49,6 +43,16 @@ import {
|
|||||||
PreviewField,
|
PreviewField,
|
||||||
} from '@payloadcms/plugin-seo/fields'
|
} from '@payloadcms/plugin-seo/fields'
|
||||||
|
|
||||||
|
// ── Slug generator — handles Swedish characters ────────────────────────────
|
||||||
|
const generateSlug = (value: string): string =>
|
||||||
|
value
|
||||||
|
.toLowerCase()
|
||||||
|
.trim()
|
||||||
|
.replace(/[åä]/g, 'a')
|
||||||
|
.replace(/ö/g, 'o')
|
||||||
|
.replace(/[^a-z0-9]+/g, '-')
|
||||||
|
.replace(/^-+|-+$/g, '')
|
||||||
|
|
||||||
export const Pages: CollectionConfig<'pages'> = {
|
export const Pages: CollectionConfig<'pages'> = {
|
||||||
slug: 'pages',
|
slug: 'pages',
|
||||||
access: {
|
access: {
|
||||||
@ -57,9 +61,6 @@ export const Pages: CollectionConfig<'pages'> = {
|
|||||||
read: authenticatedOrPublished,
|
read: authenticatedOrPublished,
|
||||||
update: authenticated,
|
update: authenticated,
|
||||||
},
|
},
|
||||||
// This config controls what's populated by default when a page is referenced
|
|
||||||
// https://payloadcms.com/docs/queries/select#defaultpopulate-collection-config-property
|
|
||||||
// Type safe if the collection slug generic is passed to `CollectionConfig` - `CollectionConfig<'pages'>
|
|
||||||
defaultPopulate: {
|
defaultPopulate: {
|
||||||
title: true,
|
title: true,
|
||||||
slug: true,
|
slug: true,
|
||||||
@ -91,23 +92,48 @@ export const Pages: CollectionConfig<'pages'> = {
|
|||||||
{
|
{
|
||||||
type: 'tabs',
|
type: 'tabs',
|
||||||
tabs: [
|
tabs: [
|
||||||
{
|
|
||||||
fields: [hero],
|
|
||||||
label: 'Hero',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'layout',
|
name: 'layout',
|
||||||
type: 'blocks',
|
type: 'blocks',
|
||||||
blocks: [FDHeroBlock, FDCtaSideImageBlock, FDFeatureAnnouncementBlock, FDServicesGridBlock, FDContactBlock, FDFaqBlock, FDCardGridBlock, FDPricingCardBlock, FDSpacerBlock, FDIconBarBlock, FDUspChecklistBlock, FDWideCardBlock, FDTechPropertiesBlock, FDUspTableBlock, FDHeaderTextImageBlock, FDContactFormBlock, FDLocationsGridBlock, FDAlternateHeroBlock, FDStatisticsBlock, FDPartnersLogosBlock, FDNewsletterBlock, FDServiceChooserBlock, FDDataTableBlock, FDVpsCalculatorBlock, FDTagsBlock, FDTextBlock, FDCodeEmbedBlock, FDVideoBlock],
|
blocks: [
|
||||||
|
FDHeroBlock,
|
||||||
|
FDCtaSideImageBlock,
|
||||||
|
FDFeatureAnnouncementBlock,
|
||||||
|
FDServicesGridBlock,
|
||||||
|
FDContactBlock,
|
||||||
|
FDFaqBlock,
|
||||||
|
FDCardGridBlock,
|
||||||
|
FDPricingCardBlock,
|
||||||
|
FDSpacerBlock,
|
||||||
|
FDIconBarBlock,
|
||||||
|
FDUspChecklistBlock,
|
||||||
|
FDWideCardBlock,
|
||||||
|
FDTechPropertiesBlock,
|
||||||
|
FDUspTableBlock,
|
||||||
|
FDHeaderTextImageBlock,
|
||||||
|
FDContactFormBlock,
|
||||||
|
FDLocationsGridBlock,
|
||||||
|
FDAlternateHeroBlock,
|
||||||
|
FDStatisticsBlock,
|
||||||
|
FDPartnersLogosBlock,
|
||||||
|
FDNewsletterBlock,
|
||||||
|
FDServiceChooserBlock,
|
||||||
|
FDDataTableBlock,
|
||||||
|
FDVpsCalculatorBlock,
|
||||||
|
FDTagsBlock,
|
||||||
|
FDTextBlock,
|
||||||
|
FDCodeEmbedBlock,
|
||||||
|
FDVideoBlock,
|
||||||
|
],
|
||||||
required: true,
|
required: true,
|
||||||
admin: {
|
admin: {
|
||||||
initCollapsed: true,
|
initCollapsed: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
label: 'Content',
|
label: 'Innehåll',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'meta',
|
name: 'meta',
|
||||||
@ -124,13 +150,9 @@ export const Pages: CollectionConfig<'pages'> = {
|
|||||||
MetaImageField({
|
MetaImageField({
|
||||||
relationTo: 'media',
|
relationTo: 'media',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
MetaDescriptionField({}),
|
MetaDescriptionField({}),
|
||||||
PreviewField({
|
PreviewField({
|
||||||
// if the `generateUrl` function is configured
|
|
||||||
hasGenerateFn: true,
|
hasGenerateFn: true,
|
||||||
|
|
||||||
// field paths to match the target field for data
|
|
||||||
titlePath: 'meta.title',
|
titlePath: 'meta.title',
|
||||||
descriptionPath: 'meta.description',
|
descriptionPath: 'meta.description',
|
||||||
}),
|
}),
|
||||||
@ -145,7 +167,22 @@ export const Pages: CollectionConfig<'pages'> = {
|
|||||||
position: 'sidebar',
|
position: 'sidebar',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
slugField(),
|
// ── Slug ──────────────────────────────────────────────────────────────
|
||||||
|
{
|
||||||
|
name: 'slug',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
index: true,
|
||||||
|
admin: {
|
||||||
|
position: 'sidebar',
|
||||||
|
description: 'Genereras automatiskt från titeln.',
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
|
beforeChange: [
|
||||||
|
({ data }) => generateSlug(data?.title || ''),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}, // ← slug object closes here, then straight into ],
|
||||||
],
|
],
|
||||||
hooks: {
|
hooks: {
|
||||||
afterChange: [revalidatePage],
|
afterChange: [revalidatePage],
|
||||||
@ -155,7 +192,7 @@ export const Pages: CollectionConfig<'pages'> = {
|
|||||||
versions: {
|
versions: {
|
||||||
drafts: {
|
drafts: {
|
||||||
autosave: {
|
autosave: {
|
||||||
interval: 100, // We set this interval for optimal live preview
|
interval: 100,
|
||||||
},
|
},
|
||||||
schedulePublish: true,
|
schedulePublish: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -25,7 +25,16 @@ import {
|
|||||||
OverviewField,
|
OverviewField,
|
||||||
PreviewField,
|
PreviewField,
|
||||||
} from '@payloadcms/plugin-seo/fields'
|
} from '@payloadcms/plugin-seo/fields'
|
||||||
import { slugField } from 'payload'
|
|
||||||
|
// ── Slug generator — handles Swedish characters ────────────────────────────
|
||||||
|
const generateSlug = (value: string): string =>
|
||||||
|
value
|
||||||
|
.toLowerCase()
|
||||||
|
.trim()
|
||||||
|
.replace(/[åä]/g, 'a')
|
||||||
|
.replace(/ö/g, 'o')
|
||||||
|
.replace(/[^a-z0-9]+/g, '-')
|
||||||
|
.replace(/^-+|-+$/g, '')
|
||||||
|
|
||||||
export const Posts: CollectionConfig<'posts'> = {
|
export const Posts: CollectionConfig<'posts'> = {
|
||||||
slug: 'posts',
|
slug: 'posts',
|
||||||
@ -35,9 +44,6 @@ export const Posts: CollectionConfig<'posts'> = {
|
|||||||
read: authenticatedOrPublished,
|
read: authenticatedOrPublished,
|
||||||
update: authenticated,
|
update: authenticated,
|
||||||
},
|
},
|
||||||
// This config controls what's populated by default when a post is referenced
|
|
||||||
// https://payloadcms.com/docs/queries/select#defaultpopulate-collection-config-property
|
|
||||||
// Type safe if the collection slug generic is passed to `CollectionConfig` - `CollectionConfig<'posts'>
|
|
||||||
defaultPopulate: {
|
defaultPopulate: {
|
||||||
title: true,
|
title: true,
|
||||||
slug: true,
|
slug: true,
|
||||||
@ -100,7 +106,7 @@ export const Posts: CollectionConfig<'posts'> = {
|
|||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
label: 'Content',
|
label: 'Innehåll',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fields: [
|
fields: [
|
||||||
@ -147,13 +153,9 @@ export const Posts: CollectionConfig<'posts'> = {
|
|||||||
MetaImageField({
|
MetaImageField({
|
||||||
relationTo: 'media',
|
relationTo: 'media',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
MetaDescriptionField({}),
|
MetaDescriptionField({}),
|
||||||
PreviewField({
|
PreviewField({
|
||||||
// if the `generateUrl` function is configured
|
|
||||||
hasGenerateFn: true,
|
hasGenerateFn: true,
|
||||||
|
|
||||||
// field paths to match the target field for data
|
|
||||||
titlePath: 'meta.title',
|
titlePath: 'meta.title',
|
||||||
descriptionPath: 'meta.description',
|
descriptionPath: 'meta.description',
|
||||||
}),
|
}),
|
||||||
@ -190,9 +192,6 @@ export const Posts: CollectionConfig<'posts'> = {
|
|||||||
hasMany: true,
|
hasMany: true,
|
||||||
relationTo: 'users',
|
relationTo: 'users',
|
||||||
},
|
},
|
||||||
// This field is only used to populate the user data via the `populateAuthors` hook
|
|
||||||
// This is because the `user` collection has access control locked to protect user privacy
|
|
||||||
// GraphQL will also not return mutated user data that differs from the underlying schema
|
|
||||||
{
|
{
|
||||||
name: 'populatedAuthors',
|
name: 'populatedAuthors',
|
||||||
type: 'array',
|
type: 'array',
|
||||||
@ -214,7 +213,23 @@ export const Posts: CollectionConfig<'posts'> = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
slugField(),
|
|
||||||
|
// ── Slug ──────────────────────────────────────────────────────────────
|
||||||
|
{
|
||||||
|
name: 'slug',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
index: true,
|
||||||
|
admin: {
|
||||||
|
position: 'sidebar',
|
||||||
|
description: 'Genereras automatiskt från titeln.',
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
|
beforeChange: [
|
||||||
|
({ data }) => generateSlug(data?.title || ''),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}, // ← slug object closes here, then straight into ],
|
||||||
],
|
],
|
||||||
hooks: {
|
hooks: {
|
||||||
afterChange: [revalidatePost],
|
afterChange: [revalidatePost],
|
||||||
@ -224,7 +239,7 @@ export const Posts: CollectionConfig<'posts'> = {
|
|||||||
versions: {
|
versions: {
|
||||||
drafts: {
|
drafts: {
|
||||||
autosave: {
|
autosave: {
|
||||||
interval: 100, // We set this interval for optimal live preview
|
interval: 100,
|
||||||
},
|
},
|
||||||
schedulePublish: true,
|
schedulePublish: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -153,49 +153,6 @@ export interface UserAuthOperations {
|
|||||||
export interface Page {
|
export interface Page {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
hero: {
|
|
||||||
type: 'none' | 'highImpact' | 'mediumImpact' | 'lowImpact';
|
|
||||||
richText?: {
|
|
||||||
root: {
|
|
||||||
type: string;
|
|
||||||
children: {
|
|
||||||
type: any;
|
|
||||||
version: number;
|
|
||||||
[k: string]: unknown;
|
|
||||||
}[];
|
|
||||||
direction: ('ltr' | 'rtl') | null;
|
|
||||||
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
|
||||||
indent: number;
|
|
||||||
version: number;
|
|
||||||
};
|
|
||||||
[k: string]: unknown;
|
|
||||||
} | null;
|
|
||||||
links?:
|
|
||||||
| {
|
|
||||||
link: {
|
|
||||||
type?: ('reference' | 'custom') | null;
|
|
||||||
newTab?: boolean | null;
|
|
||||||
reference?:
|
|
||||||
| ({
|
|
||||||
relationTo: 'pages';
|
|
||||||
value: number | Page;
|
|
||||||
} | null)
|
|
||||||
| ({
|
|
||||||
relationTo: 'posts';
|
|
||||||
value: number | Post;
|
|
||||||
} | null);
|
|
||||||
url?: string | null;
|
|
||||||
label: string;
|
|
||||||
/**
|
|
||||||
* Choose how the link should be rendered.
|
|
||||||
*/
|
|
||||||
appearance?: ('default' | 'outline') | null;
|
|
||||||
};
|
|
||||||
id?: string | null;
|
|
||||||
}[]
|
|
||||||
| null;
|
|
||||||
media?: (number | null) | Media;
|
|
||||||
};
|
|
||||||
layout: (
|
layout: (
|
||||||
| FDHeroBlock
|
| FDHeroBlock
|
||||||
| FDCtaSideImageBlock
|
| FDCtaSideImageBlock
|
||||||
@ -236,9 +193,8 @@ export interface Page {
|
|||||||
};
|
};
|
||||||
publishedAt?: string | null;
|
publishedAt?: string | null;
|
||||||
/**
|
/**
|
||||||
* When enabled, the slug will auto-generate from the title field on save and autosave.
|
* Genereras automatiskt från titeln.
|
||||||
*/
|
*/
|
||||||
generateSlug?: boolean | null;
|
|
||||||
slug: string;
|
slug: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
@ -246,53 +202,32 @@ export interface Page {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "posts".
|
* via the `definition` "FDHeroBlock".
|
||||||
*/
|
*/
|
||||||
export interface Post {
|
export interface FDHeroBlock {
|
||||||
id: number;
|
heading: string;
|
||||||
title: string;
|
subheading?: string | null;
|
||||||
heroImage?: (number | null) | Media;
|
body?: string | null;
|
||||||
content: {
|
ctaText?: string | null;
|
||||||
root: {
|
ctaLink?: string | null;
|
||||||
type: string;
|
secondaryCtaText?: string | null;
|
||||||
children: {
|
secondaryCtaLink?: string | null;
|
||||||
type: any;
|
|
||||||
version: number;
|
|
||||||
[k: string]: unknown;
|
|
||||||
}[];
|
|
||||||
direction: ('ltr' | 'rtl') | null;
|
|
||||||
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
|
||||||
indent: number;
|
|
||||||
version: number;
|
|
||||||
};
|
|
||||||
[k: string]: unknown;
|
|
||||||
};
|
|
||||||
relatedPosts?: (number | Post)[] | null;
|
|
||||||
categories?: (number | Category)[] | null;
|
|
||||||
meta?: {
|
|
||||||
title?: string | null;
|
|
||||||
/**
|
|
||||||
* Maximum upload file size: 12MB. Recommended file size for images is <500KB.
|
|
||||||
*/
|
|
||||||
image?: (number | null) | Media;
|
|
||||||
description?: string | null;
|
|
||||||
};
|
|
||||||
publishedAt?: string | null;
|
|
||||||
authors?: (number | User)[] | null;
|
|
||||||
populatedAuthors?:
|
|
||||||
| {
|
|
||||||
id?: string | null;
|
|
||||||
name?: string | null;
|
|
||||||
}[]
|
|
||||||
| null;
|
|
||||||
/**
|
/**
|
||||||
* When enabled, the slug will auto-generate from the title field on save and autosave.
|
* Fullbreddsbild bakom texten. Lämna tom för enfärgad bakgrund.
|
||||||
*/
|
*/
|
||||||
generateSlug?: boolean | null;
|
backgroundImage?: (number | null) | Media;
|
||||||
slug: string;
|
/**
|
||||||
updatedAt: string;
|
* Hur mörk overlay över bilden (för läsbarhet)
|
||||||
createdAt: string;
|
*/
|
||||||
_status?: ('draft' | 'published') | null;
|
overlayOpacity?: ('30' | '50' | '70') | null;
|
||||||
|
textColor?: ('auto' | 'white' | 'navy') | null;
|
||||||
|
/**
|
||||||
|
* Ignoreras om bakgrundsbild är vald
|
||||||
|
*/
|
||||||
|
theme?: ('light' | 'dark') | null;
|
||||||
|
id?: string | null;
|
||||||
|
blockName?: string | null;
|
||||||
|
blockType: 'fdHero';
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
@ -347,81 +282,6 @@ export interface Media {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "categories".
|
|
||||||
*/
|
|
||||||
export interface Category {
|
|
||||||
id: number;
|
|
||||||
title: string;
|
|
||||||
slug: string;
|
|
||||||
parent?: (number | null) | Category;
|
|
||||||
breadcrumbs?:
|
|
||||||
| {
|
|
||||||
doc?: (number | null) | Category;
|
|
||||||
url?: string | null;
|
|
||||||
label?: string | null;
|
|
||||||
id?: string | null;
|
|
||||||
}[]
|
|
||||||
| null;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "users".
|
|
||||||
*/
|
|
||||||
export interface User {
|
|
||||||
id: number;
|
|
||||||
name?: string | null;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
email: string;
|
|
||||||
resetPasswordToken?: string | null;
|
|
||||||
resetPasswordExpiration?: string | null;
|
|
||||||
salt?: string | null;
|
|
||||||
hash?: string | null;
|
|
||||||
loginAttempts?: number | null;
|
|
||||||
lockUntil?: string | null;
|
|
||||||
sessions?:
|
|
||||||
| {
|
|
||||||
id: string;
|
|
||||||
createdAt?: string | null;
|
|
||||||
expiresAt: string;
|
|
||||||
}[]
|
|
||||||
| null;
|
|
||||||
password?: string | null;
|
|
||||||
collection: 'users';
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "FDHeroBlock".
|
|
||||||
*/
|
|
||||||
export interface FDHeroBlock {
|
|
||||||
heading: string;
|
|
||||||
subheading?: string | null;
|
|
||||||
body?: string | null;
|
|
||||||
ctaText?: string | null;
|
|
||||||
ctaLink?: string | null;
|
|
||||||
secondaryCtaText?: string | null;
|
|
||||||
secondaryCtaLink?: string | null;
|
|
||||||
/**
|
|
||||||
* Fullbreddsbild bakom texten. Lämna tom för enfärgad bakgrund.
|
|
||||||
*/
|
|
||||||
backgroundImage?: (number | null) | Media;
|
|
||||||
/**
|
|
||||||
* Hur mörk overlay över bilden (för läsbarhet)
|
|
||||||
*/
|
|
||||||
overlayOpacity?: ('30' | '50' | '70') | null;
|
|
||||||
textColor?: ('auto' | 'white' | 'navy') | null;
|
|
||||||
/**
|
|
||||||
* Ignoreras om bakgrundsbild är vald
|
|
||||||
*/
|
|
||||||
theme?: ('light' | 'dark') | null;
|
|
||||||
id?: string | null;
|
|
||||||
blockName?: string | null;
|
|
||||||
blockType: 'fdHero';
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "FDCtaSideImageBlock".
|
* via the `definition` "FDCtaSideImageBlock".
|
||||||
@ -1376,6 +1236,101 @@ export interface FDVideoBlock {
|
|||||||
blockName?: string | null;
|
blockName?: string | null;
|
||||||
blockType: 'fdVideo';
|
blockType: 'fdVideo';
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "posts".
|
||||||
|
*/
|
||||||
|
export interface Post {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
heroImage?: (number | null) | Media;
|
||||||
|
content: {
|
||||||
|
root: {
|
||||||
|
type: string;
|
||||||
|
children: {
|
||||||
|
type: any;
|
||||||
|
version: number;
|
||||||
|
[k: string]: unknown;
|
||||||
|
}[];
|
||||||
|
direction: ('ltr' | 'rtl') | null;
|
||||||
|
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||||
|
indent: number;
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
[k: string]: unknown;
|
||||||
|
};
|
||||||
|
relatedPosts?: (number | Post)[] | null;
|
||||||
|
categories?: (number | Category)[] | null;
|
||||||
|
meta?: {
|
||||||
|
title?: string | null;
|
||||||
|
/**
|
||||||
|
* Maximum upload file size: 12MB. Recommended file size for images is <500KB.
|
||||||
|
*/
|
||||||
|
image?: (number | null) | Media;
|
||||||
|
description?: string | null;
|
||||||
|
};
|
||||||
|
publishedAt?: string | null;
|
||||||
|
authors?: (number | User)[] | null;
|
||||||
|
populatedAuthors?:
|
||||||
|
| {
|
||||||
|
id?: string | null;
|
||||||
|
name?: string | null;
|
||||||
|
}[]
|
||||||
|
| null;
|
||||||
|
/**
|
||||||
|
* Genereras automatiskt från titeln.
|
||||||
|
*/
|
||||||
|
slug: string;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
_status?: ('draft' | 'published') | null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "categories".
|
||||||
|
*/
|
||||||
|
export interface Category {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
slug: string;
|
||||||
|
parent?: (number | null) | Category;
|
||||||
|
breadcrumbs?:
|
||||||
|
| {
|
||||||
|
doc?: (number | null) | Category;
|
||||||
|
url?: string | null;
|
||||||
|
label?: string | null;
|
||||||
|
id?: string | null;
|
||||||
|
}[]
|
||||||
|
| null;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "users".
|
||||||
|
*/
|
||||||
|
export interface User {
|
||||||
|
id: number;
|
||||||
|
name?: string | null;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
email: string;
|
||||||
|
resetPasswordToken?: string | null;
|
||||||
|
resetPasswordExpiration?: string | null;
|
||||||
|
salt?: string | null;
|
||||||
|
hash?: string | null;
|
||||||
|
loginAttempts?: number | null;
|
||||||
|
lockUntil?: string | null;
|
||||||
|
sessions?:
|
||||||
|
| {
|
||||||
|
id: string;
|
||||||
|
createdAt?: string | null;
|
||||||
|
expiresAt: string;
|
||||||
|
}[]
|
||||||
|
| null;
|
||||||
|
password?: string | null;
|
||||||
|
collection: 'users';
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "redirects".
|
* via the `definition` "redirects".
|
||||||
@ -1615,28 +1570,6 @@ export interface PayloadMigration {
|
|||||||
*/
|
*/
|
||||||
export interface PagesSelect<T extends boolean = true> {
|
export interface PagesSelect<T extends boolean = true> {
|
||||||
title?: T;
|
title?: T;
|
||||||
hero?:
|
|
||||||
| T
|
|
||||||
| {
|
|
||||||
type?: T;
|
|
||||||
richText?: T;
|
|
||||||
links?:
|
|
||||||
| T
|
|
||||||
| {
|
|
||||||
link?:
|
|
||||||
| T
|
|
||||||
| {
|
|
||||||
type?: T;
|
|
||||||
newTab?: T;
|
|
||||||
reference?: T;
|
|
||||||
url?: T;
|
|
||||||
label?: T;
|
|
||||||
appearance?: T;
|
|
||||||
};
|
|
||||||
id?: T;
|
|
||||||
};
|
|
||||||
media?: T;
|
|
||||||
};
|
|
||||||
layout?:
|
layout?:
|
||||||
| T
|
| T
|
||||||
| {
|
| {
|
||||||
@ -1677,7 +1610,6 @@ export interface PagesSelect<T extends boolean = true> {
|
|||||||
description?: T;
|
description?: T;
|
||||||
};
|
};
|
||||||
publishedAt?: T;
|
publishedAt?: T;
|
||||||
generateSlug?: T;
|
|
||||||
slug?: T;
|
slug?: T;
|
||||||
updatedAt?: T;
|
updatedAt?: T;
|
||||||
createdAt?: T;
|
createdAt?: T;
|
||||||
@ -2273,7 +2205,6 @@ export interface PostsSelect<T extends boolean = true> {
|
|||||||
id?: T;
|
id?: T;
|
||||||
name?: T;
|
name?: T;
|
||||||
};
|
};
|
||||||
generateSlug?: T;
|
|
||||||
slug?: T;
|
slug?: T;
|
||||||
updatedAt?: T;
|
updatedAt?: T;
|
||||||
createdAt?: T;
|
createdAt?: T;
|
||||||
|
|||||||