updated todo with instructions to implement english EN

This commit is contained in:
Jeffrey 2026-02-24 15:24:30 +01:00
parent f48b60bb5d
commit 68d6e68cba
7 changed files with 51 additions and 442 deletions

5
.gitignore vendored
View File

@ -17,6 +17,5 @@ src/**/*.bak.*
next-env.d.ts next-env.d.ts
tsconfig.tsbuildinfo tsconfig.tsbuildinfo
media/ media/
src/migrations/*.ts !src/migrations/*.ts
src/migrations/*.json !src/migrations/*.json
!src/migrations/index.ts

View File

@ -1,17 +1,48 @@
# Web Paylod CMS testing # Web Paylod CMS testing
## Integrate english in the future
Two things remaining:
1. Connect DeepL
Get an API key at deepl.com (free tier = 500,000 chars/month, plenty for a B2B site).
Add to .env.local locally and .env on the server:
DEEPL_API_KEY=your_key_here
To translate a page, find its ID in the Payload admin URL (e.g. admin/collections/pages/abc123) then call:
bashcurl -X POST https://fiberdirekt.se/api/translate \
-H "Content-Type: application/json" \
-H "Cookie: payload-token=your_admin_token" \
-d '{"pageId": "abc123", "collection": "pages"}'
It will translate all Swedish text fields and save them as English in one shot. RichText fields (FAQ answers, body text) are skipped — do those manually in the Payload admin by switching the locale tab to EN.
2. Wire the LocaleSwitcher into the nav
When English content is ready, open src/Header/Nav/index.tsx and add the import and component. Find where the nav actions/CTA button sits and place it nearby:
tsximport { LocaleSwitcher } from '@/components/LocaleSwitcher'
// Then inside the JSX, next to the CTA button:
<LocaleSwitcher />
That's it — the component already handles the path swapping logic. Commit, push, deploy.
Recommended order:
Build out Swedish content fully and launch
Use DeepL endpoint to batch-translate pages
Review and fix translations manually in Payload admin
Wire in the switcher
Add /en/page.tsx root redirect (already done)
## Comments on what to fix ## Comments on what to fix
Can we get filler text in blocks as standard ?
~~Hero should default to none, or we should try to remove it!~~ ~~Hero should default to none, or we should try to remove it!~~
Preview thumbnails for blocks ?? ~~Preview thumbnails for blocks ??~~
Can we get filler text in blocks as standard ?
~~Why is slug defaulting to one letter? ~~ ~~Why is slug defaulting to one letter? ~~
Fix corners and embed for video block ~~Fix corners and embed for video block ~~
~~Fix posts formatting to be better~~ ~~Fix posts formatting to be better~~
@ -27,18 +58,18 @@ Fix corners and embed for video block
--- ---
## Funktionalitet att bekräfta ## Funktionalitet att bekräfta, test med Erik
#### Subscribe to newsletters, connection to API GANL * Subscribe to newsletters, connection to API GANL
#### Få en offert (Lime, GANL, epost?) * Få en offert (Lime, GANL, epost?)
~~#### Forms generellt ?~~ ~~* Forms generellt?~~
~~#### Matomo Tracking~~ ~~* Matomo Tracking~~
~~#### Cookies consent~~ ~~* Cookies consent~~
~~#### Lime forms integration ~~ ~~* Lime forms integration ~~
~~#### Other code embedding~~ ~~* Other code embedding~~

View File

@ -1,260 +0,0 @@
#!/bin/bash
# ============================================================================
# add-anchor-links.sh (macOS + Linux compatible)
# Run from your project root: bash add-anchor-links.sh
# ============================================================================
set -e
echo "🔗 Adding anchor link support to all FD blocks..."
echo ""
# ── Step 1: Create shared anchorField ──────────────────────────────────────
mkdir -p src/fields
cat > src/fields/anchorField.ts << 'FIELDEOF'
import type { Field } from 'payload'
/**
* Shared anchorId field for all FD blocks.
* Allows editors to set an anchor link ID on any section,
* enabling direct linking like /page#section-name
*
* Usage in block config:
* import { anchorField } from '@/fields/anchorField'
* fields: [ ...contentFields, anchorField ]
*
* Usage in block component:
* <section id={anchorId || undefined} ...>
*/
export const anchorField: Field = {
name: 'anchorId',
type: 'text',
label: 'Ankarlänk-ID',
admin: {
description:
'Valfritt. Används för att länka direkt till denna sektion, t.ex. "priser" ger /sida#priser. Använd bara små bokstäver, siffror och bindestreck.',
position: 'sidebar',
},
validate: (value: unknown) => {
if (!value) return true
if (typeof value === 'string' && /^[a-z0-9][a-z0-9-]*$/.test(value)) return true
return 'Använd bara små bokstäver (a-z), siffror (0-9) och bindestreck (-). Inga mellanslag.'
},
}
FIELDEOF
echo "✅ Created src/fields/anchorField.ts"
# ── Step 2: Add anchorField to all block configs ───────────────────────────
BLOCKS=(
FDHeroBlock
FDAlternateHeroBlock
FDTextBlock
FDPricingCardBlock
FDFaqBlock
FDContactBlock
FDContactFormBlock
FDDataTableBlock
FDCardGridBlock
FDCtaSideImageBlock
FDCtaBannerBlock
FDCodeEmbedBlock
FDFeatureAnnouncementBlock
FDHeaderTextImageBlock
FDServicesGridBlock
FDServiceChooserBlock
FDUspChecklistBlock
FDUspTableBlock
FDTechPropertiesBlock
FDStatisticsBlock
FDTestimonialBlock
FDTeamBlock
FDVideoBlock
FDVpsCalculatorBlock
FDWideCardBlock
FDServiceCalculatorBlock
)
for BLOCK in "${BLOCKS[@]}"; do
CONFIG="src/blocks/$BLOCK/config.ts"
if [ ! -f "$CONFIG" ]; then
echo "⚠️ Skipped $BLOCK — config not found"
continue
fi
# Skip if already has anchorField
if grep -q "anchorField" "$CONFIG"; then
echo "⏭️ Skipped $BLOCK — anchorField already present"
continue
fi
# Add import after the first line
perl -i -pe 'if ($. == 1) { $_ .= "import { anchorField } from '\''\@/fields/anchorField'\''\n" }' "$CONFIG"
# Add anchorField before the last "]," in the file
perl -i -0pe 's/( \],\n\})\s*$/ anchorField,\n$1/s' "$CONFIG"
echo "✅ Updated $CONFIG"
done
echo ""
# ── Step 3: Add anchorId to all block components ──────────────────────────
echo "🔧 Updating block components..."
for BLOCK in "${BLOCKS[@]}"; do
COMP="src/blocks/$BLOCK/Component.tsx"
if [ ! -f "$COMP" ]; then
echo "⚠️ Skipped $BLOCK component — not found"
continue
fi
# Skip if already has anchorId
if grep -q "anchorId" "$COMP"; then
echo "⏭️ Skipped $BLOCK component — anchorId already present"
continue
fi
# Add anchorId to destructured props: insert before "}) => {"
perl -i -pe 's/\}\) => \{/ anchorId,\n}) => {/' "$COMP"
# Add id={anchorId || undefined} to the first <section
# Handle single-line: <section className=...
perl -i -pe 'if (!$done && s/<section className/<section id={anchorId || undefined} className/) { $done=1 }' "$COMP"
# Handle multi-line: <section alone on a line (like FDHeroBlock)
if ! grep -q 'id={anchorId' "$COMP"; then
perl -i -pe 'if (!$done && /^\s+<section\s*$/) { $done=1; s|<section|<section id={anchorId \|\| undefined}| }' "$COMP"
fi
echo "✅ Updated $COMP"
done
echo ""
# ── Step 4: Add smooth scrolling to globals.css ───────────────────────────
GLOBALS_CSS="src/app/(frontend)/globals.css"
if grep -q "scroll-behavior" "$GLOBALS_CSS" 2>/dev/null; then
echo "⏭️ Smooth scroll already in globals.css"
else
TMPFILE=$(mktemp)
cat > "$TMPFILE" << 'CSSEOF'
/* Smooth scroll + header offset for anchor links */
html {
scroll-behavior: smooth;
scroll-padding-top: 100px;
}
CSSEOF
cat "$GLOBALS_CSS" >> "$TMPFILE"
mv "$TMPFILE" "$GLOBALS_CSS"
echo "✅ Added smooth scroll to globals.css"
fi
echo ""
# ── Step 5: Create BackToTop component ────────────────────────────────────
mkdir -p src/components/BackToTop
cat > src/components/BackToTop/index.tsx << 'BTEOF'
'use client'
import React, { useState, useEffect, useCallback } from 'react'
import { ChevronUpIcon } from 'lucide-react'
/**
* Floating "back to top" button.
* Appears after scrolling down 400px, smooth-scrolls to top on click.
* Styled to match FD design system.
*/
export const BackToTop: React.FC = () => {
const [visible, setVisible] = useState(false)
useEffect(() => {
const onScroll = () => {
setVisible(window.scrollY > 400)
}
window.addEventListener('scroll', onScroll, { passive: true })
return () => window.removeEventListener('scroll', onScroll)
}, [])
const scrollToTop = useCallback(() => {
window.scrollTo({ top: 0, behavior: 'smooth' })
}, [])
return (
<button
onClick={scrollToTop}
aria-label="Tillbaka till toppen"
className={`
fixed bottom-6 right-6 z-40
w-11 h-11 rounded-full
bg-fd-navy/80 backdrop-blur-sm
text-white hover:text-fd-yellow
border border-white/10 hover:border-fd-yellow/30
shadow-lg hover:shadow-xl
flex items-center justify-center
transition-all duration-300 ease-in-out cursor-pointer
${visible
? 'opacity-100 translate-y-0 pointer-events-auto'
: 'opacity-0 translate-y-4 pointer-events-none'
}
`}
>
<ChevronUpIcon className="w-5 h-5" />
</button>
)
}
BTEOF
echo "✅ Created src/components/BackToTop/index.tsx"
# ── Step 6: Add BackToTop to layout ───────────────────────────────────────
LAYOUT="src/app/(frontend)/layout.tsx"
if grep -q "BackToTop" "$LAYOUT" 2>/dev/null; then
echo "⏭️ BackToTop already in layout"
else
# Add import after Footer import
perl -i -pe 'if (/import \{ Footer \}/) { $_ .= "import { BackToTop } from '\''\@/components/BackToTop'\''\n" }' "$LAYOUT"
# Add component after <Footer />
perl -i -pe 's|<Footer />|<Footer />\n <BackToTop />|' "$LAYOUT"
echo "✅ Added BackToTop to layout.tsx"
fi
echo ""
echo "════════════════════════════════════════════════════════════════"
echo "✅ All done! Now follow the deployment steps below."
echo "════════════════════════════════════════════════════════════════"
echo ""
echo "LOCAL:"
echo " 1. Review changes: git diff"
echo " 2. Clean local migrations:"
echo " rm -f src/migrations/2025*.ts src/migrations/2026*.ts"
echo " echo 'export {}' > src/migrations/index.ts"
echo " 3. Commit and push:"
echo " git add -A"
echo " git commit -m 'feat: anchor links, smooth scroll, back-to-top'"
echo " git push origin main"
echo ""
echo "SERVER:"
echo " cd /var/www/fiberdirekt"
echo " git pull origin main"
echo " npm install"
echo " npx payload generate:types"
echo " npx payload migrate:create add-anchor-links"
echo " npx payload migrate"
echo " npm run build && pm2 restart fiberdirekt"
echo ""
echo "If migrate:create says 'no changes detected', skip migrate"
echo "steps and go straight to build. Block fields are stored as"
echo "JSON so new optional fields usually don't need SQL migration."
echo ""

View File

@ -0,0 +1,5 @@
import { redirect } from 'next/navigation'
export default function EnHomePage() {
redirect('/en/home')
}

View File

@ -1,74 +0,0 @@
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' },
],
},
],
}

View File

@ -1,92 +0,0 @@
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' },
],
},
],
}

File diff suppressed because one or more lines are too long