HEX
Server: LiteSpeed
System: Linux srv1.dhviews.com 5.14.0-570.23.1.el9_6.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Jun 24 11:27:16 EDT 2025 x86_64
User: bdedition (1723)
PHP: 7.4.33
Disabled: NONE
Upload Files
File: //home/bdedition/bddiary.com/daripalla.html
<!DOCTYPE html>
<html lang="bn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes">
<!-- Primary Meta Tags -->
<title>দাঁড়িপাল্লায় ভোট দিন | প্রোফাইল ফ্রেম তৈরি করুন</title>
<meta name="title" content="দাঁড়িপাল্লায় ভোট দিন | প্রোফাইল ফ্রেম তৈরি করুন">
<meta name="description" content="দাঁড়িপাল্লায় ভোট দিন - প্রোফাইল ফ্রেম জেনারেটর। ছবি আপলোড করে ফ্রেম যুক্ত করুন, ডাউনলোড করুন ও ফেসবুকে শেয়ার করুন, সহজ ও নিরাপদভাবে।">
<meta name="keywords" content="দাঁড়িপাল্লা, ভোট, বাংলাদেশ, প্রোফাইল ফ্রেম, ফ্রেম তৈরি, ফ্রেম এডিটর, ভোট ফ্রেম">
<meta name="author" content="daripalla.org">
<meta name="robots" content="index, follow">
<meta name="language" content="Bengali">
<!-- Favicon -->
<link rel="icon" type="image/png" href="https://bddiary.com/assets/logo.png">
<link rel="apple-touch-icon" href="https://bddiary.com/assets/logo.png">
<link rel="shortcut icon" href="https://bddiary.com/assets/logo.png">
<!-- Open Graph / Telegram / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://daripalla.org/">
<meta property="og:title" content="দাঁড়িপাল্লায় ভোট দিন | প্রোফাইল ফ্রেম তৈরি করুন">
<meta property="og:description" content="দাঁড়িপাল্লায় ভোট দিন - প্রোফাইল ফ্রেম জেনারেটর। ছবি আপলোড করে ফ্রেম যুক্ত করুন, ডাউনলোড করুন ও ফেসবুকে শেয়ার করুন, সহজ ও নিরাপদভাবে।">
<meta property="og:image" content="https://bddiary.com/assets/logo.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="দাঁড়িপাল্লায় ভোট দিন">
<meta property="og:locale" content="bn_BD">
<meta property="og:site_name" content="দাঁড়িপাল্লা">
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:url" content="https://daripalla.org/">
<meta property="twitter:title" content="দাঁড়িপাল্লায় ভোট দিন | প্রোফাইল ফ্রেম তৈরি করুন">
<meta property="twitter:description" content="দাঁড়িপাল্লায় ভোট দিন - প্রোফাইল ফ্রেম জেনারেটর। ছবি আপলোড করে ফ্রেম যুক্ত করুন, ডাউনলোড করুন ও ফেসবুকে শেয়ার করুন, সহজ ও নিরাপদভাবে।">
<meta property="twitter:image" content="https://bddiary.com/assets/logo.png">
<meta property="twitter:image:alt" content="দাঁড়িপাল্লায় ভোট দিন">
<!-- Additional SEO -->
<meta name="theme-color" content="#16a34a">
<meta name="msapplication-TileColor" content="#16a34a">
<link rel="canonical" href="https://daripalla.org/">
<!-- Google Font - Hind Siliguri -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Hind+Siliguri:wght@400;600;700&display=swap" rel="stylesheet">
<!-- Bootstrap 5+ CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.2/font/bootstrap-icons.css">
<!-- AOS Animation Library -->
<link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet">
<!-- Custom CSS -->
<link rel="stylesheet" href="assets/css/style.css">
  <style>
    :root {
      --primary-color: #16a34a;
      --primary-dark: #15803d;
      --secondary-color: #ea580c;
      --light-bg: #f8f9fa;
      --shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
      --shadow-md: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
      --shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
    }

    * {
      -webkit-tap-highlight-color: transparent;
    }

    body {
      font-family: 'Hind Siliguri', sans-serif;
      background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
      min-height: 100vh;
    }

/* Custom Components */

/* Frames Grid Styling */
#framesGrid {
  display: flex !important;
  gap: 12px !important;
  align-items: center !important;
  min-height: 120px !important;
  padding: 8px 0 !important;
}

#framesGrid .frame-option {
  flex-shrink: 0 !important;
  opacity: 1 !important;
  visibility: visible !important;
}

#framesGrid .frame-option img {
  display: block !important;
}

/* Fix for loading states */
.frame-option .spinner-border {
  animation: spinner-border 0.75s linear infinite;
}

@keyframes spinner-border {
  to { transform: rotate(360deg); }
}

.hero-section {
  background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 50%, var(--secondary-color) 100%);
  position: relative;
  overflow: hidden;
}

.hero-section::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 100" fill="white" fill-opacity="0.1"><polygon points="0,100 100,0 200,100 300,0 400,100 500,0 600,100 700,0 800,100 900,0 1000,100 1000,200 0,200"/></svg>') repeat-x;
  animation: wave 20s linear infinite;
}

@keyframes wave {
  0% { transform: translateX(0); }
  100% { transform: translateX(-100px); }
}

.card-custom {
  background: white;
  border-radius: 20px;
  box-shadow: var(--shadow-md);
  border: 1px solid rgba(0,0,0,0.08);
  transition: all 0.3s ease;
}

.card-custom:hover {
  transform: translateY(-5px);
  box-shadow: var(--shadow-lg);
}

.btn-primary-custom {
  background: linear-gradient(135deg, var(--primary-color), var(--primary-dark));
  border: none;
  border-radius: 15px;
  font-weight: 600;
  padding: 12px 30px;
  transition: all 0.3s ease;
  box-shadow: var(--shadow-sm);
}

.btn-primary-custom:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
  background: linear-gradient(135deg, var(--primary-dark), var(--primary-color));
}

.btn-outline-custom {
  border: 2px solid var(--primary-color);
  color: var(--primary-color);
  border-radius: 15px;
  font-weight: 600;
  padding: 10px 28px;
  transition: all 0.3s ease;
}

.btn-outline-custom:hover {
  background: var(--primary-color);
  color: white;
  transform: translateY(-2px);
}

/* Custom range slider */
.form-range {
  height: 8px;
  background: linear-gradient(to right, #e9ecef, var(--primary-color));
  border-radius: 4px;
}

.form-range::-webkit-slider-thumb {
  width: 20px;
  height: 20px;
  background: var(--primary-color);
  border: 3px solid white;
  border-radius: 50%;
  box-shadow: var(--shadow-sm);
}

.form-range::-moz-range-thumb {
  width: 20px;
  height: 20px;
  background: var(--primary-color);
  border: 3px solid white;
  border-radius: 50%;
  box-shadow: var(--shadow-sm);
}

/* Preview canvas */
#previewCanvas {
  width: 100% !important;
  height: 100% !important;
  max-width: 100%;
  display: block;
  touch-action: none;
  border-radius: 15px;
}

/* Fabric.js canvas wrapper */
.canvas-container {
  width: 100% !important;
  height: 100% !important;
  max-width: 100%;
  position: relative;
  border-radius: 15px !important;
  overflow: hidden;
}

.canvas-container canvas {
  max-width: 100% !important;
  height: auto !important;
  border-radius: 15px;
}

/* Frame option */
.frame-option {
  position: relative;
  width: 100px;
  height: 100px;
  min-width: 100px;
  border-radius: 15px;
  overflow: hidden;
  cursor: pointer;
  border: 3px solid transparent;
  transition: all 0.3s ease;
  background: var(--light-bg);
  touch-action: manipulation;
  flex-shrink: 0;
}

