Compare commits

...

3 Commits

Author SHA1 Message Date
Jon Leopard
6f353b63f7 fix: replace image placeholders with Lucide icons
- Replace "No image" text with icon-[lucide--image] icons
- Configure iconify plugin with prefixes (lucide, hugeicons, ri)
- Fix infinite 404 loop by using proper icon system
- Use layered approach: icon underneath, image overlays when loaded
- Apply to product images, image grid, and variety images

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 21:13:20 -07:00
Jon Leopard
954a4988b5 hotfix: fix infinite 404 loop on product edit page
Replace missing placeholder.png with inline SVG data URI to stop infinite error handler loop.

The image error handler was causing 1req/sec 404 floods when images failed to load.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 20:10:47 -07:00
Jon Leopard
4ac13268d9 fix: add missing placeholder.png to stop 404 loop on product edit page
The product image error handler was causing infinite 404 requests when images failed to load. This adds a placeholder image to break the loop.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 19:30:20 -07:00
4 changed files with 25 additions and 20 deletions

28
package-lock.json generated
View File

@@ -1056,7 +1056,8 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/@svgdotjs/svg.draggable.js": {
"version": "3.0.6",
@@ -1084,7 +1085,6 @@
"resolved": "https://registry.npmjs.org/@svgdotjs/svg.js/-/svg.js-3.2.5.tgz",
"integrity": "sha512-/VNHWYhNu+BS7ktbYoVGrCmsXDh+chFMaONMwGNdIBcFHrWqk2jY8fNyr3DLdtQUIalvkPfM554ZSFa3dm3nxQ==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Fuzzyma"
@@ -1108,7 +1108,6 @@
"resolved": "https://registry.npmjs.org/@svgdotjs/svg.select.js/-/svg.select.js-4.0.3.tgz",
"integrity": "sha512-qkMgso1sd2hXKd1FZ1weO7ANq12sNmQJeGDjs46QwDVsxSRcHmvWKL2NDF7Yimpwf3sl5esOLkPqtV2bQ3v/Jg==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">= 14.18"
},
@@ -1482,7 +1481,6 @@
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.15.0.tgz",
"integrity": "sha512-lpokA5okCF1BKh10LG8YjqhfpxyHBk4gE7boIgVHltJzYoM7O9nK3M7VlntLEJGsVmu7U/RzUWajmHREGT38Eg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/reactivity": "~3.1.1"
}
@@ -1641,7 +1639,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.8.9",
"caniuse-lite": "^1.0.30001746",
@@ -2062,7 +2059,6 @@
"integrity": "sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"meow": "^13.0.0"
},
@@ -2390,7 +2386,6 @@
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"license": "ISC",
"peer": true,
"engines": {
"node": ">=12"
}
@@ -2582,6 +2577,7 @@
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz",
"integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==",
"license": "MIT",
"peer": true,
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
@@ -2595,6 +2591,7 @@
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"ms": "^2.1.3"
},
@@ -2612,6 +2609,7 @@
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10.0.0"
}
@@ -2762,8 +2760,7 @@
"version": "4.32.9",
"resolved": "https://registry.npmjs.org/filepond/-/filepond-4.32.9.tgz",
"integrity": "sha512-MnNnRrTS1M/6C/puIs5dNkbP1RMGANFxnygwdweNXAxyeCS4S68UM4CdvmyF7UrZB93Fhop7Bea2Ib6rkrYHUw==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/filepond-plugin-file-validate-type": {
"version": "1.2.9",
@@ -3731,7 +3728,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -3771,7 +3767,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -3799,7 +3794,6 @@
"resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.4.0.tgz",
"integrity": "sha512-wp3HqIIUc1GRyu1XrP6m2dgyE9MoCsXVsWNlohj0rjSkLf+a0jLvEyVubdg58oMk7bhjBWnFClgp8jfAa6Ak4Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"tweetnacl": "^1.0.3"
}
@@ -3970,6 +3964,7 @@
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
"integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
@@ -3985,6 +3980,7 @@
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"ms": "^2.1.3"
},
@@ -4002,6 +3998,7 @@
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"license": "MIT",
"peer": true,
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
@@ -4015,6 +4012,7 @@
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"ms": "^2.1.3"
},
@@ -4138,8 +4136,7 @@
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.15.tgz",
"integrity": "sha512-k2WLnWkYFkdpRv+Oby3EBXIyQC8/s1HOFMBUViwtAh6Z5uAozeUSMQlIsn/c6Q2iJzqG6aJT3wdPaRNj70iYxQ==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/tapable": {
"version": "2.3.0",
@@ -4323,7 +4320,6 @@
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
@@ -4447,6 +4443,7 @@
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10.0.0"
},
@@ -4467,6 +4464,7 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
"peer": true,
"engines": {
"node": ">=0.4.0"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -7,8 +7,10 @@
@plugin "daisyui";
/* Iconify plugin */
@plugin "@iconify/tailwind4";
/* Iconify plugin (Lucide icons) */
@plugin "@iconify/tailwind4" {
prefixes: lucide, hugeicons, ri;
}
/* Alpine.js x-cloak directive */
[x-cloak] {

View File

@@ -108,7 +108,7 @@
<img src="{{ Storage::url($product->image_path) }}" alt="{{ $product->name }}" class="w-full rounded-lg">
@else
<div class="aspect-square bg-base-200 rounded-lg flex items-center justify-center">
<span class="text-base-content/50">No image</span>
<span class="icon-[lucide--image] size-16 text-base-content/40"></span>
</div>
@endif
@@ -396,7 +396,10 @@
<template x-for="(image, index) in images" :key="image.id || index">
<div class="relative group cursor-move border-2 border-base-300 rounded-lg overflow-hidden hover:border-primary transition-colors bg-base-200"
:data-id="image.id">
<img :src="'/storage/' + image.path" alt="Product image" class="w-full h-40 object-cover" @@error="$event.target.src='/images/placeholder.png'">
<div class="flex items-center justify-center h-40">
<span class="icon-[lucide--image] size-16 text-base-content/40"></span>
</div>
<img :src="'/storage/' + image.path" alt="Product image" class="absolute inset-0 w-full h-40 object-cover" @@error="$event.target.style.display='none'">
<div class="absolute top-2 left-2">
<span class="badge badge-sm" :class="index === 0 ? 'badge-primary' : 'badge-ghost badge-outline'" x-text="index === 0 ? 'Primary' : (index + 1)"></span>
</div>
@@ -616,7 +619,9 @@
@if($variety->image_path)
<img src="{{ Storage::url($variety->image_path) }}" alt="{{ $variety->name }}">
@else
<div class="bg-base-300 w-full h-full flex items-center justify-center text-xs">No image</div>
<div class="bg-base-300 w-full h-full flex items-center justify-center">
<span class="icon-[lucide--image] size-8 text-base-content/40"></span>
</div>
@endif
</div>
</div>