Skip to main content

Prerequisites

Ficha Dubai is a vanilla JavaScript application with minimal requirements:
  • A modern web browser (Chrome, Firefox, Safari, Edge)
  • A local web server (for development)
  • A text editor (VS Code, Sublime, etc.)
No build tools, no npm packages, no framework dependencies. Everything runs directly in the browser.

File Structure

Here’s the complete file structure you’ll be working with:
ficha-dubai/
├── index.html              # Main property page template
├── app.js                  # Core JavaScript logic (690 lines)
├── styles.css              # Optional custom styles (330 lines)
├── property-5157395.json   # Sample property data
└── images/                 # Property images directory
    ├── venta-594a5fafcf-1.webp
    ├── venta-cca6e41506-2.webp
    └── ...

Core Dependencies

All dependencies are loaded via CDN in the HTML head section:

Tailwind CSS (via CDN)

<!-- index.html:7 -->
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,container-queries"></script>
Includes the forms, typography, and container-queries plugins for enhanced styling.

Google Fonts

<!-- index.html:8-9 -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Plus+Jakarta+Sans:wght@600;700;800&family=Material+Icons+Outlined&display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,[email protected],0..1&display=swap" rel="stylesheet"/>
Font families used:
  • Inter: Body text and general UI elements
  • Plus Jakarta Sans: Display headings and prominent text
  • Material Icons/Symbols: All icons throughout the interface
The icon fonts provide a scalable, lightweight alternative to icon libraries. No SVG files needed!

Installation Steps

1

Create Project Directory

Set up your project folder structure:
mkdir ficha-dubai
cd ficha-dubai

# Create subdirectories
mkdir images
2

Add Core Files

Copy or create these files in your project root:
  • index.html - The main HTML template
  • app.js - JavaScript application logic
  • styles.css - Custom CSS (optional)
  • property-5157395.json - Property data
The styles.css file is optional since most styling comes from Tailwind. It contains only supplementary custom styles.
3

Add Property Images

Place your property images in the images/ directory. Ficha Dubai supports:
  • WebP format (recommended for best performance)
  • JPG/JPEG
  • PNG
Images are referenced in the JSON file like this:
"images": [
  {
    "url": "venta-594a5fafcf-1.webp",
    "order": 1,
    "type_img": 1,
    "title": null,
    "comment": null
  }
]
The app automatically prepends images/ to relative paths (see app.js:246-249).
4

Start Local Server

Launch a local development server:
python3 -m http.server 8000
# Visit http://localhost:8000
Do NOT open index.html directly with file:// protocol. The JavaScript fetch API requires HTTP/HTTPS to load JSON files.
5

Verify Installation

Open your browser and check:✅ Property title and details display correctly ✅ Images load in the gallery ✅ Thumbnails are clickable and pagination works ✅ Contact buttons have proper links ✅ Map shows property location ✅ Dark mode toggle works

Property Data Structure

Understanding the JSON structure is crucial for adding your own properties. Here’s the complete schema:
{
  "data": {
    "property": {
      "property_uuid": "bbb8185d-2ee3-48a4-ba7f-8fecaba6e549",
      "titulo": "Apartamento en Venta en Las Cabañas, Bello",
      "descripcion": "Apartamento en venta de 79m2...",
      "url_360": "https://apartamento-dubai.vercel.app/?m=bE7cSwnyKad",
      
      "images": [
        {
          "url": "venta-594a5fafcf-1.webp",
          "order": 1,
          "type_img": 1
        }
      ],
      
      "detalles_propiedad": {
        "area": 79.0,
        "tipo_inmueble": "Apartamento",
        "estrato": "3",
        "conjunto": "Dubai",
        "direccion": "CARRERA 58AA 31-166",
        "precio_venta": 328000000.0,
        "precio_anterior": null,
        "barriocomun": "Las Cabañas",
        "ciudad": "Bello",
        "num_habitaciones": 3,
        "num_piso": 5,
        "baños": 2,
        "garajes": 0,
        "telefono": "3015637932",
        "correo": "[email protected]",
        "anos_antiguedad": 10,
        "latitud": 6.319948999999999,
        "longitud": -75.565495
      },
      
      "caracteristicas_propiedad": [
        "Interior",
        "Balcón",
        "Conjunto Cerrado",
        "Instalación de gas"
      ],
      
      "servicios": [
        {
          "servicio": "gas",
          "estrato": 3,
          "valor": 25000
        },
        {
          "servicio": "energia",
          "estrato": 3,
          "valor": 100000
        }
      ]
    }
  },
  "success": true
}

Key Fields Explained

  • area: Private area in square meters
  • area_construida: Built area in square meters
  • tipo_inmueble: Property type (Apartamento, Casa, etc.)
  • estrato: Socioeconomic stratum (1-6 in Colombia)
  • precio_venta: Sale price in Colombian pesos (COP)
  • precio_anterior: Previous price (for showing discounts)
  • num_habitaciones: Number of bedrooms
  • baños: Number of bathrooms
  • garajes: Number of parking spaces
  • anos_antiguedad: Property age in years
  • direccion: Street address
  • barriocomun: Neighborhood name
  • ciudad: City name
  • departamento: State/department
  • latitud: Latitude for map display
  • longitud: Longitude for map display