.frame-option:hover {
  transform: scale(1.05);
  border-color: var(--primary-color);
  box-shadow: var(--shadow-md);
}

.frame-option:active {
  transform: scale(0.95);
}

.frame-option.selected {
  border-color: var(--primary-color);
  box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.2);
}

.frame-option img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Canvas container for zoom/move */
#previewContainer {
  cursor: grab;
  user-select: none;
  background: 
    linear-gradient(45deg, #e9ecef 25%, transparent 25%), 
    linear-gradient(-45deg, #e9ecef 25%, transparent 25%), 
    linear-gradient(45deg, transparent 75%, #e9ecef 75%), 
    linear-gradient(-45deg, transparent 75%, #e9ecef 75%);
  background-size: 20px 20px;
  background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
  border-radius: 15px;
}

#previewContainer:active {
  cursor: grabbing;
}

#previewContainer.has-image {
  cursor: move;
}

/* Toast */
.toast-custom {
  position: fixed;
  bottom: 30px;
  left: 50%;
  transform: translateX(-50%) translateY(100px);
  background: rgba(33, 37, 41, 0.95);
  color: white;
  padding: 16px 24px;
  border-radius: 15px;
  box-shadow: var(--shadow-lg);
  font-size: 14px;
  font-weight: 600;
  z-index: 1050;
  max-width: 90%;
  transition: transform 0.3s ease;
  backdrop-filter: blur(10px);
}

.toast-custom.show {
  transform: translateX(-50%) translateY(0);
    }

    .toast-custom.error {
      background: rgba(220, 53, 69, 0.95);
    }

    .toast-custom.success {
      background: rgba(25, 135, 84, 0.95);
    }

    /* Loading spinner */
    .spinner-custom {
      width: 40px;
      height: 40px;
      border: 3px solid rgba(255, 255, 255, 0.3);
      border-top: 3px solid white;
      border-radius: 50%;
      animation: spin 1s linear infinite;
    }

    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }

    /* Upload box */
    .upload-area {
      border: 3px dashed var(--primary-color);
      border-radius: 20px;
      background: rgba(22, 163, 74, 0.05);
      transition: all 0.3s ease;
    }

    .upload-area:hover {
      background: rgba(22, 163, 74, 0.1);
      border-color: var(--primary-dark);
    }

    .upload-area.has-image {
      padding: 0;
      border: none;
      background: transparent;
    }

/* Scrollbar styling */
::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 3px;
}

::-webkit-scrollbar-thumb {
  background: var(--primary-color);
  border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
  background: var(--primary-dark);
}

/* Responsive adjustments */
@media (max-width: 768px) {
  .card-custom {
    border-radius: 15px;
  }
  
  .btn-primary-custom,
  .btn-outline-custom {
    border-radius: 10px;
    padding: 10px 20px;
  }
}

/* Animation classes */
.fade-in {
  animation: fadeIn 0.6s ease-in;
    }

    @keyframes fadeIn {
      from { opacity: 0; transform: translateY(20px); }
      to { opacity: 1; transform: translateY(0); }
    }

    /* Focus states */
    .btn:focus,
    .form-range:focus {
      box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.25);
    }

    input[type="file"] {
      display: none;
    }
  </style>
</head>

