feat!: replaces admin.favicon with admin.icons

This commit is contained in:
Jacob Fletcher
2024-05-13 23:51:27 -04:00
parent a48043c2aa
commit 7438812db3
16 changed files with 97 additions and 37 deletions

View File

@@ -26,6 +26,11 @@ const merriweather = Merriweather({
weight: ['400', '900'],
})
export const metadata = {
description: 'Generated by Next.js',
title: 'Next.js',
}
export const RootLayout = async ({
children,
config: configPromise,

View File

@@ -1,4 +1,5 @@
import type { Metadata } from 'next'
import type { Icon } from 'next/dist/lib/metadata/types/metadata-types.js'
import type { SanitizedConfig } from 'payload/types'
import { payloadFaviconDark, payloadFaviconLight, payloadOgImage } from '@payloadcms/ui/assets'
@@ -13,38 +14,35 @@ export const meta = async (args: {
const titleSuffix = config.admin.meta?.titleSuffix ?? '- Payload'
const customFavicon = config.admin.meta?.favicon
const customFaviconFiletype = customFavicon?.split('.').pop()
const customFaviconMediaType = `image/${customFaviconFiletype}`
const favicon = customFavicon ?? payloadFaviconLight?.src
const ogImage = config.admin?.meta?.ogImage ?? payloadOgImage?.src
return Promise.resolve({
description,
icons: [
...(customFavicon
? [
{
type: customFaviconMediaType,
rel: 'icon',
url: favicon,
},
]
: [
const customIcons = config.admin.meta.icons as Metadata['icons']
let icons = customIcons ?? []
const payloadIcons: Icon[] = [
{
type: 'image/png',
rel: 'icon',
sizes: '32x32',
url: payloadFaviconDark?.src,
},
{
type: 'image/png',
media: '(prefers-color-scheme: dark)',
rel: 'icon',
sizes: '32x32',
url: payloadFaviconLight?.src,
},
]),
],
]
if (customIcons && typeof customIcons === 'object' && Array.isArray(customIcons)) {
icons = payloadIcons.concat(customIcons)
}
return Promise.resolve({
description,
icons,
keywords,
metadataBase: new URL(
config?.serverURL ||

View File

@@ -149,6 +149,7 @@
"get-port": "5.1.1",
"graphql-http": "^1.22.0",
"mini-css-extract-plugin": "1.6.2",
"next": "^14.3.0-canary.7",
"nodemon": "3.0.3",
"object.assign": "4.1.4",
"object.entries": "1.1.6",

View File

@@ -68,7 +68,13 @@ export default joi.object({
}),
logoutRoute: joi.string(),
meta: joi.object().keys({
favicon: joi.string(),
icons: joi
.alternatives()
.try(
joi.array().items(joi.alternatives().try(joi.string(), joi.object())),
joi.object(),
joi.string().allow(null),
),
ogImage: joi.string(),
titleSuffix: joi.string(),
}),

View File

@@ -1,6 +1,7 @@
import type { I18nOptions, TFunction } from '@payloadcms/translations'
import type { Options as ExpressFileUploadOptions } from 'express-fileupload'
import type GraphQL from 'graphql'
import type { Metadata as NextMetadata } from 'next'
import type { DestinationStream, LoggerOptions, P } from 'pino'
import type React from 'react'
import type { default as sharp } from 'sharp'
@@ -460,14 +461,15 @@ export type Config = {
}
/** The route for the logout page. */
logoutRoute?: string
/** Base meta data to use for the Admin panel. Included properties are titleSuffix, ogImage, and favicon. */
/** Base meta data to use for the Admin Panel. Included properties are titleSuffix, ogImage, and favicon. */
meta?: {
/**
* Public path to an icon
* An array of Next.js metadata objects that represent icons to be used by devices and browsers.
*
* This image may be displayed in the browser next to the title of the page
* For example browser tabs, phone home screens, and search engine results.
* @reference https://nextjs.org/docs/app/api-reference/functions/generate-metadata#icons
*/
favicon?: string
icons?: NextMetadata['icons']
/**
* Public path to an image
*

View File

@@ -1,4 +1,4 @@
export { default as payloadFavicon } from '../assets/favicon.svg'
export { default as payloadFaviconDark } from '../assets/favicon-dark.png'
export { default as payloadFaviconLight } from '../assets/favicon-light.png'
export { default as payloadOgImage } from '../assets/og-image.png'
export { default as payloadFavicon } from '../assets/payload-favicon.svg'
export { default as payloadFaviconDark } from '../assets/payload-favicon-dark.png'
export { default as payloadFaviconLight } from '../assets/payload-favicon-light.png'

View File

Before

Width:  |  Height:  |  Size: 638 B

After

Width:  |  Height:  |  Size: 638 B

View File

Before

Width:  |  Height:  |  Size: 485 B

After

Width:  |  Height:  |  Size: 485 B

View File

Before

Width:  |  Height:  |  Size: 437 B

After

Width:  |  Height:  |  Size: 437 B

3
pnpm-lock.yaml generated
View File

@@ -912,6 +912,9 @@ importers:
mini-css-extract-plugin:
specifier: 1.6.2
version: 1.6.2(webpack@5.91.0)
next:
specifier: ^14.3.0-canary.7
version: 14.3.0-canary.7(@babel/core@7.24.4)(@playwright/test@1.43.0)(react-dom@18.2.0)(react@18.2.0)(sass@1.74.1)
nodemon:
specifier: 3.0.3
version: 3.0.3

View File

@@ -7,6 +7,7 @@ import { devUser } from '../credentials.js'
import { MediaCollection } from './collections/Media/index.js'
import { PostsCollection, postsSlug } from './collections/Posts/index.js'
import { MenuGlobal } from './globals/Menu/index.js'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)

View File

@@ -25,6 +25,8 @@ import { CustomMinimalView } from './components/views/CustomMinimal/index.js'
import { CustomView } from './components/views/CustomView/index.js'
import { CustomNestedView } from './components/views/CustomViewNested/index.js'
import { CustomViewWithParam } from './components/views/CustomViewWithParam/index.js'
import { default as customFaviconDark } from './custom-favicon-dark.png'
import { default as customFaviconLight } from './custom-favicon-light.png'
import { CustomGlobalViews1 } from './globals/CustomViews1.js'
import { CustomGlobalViews2 } from './globals/CustomViews2.js'
import { Global } from './globals/Global.js'
@@ -34,7 +36,6 @@ import { GlobalHidden } from './globals/Hidden.js'
import { GlobalNoApiView } from './globals/NoApiView.js'
import { seed } from './seed.js'
import { customNestedViewPath, customParamViewPath, customViewPath } from './shared.js'
export default buildConfigWithDefaults({
admin: {
components: {
@@ -74,6 +75,21 @@ export default buildConfigWithDefaults({
},
},
},
meta: {
icons: [
{
type: 'image/png',
rel: 'icon',
url: customFaviconDark.src,
},
{
type: 'image/png',
media: '(prefers-color-scheme: dark)',
rel: 'icon',
url: customFaviconLight.src,
},
],
},
},
collections: [
UploadCollection,

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 B

View File

@@ -106,6 +106,30 @@ describe('admin', () => {
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
})
describe('metadata', () => {
test('should set Payload favicons', async () => {
await page.goto(postsUrl.admin)
const favicons = page.locator('link[rel="icon"]')
await expect(favicons).toHaveCount(4)
await expect(favicons.nth(0)).toHaveAttribute('sizes', '32x32')
await expect(favicons.nth(1)).toHaveAttribute('sizes', '32x32')
await expect(favicons.nth(1)).toHaveAttribute('media', '(prefers-color-scheme: dark)')
await expect(favicons.nth(1)).toHaveAttribute(
'href',
/\/payload-favicon-light\.[a-z\d]+\.png/,
)
})
test('should inject custom favicons', async () => {
await page.goto(postsUrl.admin)
const favicons = page.locator('link[rel="icon"]')
await expect(favicons).toHaveCount(4)
await expect(favicons.nth(2)).toHaveAttribute('href', /\/custom-favicon-dark\.[a-z\d]+\.png/)
await expect(favicons.nth(3)).toHaveAttribute('media', '(prefers-color-scheme: dark)')
await expect(favicons.nth(3)).toHaveAttribute('href', /\/custom-favicon-light\.[a-z\d]+\.png/)
})
})
describe('navigation', () => {
test('nav — should navigate to collection', async () => {
await page.goto(postsUrl.admin)

4
test/admin/types.d.ts vendored Normal file
View File

@@ -0,0 +1,4 @@
declare module '*.png' {
const value: any
export = value
}