Add replaceable placeholder images with unique img src paths.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-13 14:11:30 +03:30
co-authored by Cursor
parent 141f1a30be
commit 1272977923
53 changed files with 302 additions and 19 deletions
+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="#fef2f2"/>
<line x1="0" y1="0" x2="1280" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
<line x1="1280" y1="0" x2="0" y2="720" stroke="#fca5a5" stroke-width="2" stroke-dasharray="12 10"/>
</svg>

After

Width:  |  Height:  |  Size: 352 B

+2
View File
@@ -44,6 +44,8 @@ export function AboutSanihome() {
</div>
</div>
<Placeholder
src="/images/about.svg"
alt="درباره سانی‌هوم"
width="100%"
height="360px"
label="560×360"
+2
View File
@@ -19,6 +19,8 @@ export function BlogCarousel() {
className="w-[280px] shrink-0 overflow-hidden rounded-xl border border-border bg-surface transition-shadow hover:shadow-md md:w-[300px]"
>
<Placeholder
src={post.image}
alt={post.title}
width="100%"
height="160px"
label="300×160"
@@ -20,6 +20,8 @@ export function FeaturedCategories() {
style={{ animationDelay: `${i * 60}ms` }}
>
<Placeholder
src={cat.image}
alt={cat.name}
width="72px"
height="72px"
label="72×72"
+8
View File
@@ -7,6 +7,11 @@ import { sliderSlides } from "@/data/sample";
export function HeroSlider() {
const [active, setActive] = useState(1);
const getIndex = (offset: number) => {
const len = sliderSlides.length;
return (active + offset + len) % len;
};
const positions = [
{ offset: -1, scale: "scale-[0.92]", opacity: "opacity-55", z: "z-10" },
{ offset: 0, scale: "scale-100", opacity: "opacity-100", z: "z-20" },
@@ -19,6 +24,7 @@ export function HeroSlider() {
<div className="relative h-[220px] sm:h-[280px] md:h-[340px] lg:h-[380px]">
{positions.map(({ offset, scale, opacity, z }) => {
const isCenter = offset === 0;
const slide = sliderSlides[getIndex(offset)];
return (
<div
@@ -33,6 +39,8 @@ export function HeroSlider() {
>
<div className="overflow-hidden rounded-2xl border border-border bg-surface shadow-lg">
<Placeholder
src={slide.image}
alt={slide.title}
width="100%"
label={isCenter ? "1280×380" : "880×350"}
className={`w-full rounded-none border-0 h-[200px] sm:h-[260px] md:h-[310px] ${
+1
View File
@@ -19,6 +19,7 @@ export function SamsungCarousel() {
name={product.name}
brand={product.brand}
price={product.price}
image={product.image}
variant="brand"
/>
))}
@@ -11,6 +11,8 @@ function SpecialSaleBanner() {
className="relative w-[220px] shrink-0 self-stretch overflow-hidden rounded-xl border border-border md:w-[240px]"
>
<Placeholder
src="/images/sale-banner.svg"
alt="فروش ویژه"
width="100%"
label="240×380"
className="h-full min-h-[380px] w-full rounded-none border-0"
@@ -38,6 +40,7 @@ export function SpecialSaleCarousel() {
price={product.price}
oldPrice={product.oldPrice}
discount={product.discount}
image={product.image}
variant="sale"
/>
))}
+5 -3
View File
@@ -1,9 +1,9 @@
import { Placeholder } from "@/components/ui/Placeholder";
const banners = [
{ title: "ماشین لباسشویی", subtitle: "از ۲۸ میلیون", label: "420×160" },
{ title: "جاروبرقی", subtitle: "ارسال فوری", label: "420×160" },
{ title: "لوازم آشپزخانه", subtitle: "تا ۲۰٪ تخفیف", label: "420×160" },
{ title: "ماشین لباسشویی", subtitle: "از ۲۸ میلیون", label: "420×160", image: "/images/promo-1.svg" },
{ title: "جاروبرقی", subtitle: "ارسال فوری", label: "420×160", image: "/images/promo-2.svg" },
{ title: "لوازم آشپزخانه", subtitle: "تا ۲۰٪ تخفیف", label: "420×160", image: "/images/promo-3.svg" },
];
export function ThreeBanners() {
@@ -18,6 +18,8 @@ export function ThreeBanners() {
className="group relative overflow-hidden rounded-xl border border-border bg-surface transition-all hover:border-red hover:shadow-md"
>
<Placeholder
src={banner.image}
alt={banner.title}
width="100%"
height="160px"
label={banner.label}
@@ -19,6 +19,7 @@ export function TopSellingCarousel() {
name={product.name}
brand={product.brand}
price={product.price}
image={product.image}
/>
))}
</Carousel>
+16 -2
View File
@@ -9,7 +9,14 @@ export function TwoBanners() {
href="#"
className="group relative overflow-hidden rounded-2xl border border-border bg-surface transition-shadow hover:shadow-lg"
>
<Placeholder width="100%" height="200px" label="640×200" className="w-full rounded-none border-0" />
<Placeholder
src="/images/banner-1.svg"
alt="تخفیف ویژه یخچال و فریزر"
width="100%"
height="200px"
label="640×200"
className="w-full rounded-none border-0"
/>
<div className="absolute inset-0 flex flex-col justify-end bg-gradient-to-t from-red-dark/80 to-transparent p-6">
<p className="font-display text-xs tracking-widest text-red-muted uppercase">
Summer Sale
@@ -22,7 +29,14 @@ export function TwoBanners() {
href="#"
className="group relative overflow-hidden rounded-2xl border border-border bg-surface transition-shadow hover:shadow-lg"
>
<Placeholder width="100%" height="200px" label="640×200" className="w-full rounded-none border-0" />
<Placeholder
src="/images/banner-2.svg"
alt="تلویزیون‌های هوشمند ۲۰۲۶"
width="100%"
height="200px"
label="640×200"
className="w-full rounded-none border-0"
/>
<div className="absolute inset-0 flex flex-col justify-end bg-gradient-to-t from-red-dark/80 to-transparent p-6">
<p className="font-display text-xs tracking-widest text-red-muted uppercase">
Smart TV
+14 -5
View File
@@ -1,4 +1,6 @@
type PlaceholderProps = {
src: string;
alt?: string;
width: string;
height?: string;
label?: string;
@@ -6,6 +8,8 @@ type PlaceholderProps = {
};
export function Placeholder({
src,
alt = "",
width,
height,
label,
@@ -15,12 +19,17 @@ export function Placeholder({
<div
className={`relative flex shrink-0 items-center justify-center overflow-hidden border border-dashed border-red-muted/60 bg-red-light/40 ${className}`}
style={{ width, ...(height ? { height } : {}) }}
aria-hidden="true"
>
<div className="absolute inset-0 bg-[linear-gradient(135deg,transparent_45%,rgba(220,38,38,0.06)_50%,transparent_55%)]" />
<span className="font-display relative z-10 text-xs tracking-wider text-red-dark/50 uppercase">
{label ?? `${width} × ${height ?? ""}`}
</span>
<img
src={src}
alt={alt}
className="absolute inset-0 h-full w-full object-cover"
/>
{label && (
<span className="font-display pointer-events-none relative z-10 rounded bg-white/70 px-1.5 py-0.5 text-xs tracking-wider text-red-dark/50 uppercase">
{label}
</span>
)}
</div>
);
}
+10 -1
View File
@@ -7,6 +7,7 @@ type ProductCardProps = {
price: number;
oldPrice?: number;
discount?: number;
image: string;
variant?: "sale" | "default" | "brand";
};
@@ -16,12 +17,20 @@ export function ProductCard({
price,
oldPrice,
discount,
image,
variant = "default",
}: ProductCardProps) {
return (
<article className="group w-[220px] shrink-0 overflow-hidden rounded-xl border border-border bg-surface transition-shadow hover:shadow-md md:w-[240px]">
<div className="relative">
<Placeholder width="100%" height="200px" label="240×200" className="w-full rounded-none border-0 border-b border-dashed" />
<Placeholder
src={image}
alt={name}
width="100%"
height="200px"
label="240×200"
className="w-full rounded-none border-0 border-b border-dashed"
/>
{discount && (
<span className="absolute top-3 right-3 rounded-md bg-red px-2 py-0.5 text-xs font-bold text-white">
{discount}٪
+33 -8
View File
@@ -1,12 +1,12 @@
export const categories = [
{ id: 1, name: "یخچال و فریزر", count: 48 },
{ id: 2, name: "ماشین لباسشویی", count: 36 },
{ id: 3, name: "تلویزیون", count: 52 },
{ id: 4, name: "جاروبرقی", count: 29 },
{ id: 5, name: "مایکروویو", count: 18 },
{ id: 6, name: "ظرفشویی", count: 22 },
{ id: 7, name: "کولر و گرمایش", count: 31 },
{ id: 8, name: "لوازم آشپزخانه", count: 64 },
{ id: 1, name: "یخچال و فریزر", count: 48, image: "/images/category-1.svg" },
{ id: 2, name: "ماشین لباسشویی", count: 36, image: "/images/category-2.svg" },
{ id: 3, name: "تلویزیون", count: 52, image: "/images/category-3.svg" },
{ id: 4, name: "جاروبرقی", count: 29, image: "/images/category-4.svg" },
{ id: 5, name: "مایکروویو", count: 18, image: "/images/category-5.svg" },
{ id: 6, name: "ظرفشویی", count: 22, image: "/images/category-6.svg" },
{ id: 7, name: "کولر و گرمایش", count: 31, image: "/images/category-7.svg" },
{ id: 8, name: "لوازم آشپزخانه", count: 64, image: "/images/category-8.svg" },
];
export const specialSaleProducts = [
@@ -17,6 +17,7 @@ export const specialSaleProducts = [
price: 89500000,
oldPrice: 102000000,
discount: 12,
image: "/images/product-1.svg",
},
{
id: 2,
@@ -25,6 +26,7 @@ export const specialSaleProducts = [
price: 42800000,
oldPrice: 48500000,
discount: 11,
image: "/images/product-2.svg",
},
{
id: 3,
@@ -33,6 +35,7 @@ export const specialSaleProducts = [
price: 56200000,
oldPrice: 62000000,
discount: 9,
image: "/images/product-3.svg",
},
{
id: 4,
@@ -41,6 +44,7 @@ export const specialSaleProducts = [
price: 18900000,
oldPrice: 23500000,
discount: 19,
image: "/images/product-4.svg",
},
{
id: 5,
@@ -49,6 +53,7 @@ export const specialSaleProducts = [
price: 12400000,
oldPrice: 14800000,
discount: 16,
image: "/images/product-5.svg",
},
{
id: 6,
@@ -57,6 +62,7 @@ export const specialSaleProducts = [
price: 35600000,
oldPrice: 39900000,
discount: 10,
image: "/images/product-6.svg",
},
];
@@ -67,6 +73,7 @@ export const topSellingProducts = [
brand: "LG",
price: 67800000,
sold: 124,
image: "/images/product-7.svg",
},
{
id: 8,
@@ -74,6 +81,7 @@ export const topSellingProducts = [
brand: "LG",
price: 98500000,
sold: 89,
image: "/images/product-8.svg",
},
{
id: 9,
@@ -81,6 +89,7 @@ export const topSellingProducts = [
brand: "Samsung",
price: 38900000,
sold: 156,
image: "/images/product-9.svg",
},
{
id: 10,
@@ -88,6 +97,7 @@ export const topSellingProducts = [
brand: "Gree",
price: 24500000,
sold: 203,
image: "/images/product-10.svg",
},
{
id: 11,
@@ -95,6 +105,7 @@ export const topSellingProducts = [
brand: "Bosch",
price: 16800000,
sold: 67,
image: "/images/product-11.svg",
},
{
id: 12,
@@ -102,6 +113,7 @@ export const topSellingProducts = [
brand: "Samsung",
price: 8900000,
sold: 178,
image: "/images/product-12.svg",
},
];
@@ -111,36 +123,42 @@ export const samsungProducts = [
name: "یخچال Bespoke سامسونگ",
brand: "Samsung",
price: 112000000,
image: "/images/product-13.svg",
},
{
id: 14,
name: "ماشین لباسشویی AI EcoBubble",
brand: "Samsung",
price: 45600000,
image: "/images/product-14.svg",
},
{
id: 15,
name: "تلویزیون Neo QLED 8K",
brand: "Samsung",
price: 185000000,
image: "/images/product-15.svg",
},
{
id: 16,
name: "جاروبرقی Jet ۹۰",
brand: "Samsung",
price: 21500000,
image: "/images/product-16.svg",
},
{
id: 17,
name: "مایکروویو Grill سامسونگ",
brand: "Samsung",
price: 13800000,
image: "/images/product-17.svg",
},
{
id: 18,
name: "کولر گازی WindFree",
brand: "Samsung",
price: 32800000,
image: "/images/product-18.svg",
},
];
@@ -151,6 +169,7 @@ export const blogPosts = [
excerpt: "نکات مهم برای انتخاب یخچال با توجه به فضای آشپزخانه و تعداد اعضای خانواده.",
date: "۱۲ مرداد ۱۴۰۵",
readTime: "۵ دقیقه",
image: "/images/blog-1.svg",
},
{
id: 2,
@@ -158,6 +177,7 @@ export const blogPosts = [
excerpt: "تفاوت‌های فنی و کاربردی دو تکنولوژی محبوب نمایشگر در سال ۱۴۰۵.",
date: "۸ مرداد ۱۴۰۵",
readTime: "۷ دقیقه",
image: "/images/blog-2.svg",
},
{
id: 3,
@@ -165,6 +185,7 @@ export const blogPosts = [
excerpt: "راهکارهای عملی برای صرفه‌جویی در قبض برق با استفاده هوشمند از لوازم برقی.",
date: "۳ مرداد ۱۴۰۵",
readTime: "۴ دقیقه",
image: "/images/blog-3.svg",
},
{
id: 4,
@@ -172,6 +193,7 @@ export const blogPosts = [
excerpt: "نگاهی به سری Bespoke و Neo QLED در نمایشگاه لوازم خانگی امسال.",
date: "۲۸ تیر ۱۴۰۵",
readTime: "۶ دقیقه",
image: "/images/blog-4.svg",
},
];
@@ -181,18 +203,21 @@ export const sliderSlides = [
title: "جشنواره تابستانه لوازم خانگی",
subtitle: "تا ۳۰٪ تخفیف روی برندهای منتخب",
cta: "مشاهده پیشنهادها",
image: "/images/slider-1.svg",
},
{
id: 2,
title: "سری جدید Samsung Bespoke",
subtitle: "طراحی هوشمند برای آشپزخانه مدرن",
cta: "کاوش مجموعه",
image: "/images/slider-2.svg",
},
{
id: 3,
title: "ارسال رایگان به سراسر کشور",
subtitle: "برای سفارش‌های بالای ۵ میلیون تومان",
cta: "خرید کنید",
image: "/images/slider-3.svg",
},
];