<body>
  <!-- Header Hero Section -->
  <header class="hero-section text-white position-relative" data-aos="fade-down">
    <div class="container-fluid py-5">
      <div class="row justify-content-center">
        <div class="col-md-8 text-center">
          <div class="mb-4" data-aos="zoom-in" data-aos-delay="200">
            <img src="https://bddiary.com/assets/logo.png" alt="Logo" class="img-fluid" style="height: 80px; filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3));">
          </div>
          <h1 class="display-4 fw-bold mb-3" data-aos="fade-up" data-aos-delay="400" style="text-shadow: 2px 2px 4px rgba(0,0,0,0.3);">
            দাঁড়িপাল্লায় ভোট দিন
          </h1>
          <p class="lead opacity-90 fw-medium" data-aos="fade-up" data-aos-delay="600">
            <i class="bi bi-camera-fill me-2"></i>
            আপনার ছবিতে ফ্রেম যোগ করুন এবং শেয়ার করুন
          </p>
          <div class="mt-4" data-aos="fade-up" data-aos-delay="800">
            <div class="d-flex justify-content-center gap-3">
              <span class="badge bg-light text-dark fs-6 px-3 py-2 rounded-pill">
                <i class="bi bi-check-circle-fill text-success me-1"></i>
                সহজ ব্যবহার
              </span>
              <span class="badge bg-light text-dark fs-6 px-3 py-2 rounded-pill">
                <i class="bi bi-shield-check-fill text-primary me-1"></i>
                নিরাপদ
              </span>
              <span class="badge bg-light text-dark fs-6 px-3 py-2 rounded-pill">
                <i class="bi bi-download text-info me-1"></i>
                ফ্রি ডাউনলোড
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    <!-- Wave divider -->
    <div class="position-absolute bottom-0 start-0 w-100">
      <svg viewBox="0 0 1200 120" preserveAspectRatio="none" style="height: 60px; width: 100%;">
        <path d="M0,0V46.29c47.79,22.2,103.59,32.17,158,28C213.13,69.73,268.14,57.14,320,51.29c52.36-5.92,105.73,2.74,158,2.74s105.64-8.66,158-2.74c51.86,5.85,106.87,18.44,162.15,22.9C952.85,78.46,1008.65,68.49,1056.45,46.29V120H0V0Z" fill="white" fill-opacity="1"></path>
      </svg>
    </div>
  </header>

  <!-- Main Content -->
  <main class="container my-5">
    <div class="row justify-content-center">
      <div class="col-lg-8 col-xl-7">
        
        <!-- Frame Selector Section -->
        <section class="card-custom p-4 mb-4" data-aos="fade-up" data-aos-delay="100">
          <div class="d-flex align-items-center justify-content-between mb-4">
            <div class="d-flex align-items-center">
              <i class="bi bi-images text-primary fs-4 me-3"></i>
              <div>
                <h2 class="h4 mb-1 fw-bold text-dark">ফ্রেম নির্বাচন করুন</h2>
              </div>
            </div>
            <div class="text-end d-none d-md-block">
              <span class="badge bg-success-subtle text-success">
                <i class="bi bi-check-circle me-1"></i>
                লোকাল ফাইল
              </span>
            </div>
          </div>
          
          <div class="position-relative">
            <div class="d-flex gap-3 overflow-auto pb-2" id="framesGrid" style="scrollbar-width: thin; min-height: 120px;">
              <!-- Frames will be loaded here -->
            </div>
            
            <!-- Scroll indicators -->
            <div class="position-absolute top-50 start-0 translate-middle-y">
              <div class="btn btn-sm btn-outline-secondary rounded-circle d-none d-md-block" style="width: 40px; height: 40px;">
                <i class="bi bi-chevron-left"></i>
              </div>
            </div>
            <div class="position-absolute top-50 end-0 translate-middle-y">
              <div class="btn btn-sm btn-outline-secondary rounded-circle d-none d-md-block" style="width: 40px; height: 40px;">
                <i class="bi bi-chevron-right"></i>
              </div>
            </div>
          </div>
          </section>

        <!-- Canvas & Controls Section -->
        <section class="card-custom p-4 mb-4" data-aos="fade-up" data-aos-delay="200">
          
          <!-- Canvas Preview -->
          <div class="mb-4">
            <div class="d-flex align-items-center justify-content-between mb-3">
              <div class="d-flex align-items-center">
                <i class="bi bi-eye text-primary fs-4 me-3"></i>
                <h3 class="h5 mb-0 fw-bold text-dark">প্রিভিউ</h3>
              </div>
              <div class="text-muted small">
                <i class="bi bi-info-circle me-1"></i>
                সাইজ: 1080x1080px
              </div>
            </div>
            
            <div class="position-relative" style="aspect-ratio: 1;">
              <div class="w-100 h-100 position-relative rounded-3 overflow-hidden shadow-sm" id="previewContainer">
                <canvas id="previewCanvas" width="1080" height="1080" class="border-0"></canvas>
                
                <!-- Loading overlay -->
                <div class="position-absolute top-0 start-0 w-100 h-100 bg-dark bg-opacity-75 d-none flex-column justify-content-center align-items-center text-white rounded-3" id="loadingIndicator">
                  <div class="spinner-custom mb-3"></div>
                  <div class="fw-semibold">প্রসেস করা হচ্ছে...</div>
                </div>
              </div>
            </div>
          </div>
          
          <!-- Zoom Control -->
          <div class="mb-4" data-aos="fade-up" data-aos-delay="300">
            <label class="form-label fw-semibold text-dark d-flex align-items-center gap-2 mb-3">
              <i class="bi bi-zoom-in text-primary"></i>
              <span>জুম কন্ট্রোল</span>
              <span class="badge bg-primary ms-auto" id="zoomValue">0%</span>
            </label>
          <div class="row align-items-center">
            <div class="col-2 col-sm-1">
              <small class="text-muted">-100%</small>
            </div>
            <div class="col-8 col-sm-10">
              <input type="range" class="form-range" id="zoomSlider" min="-100" max="200" value="0" aria-label="জুম নিয়ন্ত্রণ">
            </div>
            <div class="col-2 col-sm-1 text-end">
              <small class="text-muted">200%</small>
            </div>
          </div>
          <div class="text-center mt-2">
            <small class="text-muted">
              <i class="bi bi-mouse me-1"></i>
              মাউস হুইল বা টাচ দিয়ে জুম করুন
            </small>
          </div>
        </div>

        <!-- Action Buttons -->
        <div class="d-grid gap-3" data-aos="fade-up" data-aos-delay="400">
          <button type="button" class="btn btn-primary-custom btn-lg d-flex align-items-center justify-content-center gap-2" id="selectImageBtn">
            <i class="bi bi-upload fs-5"></i>
            <span class="fw-bold">ছবি নির্বাচন করুন</span>
          </button>
          
          <button type="button" class="btn btn-outline-custom d-none d-flex align-items-center justify-content-center gap-2" id="changeImageBtn">
            <i class="bi bi-arrow-repeat fs-5"></i>
            <span class="fw-semibold">ছবি পরিবর্তন করুন</span>
          </button>
          
          <div class="row g-2">
            <div class="col-6">
              <button type="button" class="btn btn-primary-custom w-100 d-flex align-items-center justify-content-center gap-2" id="downloadBtn">
                <i class="bi bi-download fs-5"></i>
                <span class="fw-bold d-none d-sm-inline">ডাউনলোড</span>
              </button>
            </div>
            <div class="col-6">
              <button type="button" class="btn btn-outline-custom w-100 d-flex align-items-center justify-content-center gap-2" onclick="shareImage()">
                <i class="bi bi-share fs-5"></i>
                <span class="fw-semibold d-none d-sm-inline">শেয়ার</span>
              </button>
            </div>
          </div>
        </section>

        <!-- Instructions Section -->
        <section class="card-custom p-4 mb-4" data-aos="fade-up" data-aos-delay="500">
          <div class="d-flex align-items-center mb-4">
            <i class="bi bi-question-circle text-info fs-4 me-3"></i>
            <h3 class="h5 mb-0 fw-bold text-dark">কীভাবে ব্যবহার করবেন?</h3>
          </div>
          
          <div class="row g-3">
            <div class="col-md-4">
              <div class="text-center p-3 bg-light rounded-3 h-100">
                <div class="bg-primary rounded-circle d-inline-flex align-items-center justify-content-center text-white fw-bold mb-3" style="width: 50px; height: 50px;">
                  1
                </div>
                <h6 class="fw-bold text-dark">ফ্রেম নির্বাচন</h6>
                <p class="text-muted small mb-0">পছন্দের ফ্রেম বেছে নিন</p>
              </div>
            </div>
            <div class="col-md-4">
              <div class="text-center p-3 bg-light rounded-3 h-100">
                <div class="bg-success rounded-circle d-inline-flex align-items-center justify-content-center text-white fw-bold mb-3" style="width: 50px; height: 50px;">
                  2
                </div>
                <h6 class="fw-bold text-dark">ছবি আপলোড</h6>
              </div>
            </div>
            <div class="col-md-4">
              <div class="text-center p-3 bg-light rounded-3 h-100">
                <div class="bg-info rounded-circle d-inline-flex align-items-center justify-content-center text-white fw-bold mb-3" style="width: 50px; height: 50px;">
                  3
                </div>
                <h6 class="fw-bold text-dark">ডাউনলোড</h6>
                <p class="text-muted small mb-0">ছবি ডাউনলোড ও শেয়ার করুন</p>
              </div>
            </div>
          </div>
        </section>

      </div>
    </div>
  </main>

  <!-- Footer -->
  <footer class="bg-gradient-dark text-light mt-5" style="background: linear-gradient(135deg, #1a1a1a 0%, #2c3e50 50%, #34495e 100%); position: relative; overflow: hidden;">
    <!-- Background Pattern -->
    <div class="position-absolute w-100 h-100" style="opacity: 0.05; background-image: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\"><defs><pattern id=\"grain\" width=\"100\" height=\"100\" patternUnits=\"userSpaceOnUse\"><circle cx=\"50\" cy=\"50\" r=\"1\" fill=\"white\"/><circle cx=\"25\" cy=\"25\" r=\"0.5\" fill=\"white\"/><circle cx=\"75\" cy=\"75\" r=\"0.5\" fill=\"white\"/></pattern></defs><rect width=\"100\" height=\"100\" fill=\"url(%23grain)\"/></svg>'); background-repeat: repeat;"></div>
    
    <!-- Main Footer Content -->
    <div class="container position-relative" style="z-index: 2;">
      <!-- Top Section -->
      <div class="row py-5">
        <div class="col-lg-4 col-md-6 mb-4 mb-lg-0">
          <div class="d-flex align-items-center mb-3">
            <img src="https://bddiary.com/assets/logo.png" alt="দাঁড়িপাল্লা লোগো" style="height: 50px; filter: drop-shadow(0 2px 8px rgba(0,0,0,0.3));">
            <div class="ms-3">
              <h5 class="mb-1 fw-bold text-white">দাঁড়িপাল্লা</h5>
              <p class="mb-0 text-light opacity-75">প্রোফাইল ফ্রেম জেনারেটর</p>
            </div>
          </div>
          <p class="text-light opacity-75 mb-3">
            আপনার ছবিতে সুন্দর ফ্রেম যোগ করুন এবং সবার সাথে শেয়ার করুন। সহজ, দ্রুত এবং সম্পূর্ণ বিনামূল্যে।
          </p>
          <div class="d-flex gap-2">
            <span class="badge bg-success px-3 py-2 rounded-pill">
              <i class="bi bi-shield-check me-1"></i>
              নিরাপদ
            </span>
            <span class="badge bg-primary px-3 py-2 rounded-pill">
              <i class="bi bi-download me-1"></i>
              ফ্রি
            </span>
          </div>
        </div>
        
        <div class="col-lg-2 col-md-6 mb-4 mb-lg-0">
          <h6 class="fw-bold text-white mb-3">ফিচারস</h6>
          <ul class="list-unstyled">
            <li class="mb-2">
              <span class="text-light opacity-75">
                <i class="bi bi-check-circle-fill text-success me-2"></i>
                ফ্রেম নির্বাচন
              </span>
            </li>
            <li class="mb-2">
              <span class="text-light opacity-75">
                <i class="bi bi-check-circle-fill text-success me-2"></i>
                ইমেজ এডিটিং
              </span>
            </li>
            <li class="mb-2">
              <span class="text-light opacity-75">
                <i class="bi bi-check-circle-fill text-success me-2"></i>
                তাৎক্ষণিক ডাউনলোড
              </span>
            </li>
            <li class="mb-2">
              <span class="text-light opacity-75">
                <i class="bi bi-check-circle-fill text-success me-2"></i>
                সোশ্যাল শেয়ারিং
              </span>
            </li>
          </ul>
        </div>
        
        <div class="col-lg-3 col-md-6 mb-4 mb-lg-0">
          <h6 class="fw-bold text-white mb-3">সহায়তা</h6>
          <ul class="list-unstyled">
            <li class="mb-2">
              <a href="#" class="text-light opacity-75 text-decoration-none d-flex align-items-center">
                <i class="bi bi-question-circle me-2"></i>
                কীভাবে ব্যবহার করবেন
              </a>
            </li>
            <li class="mb-2">
              <a href="#" class="text-light opacity-75 text-decoration-none d-flex align-items-center">
                <i class="bi bi-shield-exclamation me-2"></i>
                গোপনীয়তা নীতি
              </a>
            </li>
            <li class="mb-2">
              <a href="#" class="text-light opacity-75 text-decoration-none d-flex align-items-center">
                <i class="bi bi-file-text me-2"></i>
                শর্তাবলী
              </a>
            </li>
            <li class="mb-2">
              <a href="#" class="text-light opacity-75 text-decoration-none d-flex align-items-center">
                <i class="bi bi-envelope me-2"></i>
                যোগাযোগ
              </a>
            </li>
          </ul>
        </div>
        
        <div class="col-lg-3 col-md-6">
          <h6 class="fw-bold text-white mb-3">আমাদের সাথে যুক্ত হন</h6>
          <div class="d-flex gap-2 mb-3">
            <a href="#" class="btn btn-outline-light btn-sm rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;" title="Facebook">
              <i class="bi bi-facebook"></i>
            </a>
            <a href="#" class="btn btn-outline-light btn-sm rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;" title="Twitter">
              <i class="bi bi-twitter"></i>
            </a>
            <a href="#" class="btn btn-outline-light btn-sm rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;" title="YouTube">
              <i class="bi bi-youtube"></i>
            </a>
            <a href="#" class="btn btn-outline-light btn-sm rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;" title="Instagram">
              <i class="bi bi-instagram"></i>
            </a>
          </div>
          <div class="bg-dark bg-opacity-25 rounded-3 p-3 border border-light border-opacity-25">
            <div class="d-flex align-items-center text-light opacity-75 small">
              <i class="bi bi-info-circle me-2 text-info"></i>
              <span>আপনার তথ্য সুরক্ষিত থাকে। আমরা কোনো ডেটা সংরক্ষণ করি না।</span>
            </div>
          </div>
        </div>
      </div>
      
      <!-- Divider -->
      <hr class="border-light border-opacity-25 my-4">
      
      <!-- Bottom Section -->
      <div class="row align-items-center py-3">
        <div class="col-md-6 mb-2 mb-md-0">
          <div class="d-flex align-items-center gap-3">
            <small class="text-light opacity-75">
              © 2024 <strong>BD Diary</strong> | সকল অধিকার সংরক্ষিত
            </small>
          </div>
        </div>
        <div class="col-md-6 text-md-end">
          <div class="d-flex align-items-center justify-content-md-end gap-2">
            <small class="text-light opacity-75">Developed By:</small>
            <a href="http://w3softbd.com" class="text-decoration-none">
              <span class="badge bg-gradient text-dark fw-bold px-3 py-2 rounded-pill shadow-sm" style="background: linear-gradient(45deg, #ffd700, #ffed4e); transition: all 0.3s ease; cursor: pointer;" onmouseover="this.style.transform='scale(1.05)'; this.style.boxShadow='0 4px 15px rgba(255,215,0,0.4)'" onmouseout="this.style.transform='scale(1)'; this.style.boxShadow='0 2px 8px rgba(0,0,0,0.1)'">
                <i class="bi bi-code-slash me-1"></i>
                W3 SOFT
              </span>
            </a>
          </div>
        </div>
      </div>
    </div>
    
    <!-- Decorative Wave -->
    <div class="position-absolute top-0 start-0 w-100" style="height: 60px; overflow: hidden; transform: rotate(180deg);">
      <svg viewBox="0 0 1200 120" preserveAspectRatio="none" style="height: 100%; width: 100%;">
        <path d="M0,0V46.29c47.79,22.2,103.59,32.17,158,28C213.13,69.73,268.14,57.14,320,51.29c52.36-5.92,105.73,2.74,158,2.74s105.64-8.66,158-2.74c51.86,5.85,106.87,18.44,162.15,22.9C952.85,78.46,1008.65,68.49,1056.45,46.29V120H0V0Z" fill="white" fill-opacity="0.1"></path>
      </svg>
    </div>
  </footer>

  <!-- Hidden file input -->
  <input type="file" id="fileInput" accept="image/*" style="display: none;">

  <!-- Toast notification -->
  <div id="toast" class="toast-custom">
    <span id="toastMessage">বার্তা</span>
  </div>

  <!-- Bootstrap 5+ JS Bundle -->
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>

  <!-- AOS Animation Library -->
  <script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script>

  <!-- Custom JavaScript -->
  <script src="assets/js/app.js"></script>

  <!-- Initialize AOS -->
  <script>
    // Initialize AOS animations
    AOS.init({
    duration: 800,
    easing: 'ease-out-cubic',
    once: true,
    offset: 100
  });

  // Enhanced smooth scrolling for internal links
  document.querySelectorAll('a[href^="#"]').forEach(anchor => {
    anchor.addEventListener('click', function (e) {
      e.preventDefault();
      const target = document.querySelector(this.getAttribute('href'));
      if (target) {
        target.scrollIntoView({
          behavior: 'smooth',
          block: 'start'
        });
      }
    });
  });

  // Add loading class to buttons when clicked
  document.querySelectorAll('.btn').forEach(btn => {
    btn.addEventListener('click', function() {
      if (!this.classList.contains('btn-loading')) {
        this.classList.add('btn-loading');
        setTimeout(() => {
          this.classList.remove('btn-loading');
        }, 2000);
      }
    });
  });

  // Enhanced frame grid scrolling
  // framesGrid is already declared in DOM ELEMENTS section
  if (framesGrid) {
    // Add scroll indicators
    const scrollIndicatorLeft = document.querySelector('.position-absolute.start-0');
    const scrollIndicatorRight = document.querySelector('.position-absolute.end-0');
    
    if (scrollIndicatorLeft && scrollIndicatorRight) {
      // Hide/show scroll indicators based on scroll position
      framesGrid.addEventListener('scroll', function() {
        scrollIndicatorLeft.style.opacity = this.scrollLeft > 0 ? '1' : '0.3';
        scrollIndicatorRight.style.opacity = 
          this.scrollLeft < (this.scrollWidth - this.clientWidth) ? '1' : '0.3';
      });
      
      // Add click handlers for scroll indicators
      scrollIndicatorLeft.addEventListener('click', () => {
        framesGrid.scrollBy({ left: -200, behavior: 'smooth' });
      });
      
      scrollIndicatorRight.addEventListener('click', () => {
        framesGrid.scrollBy({ left: 200, behavior: 'smooth' });
      });
    }
  }

  // Add ripple effect to buttons
  function createRipple(event) {
    const button = event.currentTarget;
    const circle = document.createElement('span');
    const diameter = Math.max(button.clientWidth, button.clientHeight);
    const radius = diameter / 2;
    const rect = button.getBoundingClientRect();
    
    circle.style.width = circle.style.height = `${diameter}px`;
    circle.style.left = `${event.clientX - rect.left - radius}px`;
    circle.style.top = `${event.clientY - rect.top - radius}px`;
    circle.classList.add('ripple');
    
    const ripple = button.getElementsByClassName('ripple')[0];
    if (ripple) {
      ripple.remove();
    }
    
    button.appendChild(circle);
  }

  // Apply ripple effect to all buttons
  document.querySelectorAll('.btn').forEach(btn => {
    btn.addEventListener('click', createRipple);
  });

  // Add CSS for ripple effect
  const rippleStyle = document.createElement('style');
  rippleStyle.textContent = `
    .btn {
      position: relative;
      overflow: hidden;
    }
    
    .ripple {
      position: absolute;
      border-radius: 50%;
      background: rgba(255, 255, 255, 0.4);
      transform: scale(0);
      animation: ripple-animation 0.6s linear;
      pointer-events: none;
    }
    
    @keyframes ripple-animation {
      to {
        transform: scale(4);
        opacity: 0;
      }
    }
    
    .btn-loading {
      pointer-events: none;
      opacity: 0.8;
    }
    
    .btn-loading::after {
      content: '';
      display: inline-block;
      width: 16px;
      height: 16px;
      border: 2px solid transparent;
      border-top-color: currentColor;
      border-radius: 50%;
      animation: spin 0.8s linear infinite;
      margin-left: 8px;
    }
  `;
  document.head.appendChild(rippleStyle);
