Opravit nezobrazování obrázků na webu
Payload skládá URL uploadů absolutně podle serverURL. next/image to vyhodnotí jako externí zdroj a bez images.remotePatterns odmítne s HTTP 400 "url parameter is not allowed" — samotný soubor se přitom servíruje správně, takže se to projevilo až s nahraným obrázkem. Do next/image proto posíláme jen cestu (helper cestaKSouboru). Soubor leží na stejném originu jako web, takže je to korektní, a navíc na tom nezávisí doména: remotePatterns se zapékají při buildu, ale tentýž image běží na stagingu i v produkci pod jiným jménem. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -27,3 +27,8 @@ verzování [sémantické](https://semver.org/lang/cs/).
|
|||||||
- Adresáře `data/` a `media/` jsou v repu přes `.gitkeep`. SQLite si adresář
|
- Adresáře `data/` a `media/` jsou v repu přes `.gitkeep`. SQLite si adresář
|
||||||
nevytvoří, takže po čerstvém `git clone` padaly testy i `payload migrate`
|
nevytvoří, takže po čerstvém `git clone` padaly testy i `payload migrate`
|
||||||
na `SQLITE_CANTOPEN` (kód 14) — projevilo se to až v CI.
|
na `SQLITE_CANTOPEN` (kód 14) — projevilo se to až v CI.
|
||||||
|
- Obrázky se na webu nezobrazovaly. Payload vrací absolutní URL podle
|
||||||
|
`serverURL`, což `next/image` bere jako cizí zdroj a bez `remotePatterns`
|
||||||
|
odmítne s HTTP 400 „url parameter is not allowed". Do `next/image` se nově
|
||||||
|
posílá jen cesta — soubor leží na stejném originu a stejný image tak funguje
|
||||||
|
na stagingu i v produkci, kde se domény liší.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import React from 'react'
|
|||||||
|
|
||||||
import config from '@/payload.config'
|
import config from '@/payload.config'
|
||||||
import type { Media, Product } from '@/payload-types'
|
import type { Media, Product } from '@/payload-types'
|
||||||
import { formatujCenu, popisStavu } from '@/lib/format'
|
import { cestaKSouboru, formatujCenu, popisStavu } from '@/lib/format'
|
||||||
import '../../styles.css'
|
import '../../styles.css'
|
||||||
|
|
||||||
export const dynamic = 'force-dynamic'
|
export const dynamic = 'force-dynamic'
|
||||||
@@ -59,7 +59,7 @@ export default async function DetailPolozky({ params }: Props) {
|
|||||||
<Image
|
<Image
|
||||||
key={obrazek.id}
|
key={obrazek.id}
|
||||||
alt={obrazek.alt ?? polozka.nazev}
|
alt={obrazek.alt ?? polozka.nazev}
|
||||||
src={url}
|
src={cestaKSouboru(url)}
|
||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
sizes="(max-width: 900px) 100vw, 800px"
|
sizes="(max-width: 900px) 100vw, 800px"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import React from 'react'
|
|||||||
|
|
||||||
import config from '@/payload.config'
|
import config from '@/payload.config'
|
||||||
import type { Media, Product } from '@/payload-types'
|
import type { Media, Product } from '@/payload-types'
|
||||||
import { formatujCenu, popisStavu } from '@/lib/format'
|
import { cestaKSouboru, formatujCenu, popisStavu } from '@/lib/format'
|
||||||
import './styles.css'
|
import './styles.css'
|
||||||
|
|
||||||
// Obsah se čte z CMS při každém požadavku — jinak by se úprava položky
|
// Obsah se čte z CMS při každém požadavku — jinak by se úprava položky
|
||||||
@@ -86,5 +86,5 @@ function prvniObrazek(polozka: Product) {
|
|||||||
|
|
||||||
if (!url || !width || !height) return null
|
if (!url || !width || !height) return null
|
||||||
|
|
||||||
return { url, width, height, alt: media.alt ?? polozka.nazev }
|
return { url: cestaKSouboru(url), width, height, alt: media.alt ?? polozka.nazev }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,22 @@
|
|||||||
import type { Product } from '@/payload-types'
|
import type { Product } from '@/payload-types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payload skládá URL obrázků absolutně podle `serverURL`
|
||||||
|
* (`https://…/api/media/file/x.png`). `next/image` by to bral jako cizí zdroj
|
||||||
|
* a bez `remotePatterns` ho odmítne s „url parameter is not allowed".
|
||||||
|
*
|
||||||
|
* Doménu proto zahazujeme — soubor leží na stejném originu jako web. Navíc
|
||||||
|
* je tím stejný image použitelný na stagingu i v produkci, kde se domény liší;
|
||||||
|
* `remotePatterns` se zapékají při buildu, takže by to jinak nešlo.
|
||||||
|
*/
|
||||||
|
export function cestaKSouboru(url: string): string {
|
||||||
|
try {
|
||||||
|
return new URL(url).pathname
|
||||||
|
} catch {
|
||||||
|
return url // už je relativní
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** `28900` → `28 900 Kč` (pevná mezera, ať se cena nezalomí). */
|
/** `28900` → `28 900 Kč` (pevná mezera, ať se cena nezalomí). */
|
||||||
export function formatujCenu(cena: number): string {
|
export function formatujCenu(cena: number): string {
|
||||||
return `${cena.toLocaleString('cs-CZ').replace(/\s/g, ' ')} Kč`
|
return `${cena.toLocaleString('cs-CZ').replace(/\s/g, ' ')} Kč`
|
||||||
|
|||||||
Reference in New Issue
Block a user