The app uses OpenStreetMap for embedded maps (app.js:549-568).
  • telefono: Phone number for calls
  • correo: Email address
  • contacto_zona: Alternative contact number
The app automatically generates:
  • tel: links for phone calls
  • mailto: links for emails
  • WhatsApp links with country code (+57 for Colombia)
Each image object contains:
  • url: Filename or full URL
  • order: Display order (sorted automatically)
  • type_img: Image type identifier
The app handles both relative paths (prefixed with images/) and absolute URLs.
  • url_360: Link to 360° virtual tour
When present, displays:
  • Overlay button on main gallery image
  • Link button in description section

Adding Your Property Data

Create a new JSON file for each property:
1

Duplicate Template

cp property-5157395.json property-new.json
2

Update Property Information

Edit the JSON with your property details. Required fields:
  • titulo (title)
  • descripcion (description)
  • detalles_propiedad.precio_venta (price)
  • At least one image
3

Configure App to Load Your Data

Two approaches:
// In app.js:675, update the filename
const response = await fetch("./property-new.json");

Key Features Implementation

Currency Formatting

Prices are formatted using Colombian peso (COP) format:
// app.js:15-22
const formatCurrency = (value) => {
  if (!value && value !== 0) return "--";
  return new Intl.NumberFormat("es-CO", {
    style: "currency",
    currency: "COP",
    maximumFractionDigits: 0,
  }).format(value);
};
To change currency, modify the currency and style parameters. The gallery features:
  • Paginated thumbnails: 8 on desktop, 4 on mobile
  • Lightbox mode: Full-screen image viewer with keyboard navigation
  • Auto-pagination: Automatically advances pages when using arrow navigation
// Gallery configuration (app.js:31-33)
const getThumbsPerPage = () => {
  return window.innerWidth < 768 ? 4 : 8;
};

Responsive Design

Breakpoints are handled by Tailwind CSS classes. The app automatically adjusts:
  • Gallery thumbnails per page on resize
  • Header layout (stacked on mobile)
  • Contact sidebar position

Customization Tips

Change Language

All text is in Spanish by default. To translate:
  • Update HTML text in index.html
  • Update currency locale in app.js:17 ("es-CO""en-US")
  • Update property data in JSON files

Add Google Analytics

Already included! Update the tracking ID in index.html:37-43:
gtag('config', 'YOUR-GA-ID');

Modify Color Scheme

Edit Tailwind config in index.html:11-34. Custom colors:
  • primary: Main accent color
  • accent-teal: 360° tour button
  • navy-deep: Header background

Custom Styles

Add custom CSS to the <style type="text/tailwindcss"> block in index.html:45-68 or external styles.css.

Production Deployment

For production deployment:
1

Optimize Images

Convert images to WebP format and compress:
# Using cwebp
for img in images/*.jpg; do
  cwebp -q 85 "$img" -o "${img%.jpg}.webp"
done
2

Update Google Analytics ID

Replace the placeholder ID in index.html:43 with your actual tracking ID.
3

Consider CDN Alternatives

For production, consider:
  • Self-hosting Tailwind CSS for offline availability
  • Using a font hosting service or self-hosting fonts
  • Implementing a proper backend API for property data
4

Deploy Static Files

Upload all files to your web server or static hosting service:
  • Netlify
  • Vercel
  • GitHub Pages
  • AWS S3 + CloudFront
  • Any web hosting with static file support

Troubleshooting

Error: “No se pudo cargar el inmueble”Solutions:
  • Verify JSON file exists in the same directory as index.html
  • Check browser console for fetch errors
  • Ensure you’re using a web server (not file:// protocol)
  • Validate JSON syntax using jsonlint.com
Possible causes:
  • Images not in images/ directory
  • Incorrect file paths in JSON
  • File permissions issue
Check: Open browser DevTools → Network tab to see failed image requests
The toggle button (index.html:238-241) requires JavaScript. Verify:
  • app.js is loaded successfully
  • No JavaScript errors in console
  • Button is visible (bottom-left corner)
Maps require valid coordinates:
  • Check latitud and longitud fields in JSON
  • OpenStreetMap embed may be blocked by ad blockers
  • Try the “Ver en Google Maps” link as fallback

What’s Next?

Now that you have Ficha Dubai installed, explore:
  • Creating multiple property pages
  • Customizing the theme to match your brand
  • Integrating with a backend API
  • Adding property search functionality
  • Building a property listing index page
Pro Tip: Use URL parameters to dynamically load different properties. Modify app.js to read a ?property= parameter and fetch the corresponding JSON file.

Build docs developers (and LLMs) love