</script>
</div>
</div>
<input type="file" id="fileInput" accept="image/*" aria-label="ছবি নির্বাচন করুন" style="display: none;">
</div>
</div>
<!-- Toast Container -->
<div id="toast" class="toast"></div>

<!-- Fabric.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.0/fabric.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<!-- Main Application Script -->
<script>
// ============================================
// DEBUG FUNCTION FOR FRAME TESTING
// ============================================
window.testFrame = function(frameUrl) {
  const img = new Image();
  img.onload = () => {
    showToast(`ফ্রেম সফলভাবে লোড হয়েছে: ${frameUrl}`, 'success');
  };
  img.onerror = (error) => {
    showToast(`ফ্রেম লোড হয়নি: ${frameUrl}`, 'error');
  };
  img.src = frameUrl;
};

window.testAllFrames = function() {
  CONFIG.frames.forEach((frame, index) => {
    setTimeout(() => {
      testFrame(frame.url);
    }, index * 1000);
  });
};

// Update debug info
window.updateDebugInfo = function() {
  const debugFrameCount = document.getElementById('debugFrameCount');
  const debugCanvasReady = document.getElementById('debugCanvasReady');
  const debugCurrentFrame = document.getElementById('debugCurrentFrame');
  
  if (debugFrameCount) debugFrameCount.textContent = CONFIG.frames ? CONFIG.frames.length : '0';
  if (debugCanvasReady) debugCanvasReady.textContent = fabricCanvas ? 'Yes' : 'No';
  if (debugCurrentFrame) debugCurrentFrame.textContent = currentFrame || 'None';

};

