diff --git a/app/[locale]/MenuClient.tsx b/app/[locale]/MenuClient.tsx
index 513fccb..1526a60 100644
--- a/app/[locale]/MenuClient.tsx
+++ b/app/[locale]/MenuClient.tsx
@@ -2,6 +2,7 @@
import React, { useEffect, useState, useRef, Fragment } from "react";
import { motion, AnimatePresence } from "framer-motion";
+import Image from "next/image";
import { MenuCategory, MenuItem as MenuItemType } from "@/data/menu";
import { CategoryNav } from "@/components/CategoryNav";
import { MenuItem } from "@/components/MenuItem";
@@ -294,7 +295,13 @@ export default function MenuClient({ initialCategories, siteSettings }: { initia
>
{selectedItem.image && (
-

+
{item.image && (
-
-
![]()
+
)}
diff --git a/lib/openinary-loader.ts b/lib/openinary-loader.ts
new file mode 100644
index 0000000..2678883
--- /dev/null
+++ b/lib/openinary-loader.ts
@@ -0,0 +1,39 @@
+'use client'
+
+export default function openinaryLoader({ src, width, quality }: { src: string, width: number, quality?: number }) {
+ // Handle already absolute openinary URLs
+ let path = src;
+ if (src.startsWith('https://media.ayris.tech/t/')) {
+ // format: https://media.ayris.tech/t/w_800,h_800/moyqr/img.jpg
+ const parts = src.split('/');
+ path = parts.slice(5).join('/');
+ } else if (src.startsWith('https://media.ayris.tech/upload/')) {
+ // format: https://media.ayris.tech/upload/moyqr/img.jpg
+ const parts = src.split('/');
+ path = parts.slice(4).join('/');
+ } else if (src.includes('res.cloudinary.com')) {
+ // Correctly apply width & quality for unmigrated Cloudinary URLs
+ // e.g. https://res.cloudinary.com/domain/image/upload/v1234/path.jpg
+ // becomes: https://res.cloudinary.com/domain/image/upload/w_800,f_webp,q_75/v1234/path.jpg
+ const parts = src.split('/upload/');
+ if (parts.length === 2) {
+ return `${parts[0]}/upload/w_${width},f_webp,q_${quality || 75}/${parts[1]}`;
+ }
+ return src;
+ } else if (src.startsWith('http')) {
+ // For other external URLs, we append the width as a query parameter to satisfy Next.js.
+ const url = new URL(src);
+ url.searchParams.set('w', width.toString());
+ if (quality) {
+ url.searchParams.set('q', quality.toString());
+ }
+ return url.toString();
+ }
+
+ // Clean up any leading slash
+ if (path.startsWith('/')) {
+ path = path.substring(1);
+ }
+
+ return `https://media.ayris.tech/t/w_${width},f_webp,q_${quality || 75}/${path}`
+}
diff --git a/next.config.ts b/next.config.ts
index 5dc0219..4259f43 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -6,6 +6,8 @@ const withNextIntl = createNextIntlPlugin('./i18n/request.ts');
const nextConfig: NextConfig = {
output: "standalone",
images: {
+ loader: 'custom',
+ loaderFile: './lib/openinary-loader.ts',
remotePatterns: [
{
protocol: 'https',