fix(images) : retry failed CDN images through Cloudflare resizing
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import { ArrowLeftIcon } from "lucide-react";
|
import { ArrowLeftIcon } from "lucide-react";
|
||||||
import { notFound, redirect } from "next/navigation";
|
import { notFound, redirect } from "next/navigation";
|
||||||
import { connection } from "next/server";
|
import { connection } from "next/server";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { ArrowLeftIcon, ArrowUpRightIcon } from "lucide-react";
|
import { ArrowLeftIcon, ArrowUpRightIcon } from "lucide-react";
|
||||||
import { notFound, redirect } from "next/navigation";
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
|
|
||||||
import { SiteFooter } from "@/components/public/site-footer";
|
import { SiteFooter } from "@/components/public/site-footer";
|
||||||
import { SiteHeader } from "@/components/public/site-header";
|
import { SiteHeader } from "@/components/public/site-header";
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { ExternalLinkIcon } from "lucide-react";
|
import { ExternalLinkIcon } from "lucide-react";
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { searchItems } from "@/lib/search";
|
import { searchItems } from "@/lib/search";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { ArrowLeftIcon, CheckIcon, SearchIcon } from "lucide-react";
|
import { ArrowLeftIcon, CheckIcon, SearchIcon } from "lucide-react";
|
||||||
import { useMemo, useState, useTransition } from "react";
|
import { useMemo, useState, useTransition } from "react";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { searchItems } from "@/lib/search";
|
import { searchItems } from "@/lib/search";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import { SearchIcon, Trash2Icon } from "lucide-react";
|
import { SearchIcon, Trash2Icon } from "lucide-react";
|
||||||
import { useMemo, useState, useTransition } from "react";
|
import { useMemo, useState, useTransition } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import { closestCenter, DndContext, KeyboardSensor, PointerSensor, useSensor, useSensors, type DragEndEvent } from "@dnd-kit/core";
|
import { closestCenter, DndContext, KeyboardSensor, PointerSensor, useSensor, useSensors, type DragEndEvent } from "@dnd-kit/core";
|
||||||
import { SortableContext, arrayMove, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
import { SortableContext, arrayMove, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
||||||
import { CSS } from "@dnd-kit/utilities";
|
import { CSS } from "@dnd-kit/utilities";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { searchItems } from "@/lib/search";
|
import { searchItems } from "@/lib/search";
|
||||||
|
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import {
|
import {
|
||||||
ArrowLeftIcon,
|
ArrowLeftIcon,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import type { MouseEvent } from "react";
|
import type { MouseEvent } from "react";
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Image, { getImageProps } from "next/image";
|
import { getImageProps } from "next/image";
|
||||||
|
import Image from "@/components/ui/resilient-image";
|
||||||
import {
|
import {
|
||||||
closestCenter,
|
closestCenter,
|
||||||
DndContext,
|
DndContext,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { searchItems } from "@/lib/search";
|
import { searchItems } from "@/lib/search";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useEffect, useMemo, useRef, useState, useTransition, type ReactNode } from "react";
|
import { useEffect, useMemo, useRef, useState, useTransition, type ReactNode } from "react";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import { CircleHelpIcon } from "lucide-react";
|
import { CircleHelpIcon } from "lucide-react";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import type { ComponentProps, ReactNode } from "react";
|
import type { ComponentProps, ReactNode } from "react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import { UserRoundIcon } from "lucide-react";
|
import { UserRoundIcon } from "lucide-react";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import { UserRoundIcon, XIcon } from "lucide-react";
|
import { UserRoundIcon, XIcon } from "lucide-react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { ArtifactSelect, CharacterSelect, WeaponSelect } from "@/components/admin/ui/catalog-select";
|
import { ArtifactSelect, CharacterSelect, WeaponSelect } from "@/components/admin/ui/catalog-select";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import { ArrowUpRightIcon } from "lucide-react";
|
import { ArrowUpRightIcon } from "lucide-react";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import { MousePointerClickIcon } from "lucide-react";
|
import { MousePointerClickIcon } from "lucide-react";
|
||||||
import { Children, Fragment, type ReactNode, useState } from "react";
|
import { Children, Fragment, type ReactNode, useState } from "react";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
|
|
||||||
import { GuideExportBranding } from "@/components/public/guide-export-branding";
|
import { GuideExportBranding } from "@/components/public/guide-export-branding";
|
||||||
import { ExportText } from "@/components/public/export-language";
|
import { ExportText } from "@/components/public/export-language";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
|
|
||||||
import { elementIconFilter } from "@/lib/catalog/element";
|
import { elementIconFilter } from "@/lib/catalog/element";
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
|
|
||||||
export function GuideExportBranding({
|
export function GuideExportBranding({
|
||||||
backgroundUrl,
|
backgroundUrl,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRef, type PointerEvent } from "react";
|
import { useRef, type PointerEvent } from "react";
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { BookOpenIcon, MenuIcon } from "lucide-react";
|
import { BookOpenIcon, MenuIcon } from "lucide-react";
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
import { PencilIcon } from "lucide-react";
|
import { PencilIcon } from "lucide-react";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { searchItems } from "@/lib/search";
|
import { searchItems } from "@/lib/search";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useSearchParams } from "next/navigation";
|
import { useSearchParams } from "next/navigation";
|
||||||
import { SearchIcon, SlidersHorizontalIcon, StarIcon, UsersIcon, XIcon } from "lucide-react";
|
import { SearchIcon, SlidersHorizontalIcon, StarIcon, UsersIcon, XIcon } from "lucide-react";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import localFont from "next/font/local";
|
import localFont from "next/font/local";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { ArrowLeftIcon, ArrowUpRightIcon } from "lucide-react";
|
import { ArrowLeftIcon, ArrowUpRightIcon } from "lucide-react";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { ArrowUpRightIcon, SearchIcon, XIcon } from "lucide-react";
|
import { ArrowUpRightIcon, SearchIcon, XIcon } from "lucide-react";
|
||||||
import { Fragment, useMemo, useState, type ReactNode } from "react";
|
import { Fragment, useMemo, useState, type ReactNode } from "react";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import { DownloadIcon } from "lucide-react";
|
import { DownloadIcon } from "lucide-react";
|
||||||
import { useState, type ReactNode } from "react";
|
import { useState, type ReactNode } from "react";
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Image from "next/image";
|
import Image from "@/components/ui/resilient-image";
|
||||||
import { CheckIcon, XIcon } from "lucide-react";
|
import { CheckIcon, XIcon } from "lucide-react";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import NextImage, { type ImageProps } from "next/image";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
const CDN_ORIGIN = "https://buzz-cdn.astrxl.dev";
|
||||||
|
|
||||||
|
export default function ResilientImage({ src, unoptimized, onError, ...props }: ImageProps) {
|
||||||
|
const [fallback, setFallback] = useState<{ source: string; url: string } | null>(null);
|
||||||
|
const fallbackUrl = typeof src === "string" && fallback?.source === src ? fallback.url : null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NextImage
|
||||||
|
{...props}
|
||||||
|
src={fallbackUrl ?? src}
|
||||||
|
unoptimized={unoptimized || Boolean(fallbackUrl)}
|
||||||
|
onError={(event) => {
|
||||||
|
if (!fallbackUrl && typeof src === "string" && src.startsWith(`${CDN_ORIGIN}/`)) {
|
||||||
|
const source = new URL(src);
|
||||||
|
if (!source.pathname.startsWith("/cdn-cgi/image/")) {
|
||||||
|
const optimized = new URL(event.currentTarget.currentSrc);
|
||||||
|
const width = Number(optimized.searchParams.get("w")) || 1080;
|
||||||
|
const quality = Number(optimized.searchParams.get("q")) || 75;
|
||||||
|
setFallback({
|
||||||
|
source: src,
|
||||||
|
url: `${CDN_ORIGIN}/cdn-cgi/image/width=${width},quality=${quality},format=auto${source.pathname}${source.search}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onError?.(event);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user