// Auto-update debug info
setInterval(updateDebugInfo, 2000);

// Update frame loading status
function updateFrameStatus(loaded, total) {
  const statusContainer = document.querySelector('.text-end.d-none.d-md-block');
  if (statusContainer) {
    const badge = document.createElement('span');
    badge.className = `badge ${loaded === total ? 'bg-success' : 'bg-warning'}`;
    badge.innerHTML = `<i class="bi bi-check-circle me-1"></i>${loaded}/${total} ফ্রেম`;
    statusContainer.innerHTML = '';
    statusContainer.appendChild(badge);
  }
}

const CONFIG = {
eventName: "দাঁড়িপাল্লায় ভোট দিন",
defaultFormat: "png",
frames: [
{ name: "ফ্রেম ১", url: "assets/img/1.png" },
{ name: "ফ্রেম ২", url: "assets/img/2.png" },
{ name: "ফ্রেম ৩", url: "assets/img/3.png" },
{ name: "ফ্রেম ৪", url: "assets/img/4.png" },
{ name: "ফ্রেম ৫", url: "assets/img/5.png" }
],
exportSize: 1080,
showWatermarkToggle: false,
watermarkText: "#দাঁড়িপাল্লায়ভোটদিন",
maxFileSize: 10 * 1024 * 1024,
maxImageDimension: 4096,

// Auto-detect frames from img folder (for future enhancement)
async detectFrames() {
try {
// This would need server-side support to list directory contents
// For now, using the predefined frames array above
const detectedFrames = [];
const frameFiles = ['1.png', '2.png', '3.png', '4.png', '5.png'];

frameFiles.forEach((file, index) => {
detectedFrames.push({
name: `ফ্রেম ${index + 1}`,
url: `assets/img/${file}`
});
});
return detectedFrames;
} catch (error) {
return this.frames;
}
},
};

// ============================================
// STATE
// ============================================
let fabricCanvas = null;
let userImageObj = null;
let frameImageObj = null;
let currentImageSrc = null;
let currentFrame = null;
let frameImages = {};
let noWatermark = true;
// Touch state
let lastTouchDistance = 0;
let isPinching = false;

// ============================================
// DOM ELEMENTS
// ============================================
const fileInput = document.getElementById('fileInput');
const framesGrid = document.getElementById('framesGrid');
const previewCanvas = document.getElementById('previewCanvas');
const previewContainer = document.getElementById('previewContainer');
const loadingIndicator = document.getElementById('loadingIndicator');
const toast = document.getElementById('toast');

const zoomSlider = document.getElementById('zoomSlider');
const zoomValue = document.getElementById('zoomValue');
const selectImageBtn = document.getElementById('selectImageBtn');
const changeImageBtn = document.getElementById('changeImageBtn');
const downloadBtn = document.getElementById('downloadBtn');

// ============================================
// INITIALIZATION
// ============================================
function init() {
// Initialize Fabric.js canvas with responsive sizing
const container = previewContainer;
const containerWidth = container.offsetWidth;
fabricCanvas = new fabric.Canvas('previewCanvas', {
width: CONFIG.exportSize,
height: CONFIG.exportSize,
backgroundColor: 'transparent',
selection: false,
preserveObjectStacking: true,
renderOnAddRemove: true,
stateful: false
});
// Make canvas responsive - fit within container
function resizeCanvas() {
if (!fabricCanvas || !previewContainer) return;
const containerWidth = previewContainer.offsetWidth;
const containerHeight = previewContainer.offsetHeight;
// Calculate scale to fit container (maintain aspect ratio)
const scale = Math.min(containerWidth, containerHeight) / CONFIG.exportSize;
// Set canvas display size (CSS only - keeps internal size at exportSize)
const canvasElement = fabricCanvas.getElement();
if (canvasElement) {
canvasElement.style.width = (CONFIG.exportSize * scale) + 'px';
canvasElement.style.height = (CONFIG.exportSize * scale) + 'px';
canvasElement.style.maxWidth = '100%';
canvasElement.style.maxHeight = '100%';
}
// Also update upper canvas if exists
const upperCanvas = fabricCanvas.upperCanvasEl;
if (upperCanvas) {
upperCanvas.style.width = (CONFIG.exportSize * scale) + 'px';
upperCanvas.style.height = (CONFIG.exportSize * scale) + 'px';
upperCanvas.style.maxWidth = '100%';
upperCanvas.style.maxHeight = '100%';
}
fabricCanvas.renderAll();
}
// Initial resize - wait for container to be ready
setTimeout(() => {
resizeCanvas();
}, 100);
// Resize on window resize
let resizeTimeout;
window.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(resizeCanvas, 100);
});

// Default object settings - will be customized per object
// Don't disable controls globally - let each object set its own
fabric.Object.prototype.lockRotation = true;

