[number]
-type NavItem = {
- label: string
+// ─── Resolve href from reference or custom url ────────────────────────────────
+function resolveHref(item: {
+ type?: string | null
url?: string | null
- megaMenu?: boolean | null
- children?: NavChild[] | null
+ reference?: { relationTo?: string; value?: number | Page | null } | null
+}): string {
+ if (item.type === 'reference' && item.reference?.value) {
+ const page = item.reference.value
+ if (typeof page === 'object' && page !== null) {
+ return page.slug === 'home' || page.slug === 'startsida' ? '/' : `/${(page as Page).slug}`
+ }
+ return '#'
+ }
+ return item.url || '#'
}
// ─── Swedish Flag ─────────────────────────────────────────────────────────────
@@ -81,14 +87,14 @@ const MegaMenuPanel: React.FC<{
return (
<>
- {/* Blur backdrop — covers page below, click to close */}
+ {/* Blur backdrop */}
- {/* Panel — same white as header, no top border so they read as one */}
+ {/* Panel */}
(
= ({ data }) => {
{item.children!.map((child, j) => (
setOpenDropdown(null)}
className="block px-5 py-2.5 font-joey text-fd-navy hover:bg-fd-yellow/20 transition-colors text-sm"
>
@@ -250,7 +256,7 @@ export const HeaderNav: React.FC<{ data: HeaderType }> = ({ data }) => {
) : (
{item.label}
@@ -326,7 +332,7 @@ export const HeaderNav: React.FC<{ data: HeaderType }> = ({ data }) => {
{item.children!.map((child, j) => (
@@ -338,7 +344,7 @@ export const HeaderNav: React.FC<{ data: HeaderType }> = ({ data }) => {
) : (
diff --git a/src/Header/config.ts b/src/Header/config.ts
index 0612e46..7b70546 100644
--- a/src/Header/config.ts
+++ b/src/Header/config.ts
@@ -7,6 +7,49 @@ export const Header: GlobalConfig = {
read: () => true,
},
fields: [
+ // ── Logo link ─────────────────────────────────────────────────────────────
+ {
+ name: 'logoLink',
+ type: 'group',
+ label: 'Logotyplänk',
+ admin: {
+ description: 'Vart man hamnar när man klickar på logotypen. Standard är startsidan (/).',
+ },
+ fields: [
+ {
+ name: 'type',
+ type: 'radio',
+ label: 'Länktyp',
+ options: [
+ { label: 'Intern sida', value: 'reference' },
+ { label: 'Anpassad URL', value: 'custom' },
+ ],
+ defaultValue: 'custom',
+ admin: { layout: 'horizontal' },
+ },
+ {
+ name: 'reference',
+ type: 'relationship',
+ label: 'Intern sida',
+ relationTo: ['pages'] as const,
+ admin: {
+ condition: (_, siblingData) => siblingData?.type === 'reference',
+ },
+ },
+ {
+ name: 'url',
+ type: 'text',
+ label: 'URL',
+ defaultValue: '/',
+ admin: {
+ condition: (_, siblingData) => siblingData?.type === 'custom',
+ description: 'T.ex. / eller /startsida',
+ },
+ },
+ ],
+ },
+
+ // ── Nav items ─────────────────────────────────────────────────────────────
{
name: 'navItems',
type: 'array',
@@ -22,13 +65,43 @@ export const Header: GlobalConfig = {
name: 'label',
type: 'text',
required: true,
- label: 'Label',
+ label: 'Etikett',
+ },
+ // ── Link type toggle ────────────────────────────────────────────────
+ {
+ name: 'type',
+ type: 'radio',
+ label: 'Länktyp',
+ options: [
+ { label: 'Intern sida', value: 'reference' },
+ { label: 'Anpassad URL', value: 'custom' },
+ ],
+ defaultValue: 'custom',
+ admin: {
+ layout: 'horizontal',
+ description:
+ 'Lämna tomt / ignoreras om detta objekt har en undermeny.',
+ },
+ },
+ {
+ name: 'reference',
+ type: 'relationship',
+ label: 'Intern sida',
+ relationTo: ['pages'] as const,
+ admin: {
+ condition: (_, siblingData) => siblingData?.type === 'reference',
+ },
},
{
name: 'url',
type: 'text',
- label: 'URL (leave empty if this item has a submenu)',
+ label: 'URL',
+ admin: {
+ condition: (_, siblingData) => siblingData?.type === 'custom',
+ description: 'T.ex. /bredband eller https://extern-sida.se',
+ },
},
+ // ── Mega menu toggle ────────────────────────────────────────────────
{
name: 'megaMenu',
type: 'checkbox',
@@ -36,17 +109,18 @@ export const Header: GlobalConfig = {
defaultValue: false,
admin: {
description:
- 'When checked, hovering/clicking this item opens a full-width mega menu instead of a small dropdown card.',
+ 'När ikryssad öppnar hover/klick ett fullbredds mega menu istället för en liten dropdown.',
},
},
+ // ── Children ────────────────────────────────────────────────────────
{
name: 'children',
type: 'array',
- label: 'Submenu links',
+ label: 'Undermenylänkar',
maxRows: 16,
admin: {
description:
- 'Add submenu links. If these exist, the parent URL is ignored. Use "Group" to create columns in the mega menu.',
+ 'Lägg till undermenylänkar. Om dessa finns ignoreras förälderlänken. Använd "Grupp" för att skapa kolumner i mega menu.',
initCollapsed: true,
},
fields: [
@@ -54,21 +128,43 @@ export const Header: GlobalConfig = {
name: 'label',
type: 'text',
required: true,
- label: 'Label',
+ label: 'Etikett',
+ },
+ {
+ name: 'type',
+ type: 'radio',
+ label: 'Länktyp',
+ options: [
+ { label: 'Intern sida', value: 'reference' },
+ { label: 'Anpassad URL', value: 'custom' },
+ ],
+ defaultValue: 'custom',
+ admin: { layout: 'horizontal' },
+ },
+ {
+ name: 'reference',
+ type: 'relationship',
+ label: 'Intern sida',
+ relationTo: ['pages'] as const,
+ admin: {
+ condition: (_, siblingData) => siblingData?.type === 'reference',
+ },
},
{
name: 'url',
type: 'text',
- required: true,
label: 'URL',
+ admin: {
+ condition: (_, siblingData) => siblingData?.type === 'custom',
+ },
},
{
name: 'group',
type: 'text',
- label: 'Group (optional)',
+ label: 'Grupp (valfri)',
admin: {
description:
- 'Links with the same group name appear together in a separate column in the mega menu. Leave empty for the main column.',
+ 'Länkar med samma gruppnamn visas tillsammans i en separat kolumn i mega menu. Lämna tomt för huvudkolumnen.',
},
},
],
diff --git a/src/collections/Pages/index.ts b/src/collections/Pages/index.ts
index f881586..3826ea2 100644
--- a/src/collections/Pages/index.ts
+++ b/src/collections/Pages/index.ts
@@ -46,8 +46,8 @@ import {
PreviewField,
} from '@payloadcms/plugin-seo/fields'
-// ── Slug generator — handles Swedish characters ────────────────────────────
-const generateSlug = (value: string): string =>
+// ── Slug generator — handles Swedish characters ────────────────────────────────
+const generateSlugFromTitle = (value: string): string =>
value
.toLowerCase()
.trim()
@@ -131,7 +131,7 @@ export const Pages: CollectionConfig<'pages'> = {
FDVideoBlock,
FDCtaBannerBlock,
FDTestimonialBlock,
- FDTeamBlock
+ FDTeamBlock,
],
required: true,
admin: {
@@ -173,7 +173,7 @@ export const Pages: CollectionConfig<'pages'> = {
position: 'sidebar',
},
},
- // ── Slug ──────────────────────────────────────────────────────────────
+ // ── Slug ─────────────────────────────────────────────────────────────────
{
name: 'slug',
type: 'text',
@@ -181,14 +181,34 @@ export const Pages: CollectionConfig<'pages'> = {
index: true,
admin: {
position: 'sidebar',
- description: 'Genereras automatiskt från titeln.',
+ description:
+ 'Sidans URL-slug, t.ex. "om-oss" → fiberdirekt.se/om-oss. Kan alltid redigeras manuellt. Bocka i "Generera slug" nedan för att skriva om automatiskt från titeln.',
},
hooks: {
beforeChange: [
- ({ data }) => generateSlug(data?.title || ''),
+ ({ data, siblingData, value }) => {
+ // Only auto-generate if the checkbox is explicitly checked
+ if (siblingData?.generateSlug) {
+ return generateSlugFromTitle(data?.title || siblingData?.title || '')
+ }
+ // Otherwise keep whatever value the editor typed (or the existing value)
+ return value
+ },
],
},
- }, // ← slug object closes here, then straight into ],
+ },
+ // ── Auto-generate toggle ──────────────────────────────────────────────────
+ {
+ name: 'generateSlug',
+ type: 'checkbox',
+ label: 'Generera slug automatiskt från titeln',
+ defaultValue: true,
+ admin: {
+ position: 'sidebar',
+ description:
+ 'När ikryssad skrivs slugen om från titeln vid varje sparning. Avbocka för att låsa slugen och redigera den manuellt.',
+ },
+ },
],
hooks: {
afterChange: [revalidatePage],