Skip to main content

Overview

Property images are stored in the images array within the property object. Each image object contains metadata about the image file, display order, and optional descriptive information.

Image Object Structure

url
string
required
Image filename or URLThe application prepends images/ to relative paths unless the URL starts with http.Example: "venta-594a5fafcf-1.webp"
order
number
required
Display order of the image (1-based)Images are sorted by this field in ascending order before rendering.Example: 1, 2, 3
type_img
number
required
Image type identifierUsed to categorize images (e.g., interior, exterior, amenities).Example: 1
title
string
Optional image titleTypically null in the current implementation.Example: null or "Living Room View"
comment
string
Optional image comment or descriptionTypically null in the current implementation.Example: null or "View from balcony"

Example Image Array

"images": [
  {
    "url": "venta-594a5fafcf-1.webp",
    "order": 1,
    "type_img": 1,
    "title": null,
    "comment": null
  },
  {
    "url": "venta-cca6e41506-2.webp",
    "order": 2,
    "type_img": 1,
    "title": null,
    "comment": null
  },
  {
    "url": "venta-130542346a-3.webp",
    "order": 3,
    "type_img": 1,
    "title": null,
    "comment": null
  }
]

Image Processing & Rendering

Normalization

Images are processed in the normalizeProperty() function (app.js:574-579):
const images = Array.isArray(property?.images)
  ? property.images
      .slice()
      .sort((a, b) => (a.order || 0) - (b.order || 0))
      .map((img) => img.url || img)
  : [];
Key behaviors:
  • Array validation: Ensures images is an array
  • Sorting: Images are sorted by order field (ascending)
  • URL extraction: Maps objects to their url property
  • Fallback: Returns empty array if images are invalid

URL Resolution

Image URLs are resolved in renderGallery() (app.js:247-249):
const resolvedImages = images.length
  ? images.map((img) => (img.startsWith("http") ? img : `images/${img}`))
  : ["https://via.placeholder.com/1200x750?text=Sin+imagen"];
Resolution rules:
  • Absolute URLs: URLs starting with http are used as-is
  • Relative URLs: Prepended with images/ directory
  • Missing images: Placeholder image is shown when array is empty
Images are rendered in three locations:
  1. Main Gallery (app.js:237-392)
    • Large preview image
    • Thumbnail strip with pagination (4 on mobile, 8 on desktop)
    • Navigation arrows for main image
    • Click to open lightbox
  2. Lightbox (app.js:54-212)
    • Full-screen image viewer
    • Thumbnail navigation (8 per page)
    • Keyboard navigation (Arrow keys, Escape)
    • Image counter (e.g., “3 / 15”)
  3. 360° Tour Button
    • Displayed on first image only when url_360 exists
    • Visibility controlled by index === 0 check

Sorting Behavior

The order field determines display sequence:
.sort((a, b) => (a.order || 0) - (b.order || 0))
  • Images without an order field default to 0
  • Ascending numeric sort
  • Maintains original order for equal values

Image Count Display

The photo count is displayed in the gallery header (app.js:256-259):
const photoCount = $("#photo-count");
if (photoCount) {
  photoCount.textContent = resolvedImages.length;
}

Responsive Behavior

Thumbnail pagination adjusts based on screen size:
const getThumbsPerPage = () => {
  return window.innerWidth < 768 ? 4 : 8;
};
  • Mobile (less than 768px): 4 thumbnails per page
  • Desktop (768px and above): 8 thumbnails per page
  • Window resize triggers thumbnail re-render

Common Patterns

Checking for Images

if (!images || !images.length) {
  // Show placeholder
  return ["https://via.placeholder.com/1200x750?text=Sin+imagen"];
}

Opening Lightbox at Specific Image

openLightbox(imageIndex); // 0-based index

Double-Click to Zoom

thumb.addEventListener("dblclick", () => openLightbox(i));
  • Property Schema - Parent property object
  • Gallery component - renderGallery() in app.js:237
  • Lightbox component - initLightbox() in app.js:183

Build docs developers (and LLMs) love