loadFrames().then(() => {
// Load default first frame after all frames are loaded
if (currentFrame && frameImages[currentFrame]) {
updateFrame();
} else {
// Set default frame if no frame is selected
setTimeout(() => {
if (CONFIG.frames && CONFIG.frames.length > 0) {
currentFrame = CONFIG.frames[0].url;
frameImages[currentFrame] = currentFrame;
updateFrame();
}
}, 500);
}
});

selectImageBtn.addEventListener('click', () => fileInput.click());
changeImageBtn.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', handleFileSelect);
zoomSlider.addEventListener('input', handleZoom);
downloadBtn.addEventListener('click', downloadImage);

// Mouse wheel zoom (desktop)
previewCanvas.addEventListener('wheel', handleWheel, { passive: false });

// Touch events for pinch zoom (mobile)
previewCanvas.addEventListener('touchstart', handleTouchStart, { passive: false });
previewCanvas.addEventListener('touchmove', handleTouchMove, { passive: false });
previewCanvas.addEventListener('touchend', handleTouchEnd);

trackVisit();
}

// ============================================
// ANALYTICS TRACKING
// ============================================
function trackVisit() {
const analytics = getAnalytics();
analytics.visits.push({
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
referrer: document.referrer || 'direct'
});
saveAnalytics(analytics);
}

function trackFrameGeneration(frameUrl) {
const analytics = getAnalytics();
analytics.generations.push({
timestamp: new Date().toISOString(),
frame: frameUrl,
action: 'download'
});
saveAnalytics(analytics);
}

function trackFrameShare(frameUrl) {
const analytics = getAnalytics();
analytics.generations.push({
timestamp: new Date().toISOString(),
frame: frameUrl,
action: 'share'
});
saveAnalytics(analytics);
}

function getAnalytics() {
const data = localStorage.getItem('frameAnalytics');
if (data) {
return JSON.parse(data);
}
return {
visits: [],
generations: [],
startDate: new Date().toISOString()
};
}

function saveAnalytics(analytics) {
localStorage.setItem('frameAnalytics', JSON.stringify(analytics));
}

// ============================================
// FRAME MANAGEMENT
// ============================================
// Note: The working loadFrames function is defined at the bottom of the page

function selectFrame(element, frameUrl) {
  document.querySelectorAll('.frame-option').forEach(el => el.classList.remove('selected'));
  element.classList.add('selected');
  currentFrame = frameUrl;
  updateFrame();
}

function updateFrame() {
if (!frameImages[currentFrame] || !fabricCanvas) {
return;
}
// Remove old frame if exists - ensure complete removal
if (frameImageObj) {
try {
// Remove from canvas
const objects = fabricCanvas.getObjects();
const frameIndex = objects.indexOf(frameImageObj);
if (frameIndex > -1) {
fabricCanvas.remove(frameImageObj);
}
// Dispose the object
frameImageObj.dispose();
} catch (e) {
}
frameImageObj = null;
fabricCanvas.renderAll(); // Render after removal
}
  // Add frame on top - exactly 100% width and height
  try {
    // For local files, use the direct URL instead of data URL
    const frameUrl = frameImages[currentFrame] || currentFrame;
    
    fabric.Image.fromURL(frameUrl, (img) => {
      if (!img) {
        showToast('ফ্রেম লোড করতে সমস্যা হয়েছে। অন্য ফ্রেম নির্বাচন করুন।', 'error');
        return;
      }
      
      // Scale frame to exactly match canvas size (100% width and height)
      const scaleX = CONFIG.exportSize / img.width;
      const scaleY = CONFIG.exportSize / img.height;
      // Use max to ensure frame covers entire canvas (100% coverage)
      const scale = Math.max(scaleX, scaleY);
      
      img.set({
        left: CONFIG.exportSize / 2,
        top: CONFIG.exportSize / 2,
        originX: 'center',
        originY: 'center',
        scaleX: scale,
        scaleY: scale,
        selectable: false,
        evented: false, // Frame should not block user image interactions
        excludeFromExport: false,
        lockMovementX: true,
        lockMovementY: true,
        lockScalingX: true,
        lockScalingY: true,
        hoverCursor: 'default',
        moveCursor: 'default',
        // Ensure frame doesn't interfere with controls
        perPixelTargetFind: false,
        objectCaching: false
});
frameImageObj = img;
fabricCanvas.add(img);
// Ensure frame is on top and user image is below
if (userImageObj) {
fabricCanvas.sendToBack(userImageObj);
} else {
// If no user image, bring frame to front
fabricCanvas.bringToFront(img);
}
fabricCanvas.renderAll();
}, {
crossOrigin: 'anonymous'
});
} catch (error) {
showToast('ফ্রেম লোড করতে সমস্যা হয়েছে।', 'error');
}
}

// ============================================
// FILE HANDLING
// ============================================
function handleFileSelect(e) {
const file = e.target.files[0];
if (!file) return;

// Validate file
if (!file.type.match('image.*')) {
showToast('দয়া করে একটি ছবি ফাইল নির্বাচন করুন।', 'error');
return;
}

if (file.size > CONFIG.maxFileSize) {
showToast('ফাইল খুব বড়। সর্বোচ্চ ১০ MB অনুমোদিত।', 'error');
return;
}

// Read and load image
const reader = new FileReader();
reader.onload = (event) => {
loadImage(event.target.result);
};
reader.readAsDataURL(file);
}

function loadImage(imageSrc) {
currentImageSrc = imageSrc;
fabric.Image.fromURL(imageSrc, (img) => {
// Check if image needs downscaling
const maxDim = Math.max(img.width, img.height);
if (maxDim > CONFIG.maxImageDimension) {
const scale = CONFIG.maxImageDimension / maxDim;
img.scale(scale);
}

// Center the image at canvas center
const canvasSize = CONFIG.exportSize;
const centerX = canvasSize / 2;
const centerY = canvasSize / 2;
// Using default Fabric.js resize controls - no custom handlers needed

img.set({
left: centerX,
top: centerY,
originX: 'center',
originY: 'center',
selectable: true,
evented: true,
// Enable default Fabric.js resize controls (4 corners)
hasControls: true,
hasBorders: true,
borderColor: '#16a34a',
borderOpacityWhenMoving: 1,
borderDashArray: [5, 5],
cornerColor: '#16a34a',
cornerSize: 18,
cornerStyle: 'circle',
transparentCorners: false,
borderScaleFactor: 2,
cornerStrokeColor: '#ffffff',
cornerStrokeWidth: 3,
// Allow movement and scaling
lockMovementX: false,
lockMovementY: false,
lockRotation: true,
lockScalingX: false,
lockScalingY: false,
lockUniScaling: true, // Maintain aspect ratio when resizing from corners (default 4 corner controls)
// Make controls more visible
padding: 8
// Using default Fabric.js corner controls (4 corners) - no custom edge controls
// lockUniScaling ensures aspect ratio is maintained when resizing
});

// Remove old image if exists
if (userImageObj) {
fabricCanvas.remove(userImageObj);
}

userImageObj = img;
fabricCanvas.add(img);
// Ensure user image is below frame
if (frameImageObj) {
fabricCanvas.sendToBack(img);
// Make sure frame doesn't block clicks - bring frame to front but keep it non-interactive
fabricCanvas.bringToFront(frameImageObj);
}
// Set as active object to show controls immediately
fabricCanvas.setActiveObject(img);
// Force show controls - multiple attempts to ensure visibility
setTimeout(() => {
if (fabricCanvas && userImageObj === img) {
fabricCanvas.setActiveObject(img);
fabricCanvas.renderAll();
}
}, 100);
setTimeout(() => {
if (fabricCanvas && userImageObj === img) {
fabricCanvas.setActiveObject(img);
fabricCanvas.renderAll();
}
}, 300);
// Add event listeners for resize and movement
img.on('modified', () => {
fabricCanvas.renderAll();
});
img.on('scaling', () => {
fabricCanvas.renderAll();
});
img.on('moving', () => {
fabricCanvas.renderAll();
});
img.on('selected', () => {
fabricCanvas.renderAll();
});
// Ensure image can be selected even when frame is on top
img.on('mousedown', (e) => {
fabricCanvas.setActiveObject(img);
fabricCanvas.renderAll();
if (e.e) e.e.stopPropagation();
});
// Click on canvas to select image
fabricCanvas.on('mouse:down', (e) => {
if (e.target === img || (!e.target && userImageObj === img)) {
fabricCanvas.setActiveObject(img);
fabricCanvas.renderAll();
}
});
fabricCanvas.renderAll();

// Reset zoom slider to 0% (1x scale)
zoomSlider.value = 0;
zoomValue.textContent = '0%';

// Show change image button
selectImageBtn.classList.add('d-none');
changeImageBtn.classList.remove('d-none');
previewContainer.classList.add('has-image');

// Update frame (ensure frame is on top)
if (frameImageObj) {
fabricCanvas.bringToFront(frameImageObj);
}
fabricCanvas.renderAll();
}, {
crossOrigin: 'anonymous'
});
}

// ============================================
// CANVAS INTERACTION (Mouse Wheel Zoom)
// ============================================
function handleWheel(e) {
if (!userImageObj) return;
e.preventDefault();
const delta = e.deltaY > 0 ? -0.05 : 0.05;
const currentScale = userImageObj.scaleX;
const newScale = Math.max(0, Math.min(3, currentScale + delta));
// Zoom centered on canvas
const canvasCenter = {
x: CONFIG.exportSize / 2,
y: CONFIG.exportSize / 2
};
const scaleRatio = newScale / currentScale;
const imgCenterX = userImageObj.left;
const imgCenterY = userImageObj.top;
userImageObj.scale(newScale);
userImageObj.set({
left: canvasCenter.x - (canvasCenter.x - imgCenterX) * scaleRatio,
top: canvasCenter.y - (canvasCenter.y - imgCenterY) * scaleRatio
});
// Update slider: scale 0-3 maps to -100% to 200%
const zoomPercent = Math.round((newScale * 100) - 100);
zoomSlider.value = Math.max(-100, Math.min(200, zoomPercent));
zoomValue.textContent = zoomSlider.value + '%';
fabricCanvas.renderAll();
}

// ============================================
// CANVAS INTERACTION (Touch - Pinch Zoom)
// ============================================
function handleTouchStart(e) {
if (!userImageObj) return;
if (e.touches.length === 2) {
e.preventDefault();
isPinching = true;
const touch1 = e.touches[0];
const touch2 = e.touches[1];
lastTouchDistance = Math.hypot(
touch2.clientX - touch1.clientX,
touch2.clientY - touch1.clientY
);
}
}

function handleTouchMove(e) {
if (!userImageObj || !isPinching) return;
if (e.touches.length === 2) {
e.preventDefault();
const touch1 = e.touches[0];
const touch2 = e.touches[1];
const distance = Math.hypot(
touch2.clientX - touch1.clientX,
touch2.clientY - touch1.clientY
);
if (lastTouchDistance > 0) {
const scaleChange = distance / lastTouchDistance;
const currentScale = userImageObj.scaleX;
const newScale = Math.max(0, Math.min(3, currentScale * scaleChange));
// Zoom centered on canvas (not on touch point for consistency)
const canvasCenter = {
x: CONFIG.exportSize / 2,
y: CONFIG.exportSize / 2
};
const scaleRatio = newScale / currentScale;
const imgCenterX = userImageObj.left;
const imgCenterY = userImageObj.top;
userImageObj.scale(newScale);
userImageObj.set({
left: canvasCenter.x - (canvasCenter.x - imgCenterX) * scaleRatio,
top: canvasCenter.y - (canvasCenter.y - imgCenterY) * scaleRatio
});
// Update slider: scale 0-3 maps to -100% to 200%
const zoomPercent = Math.round((newScale * 100) - 100);
zoomSlider.value = Math.max(-100, Math.min(200, zoomPercent));
zoomValue.textContent = zoomSlider.value + '%';
fabricCanvas.renderAll();
}
lastTouchDistance = distance;
}
}

function handleTouchEnd(e) {
isPinching = false;
lastTouchDistance = 0;
}

// ============================================
// ZOOM SLIDER
// ============================================
function handleZoom(e) {
if (!userImageObj) return;
const sliderValue = parseInt(e.target.value);
zoomValue.textContent = sliderValue + '%';
// Calculate scale: -100% = 0x, 0% = 1x, 100% = 2x, 200% = 3x
const newScale = (sliderValue + 100) / 100; // Range: 0 to 3
const currentScale = userImageObj.scaleX;
// Zoom centered on canvas
const canvasCenter = {
x: CONFIG.exportSize / 2,
y: CONFIG.exportSize / 2
};
// Calculate scale ratio
const scaleRatio = newScale / currentScale;
// Get current image center
const imgCenterX = userImageObj.left;
const imgCenterY = userImageObj.top;
// Apply new scale
userImageObj.scale(newScale);
// Keep image centered on canvas while zooming
userImageObj.set({
left: canvasCenter.x - (canvasCenter.x - imgCenterX) * scaleRatio,
top: canvasCenter.y - (canvasCenter.y - imgCenterY) * scaleRatio
});
fabricCanvas.renderAll();
}

// Fabric.js handles rendering automatically - no need for manual preview functions

function drawWatermark(ctx, size) {
ctx.save();
ctx.font = `${size * 0.025}px 'Hind Siliguri', sans-serif`;
ctx.fillStyle = 'rgba(255, 255, 255, 0.6)';
ctx.textAlign = 'right';
ctx.textBaseline = 'bottom';
ctx.fillText(CONFIG.watermarkText, size - 20, size - 20);
ctx.restore();
}

// ============================================
// EXPORT
// ============================================
async function downloadImage() {
if (!userImageObj) {
showToast('দয়া করে আগে একটি ছবি নির্বাচন করুন।', 'error');
return;
}

showLoading(true);

try {
await new Promise(resolve => setTimeout(resolve, 100));
// Export canvas to data URL using Fabric.js
const dataURL = fabricCanvas.toDataURL({
format: 'png',
quality: 1.0,
multiplier: 1,
enableRetinaScaling: true
});
const filename = `daripalla_frame_${Date.now()}.png`;
// Create download link
const a = document.createElement('a');
a.href = dataURL;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);

// Track download
trackFrameGeneration(currentFrame);

showToast('ডাউনলোড সম্পন্ন হয়েছে!', 'success');
} catch (error) {
showToast('ডাউনলোড করতে সমস্যা হয়েছে। আবার চেষ্টা করুন।', 'error');
} finally {
showLoading(false);
}
}

async function shareImage() {
  if (!userImageObj) {
    showToast('দয়া করে আগে একটি ছবি আপলোড করুন।', 'error');
    return;
  }

  showLoading(true);

  try {
    // Export canvas to data URL using Fabric.js
    const dataURL = fabricCanvas.toDataURL({
      format: 'png',
      quality: 1.0,
      multiplier: 1,
      enableRetinaScaling: true
    });

    const filename = `daripalla_frame_${Date.now()}.png`;

    // Convert data URL to blob for better handling
    const response = await fetch(dataURL);
    const blob = await response.blob();
    const file = new File([blob], filename, { type: 'image/png' });

    // Try multiple sharing methods
    let shareSuccess = false;

    // Method 1: Native Web Share API (if available)
    if (navigator.share && navigator.canShare && navigator.canShare({ files: [file] })) {
      try {
        await navigator.share({
          files: [file],
          title: 'দাঁড়িপাল্লায় ভোট দিন',
          text: 'আমার নতুন প্রোফাইল ফ্রেম দেখুন! 🗳️ #দাঁড়িপাল্লায়ভোটদিন',
          url: 'http://bddiary.com/'
        });
        shareSuccess = true;
        showToast('শেয়ার সম্পন্ন হয়েছে!', 'success');
      } catch (shareError) {
        if (shareError.name !== 'AbortError') {
          console.log('Native share failed, trying Facebook');
        } else {
          shareSuccess = true; // User cancelled
        }
      }
    }

    // Method 2: Facebook Share Dialog (if native share failed)
    if (!shareSuccess) {
      // First download the image
      const tempLink = document.createElement('a');
      tempLink.href = dataURL;
      tempLink.download = filename;
      tempLink.style.display = 'none';
      document.body.appendChild(tempLink);
      tempLink.click();
      
      // Then open Facebook share dialog
      const shareText = encodeURIComponent('আমার নতুন প্রোফাইল ফ্রেম দেখুন! দাঁড়িপাল্লায় ভোট দিন 🗳️\n\nআপনিও তৈরি করুন: http://bddiary.com/');
      const facebookShareUrl = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent('http://bddiary.com/')}&quote=${shareText}`;
      
      // Open Facebook share in popup
      const popup = window.open(
        facebookShareUrl,
        'facebook-share',
        'width=600,height=500,resizable=yes,scrollbars=yes,toolbar=no,location=yes,directories=no,status=yes,menubar=no'
      );

      if (popup && !popup.closed) {
        shareSuccess = true;
        showToast('Facebook এ শেয়ার করার জন্য ছবি ডাউনলোড হয়েছে। পোস্টে ছবিটি যোগ করুন।', 'success');
        
        // Focus the popup and monitor when it closes
        popup.focus();
        const checkClosed = setInterval(() => {
          if (popup.closed) {
            clearInterval(checkClosed);
            // Track share when popup closes
            trackFrameShare(currentFrame);
          }
        }, 1000);
      } else {
        showToast('Facebook শেয়ার ব্লক করা হয়েছে। ছবি ডাউনলোড হয়েছে - ম্যানুয়ালি শেয়ার করুন।', 'success');
      }
      
      // Clean up download link
      setTimeout(() => {
        if (document.body.contains(tempLink)) {
          document.body.removeChild(tempLink);
        }
      }, 2000);
    }

    // Track the share attempt
    if (shareSuccess) {
      trackFrameShare(currentFrame);
    }

  } catch (error) {
    console.error('Share error:', error);
    showToast('শেয়ার করতে সমস্যা হয়েছে। আবার চেষ্টা করুন।', 'error');
  } finally {
    showLoading(false);
  }
}

// ============================================
// UI HELPERS
// ============================================
function showLoading(show) {
  const loadingIndicator = document.getElementById('loadingIndicator');
  if (show) {
    loadingIndicator.classList.remove('d-none');
    loadingIndicator.classList.add('d-flex');
  } else {
    loadingIndicator.classList.add('d-none');
    loadingIndicator.classList.remove('d-flex');
  }
}

function showToast(message, type = 'info') {
  const toast = document.getElementById('toast');
  const toastMessage = document.getElementById('toastMessage');
  
  toastMessage.textContent = message;
  toast.className = 'toast-custom show';
  
  if (type === 'error') toast.classList.add('error');
  if (type === 'success') toast.classList.add('success');

  setTimeout(() => {
    toast.classList.remove('show');
    toast.classList.remove('error', 'success');
  }, 3000);
}

// ============================================
// START APPLICATION
// ============================================
function startApp() {
if (typeof fabric === 'undefined') {
// Wait for Fabric.js to load (max 10 seconds)
const startTime = Date.now();
const checkFabric = setInterval(() => {
if (typeof fabric !== 'undefined') {
clearInterval(checkFabric);
init();
} else if (Date.now() - startTime > 10000) {
clearInterval(checkFabric);
showToast('Fabric.js লোড করতে সমস্যা হয়েছে। পেজ রিফ্রেশ করুন।', 'error');
}
}, 100);
return;
}
init();
}

window.addEventListener('DOMContentLoaded', startApp);
</script>
<script>
// Simplified frame loading function to fix frame display issues
async function loadFramesFixed() {
  if (!framesGrid) {
    return;
  }
  
  const framesToLoad = CONFIG.frames;
  if (!framesToLoad?.length) {
    framesGrid.innerHTML = `
      <div class="alert alert-warning w-100 m-0">
        <i class="bi bi-exclamation-triangle me-2"></i>
        কোনো ফ্রেম কনফিগার করা হয়নি।
      </div>
    `;
    return;
  }
  
  // Clear existing content
  framesGrid.innerHTML = '';
  let loadedCount = 0;
  
  framesToLoad.forEach((frame, index) => {
    // Create frame container
    const frameDiv = document.createElement('div');
    frameDiv.className = 'frame-option';
    frameDiv.dataset.frame = frame.url;
    
    // Add loading placeholder
    frameDiv.innerHTML = `
      <div class="d-flex flex-column align-items-center justify-content-center h-100 text-muted text-center p-2">
        <div class="spinner-border spinner-border-sm mb-2" role="status"></div>
        <small class="fw-semibold">ফ্রেম ${index + 1}</small>
      </div>
    `;
    
    // Select first frame by default
    if (index === 0) {
      frameDiv.classList.add('selected');
      currentFrame = frame.url;
    }
    
    framesGrid.appendChild(frameDiv);
    
    // Load image
    const img = new Image();
    img.onload = () => {
      // Replace with actual image
      frameDiv.innerHTML = '';
      const imgElement = document.createElement('img');
      imgElement.src = frame.url;
      imgElement.alt = frame.name;
      imgElement.style.cssText = 'width: 100%; height: 100%; object-fit: cover;';
      frameDiv.appendChild(imgElement);
      frameDiv.title = frame.name;
      
      // Store for canvas usage
      frameImages[frame.url] = frame.url;
      loadedCount++;
      
      // Update status
      if (typeof updateFrameStatus === 'function') {
        updateFrameStatus(loadedCount, framesToLoad.length);
      }
      
      // Auto-load first frame in canvas preview
      if (index === 0) {
        setTimeout(() => {
          if (typeof updateFrame === 'function') {
            updateFrame();
          }
        }, 300);
      }
    };
    
    img.onerror = (error) => {
      frameDiv.innerHTML = `
        <div class="d-flex flex-column align-items-center justify-content-center h-100 text-danger text-center p-2">
          <i class="bi bi-exclamation-triangle fs-4 mb-1"></i>
          <small class="fw-semibold">ফ্রেম ${index + 1}</small>
          <small style="font-size: 10px;">লোড হয়নি</small>
        </div>
      `;
      // Try to make it still work
      frameImages[frame.url] = frame.url;
    };
    
    img.src = frame.url;
    
    // Add click handler
    frameDiv.addEventListener('click', () => {
      document.querySelectorAll('.frame-option').forEach(el => el.classList.remove('selected'));
      frameDiv.classList.add('selected');
      currentFrame = frame.url;
      if (typeof updateFrame === 'function') {
        updateFrame();
      }
    });
  });
}

// Override the problematic loadFrames function
window.loadFrames = loadFramesFixed;

// Also make sure it loads when DOM is ready
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', () => {
    setTimeout(loadFramesFixed, 1000);
  });
} else {
  setTimeout(loadFramesFixed, 1000);
}
</script>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/vcd15cbe7772f49c399c6a5babf22c1241717689176015" integrity="sha512-ZpsOmlRQV6y907TI0dKBHq9Md29nnaEIPlkf84rnaERnq6zvWvPUqr2ft8M1aS28oN72PdrCzSjY4U6VaAw1EQ==" data-cf-beacon='{"version":"2024.11.0","token":"0fcae263d6cc4af69b088db69c0d359c","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>