VibeCoderzVibeCoderz
Telegram
All Prompts
Travel Search Bar with Destinations, Dates & Passengers preview
search bartravelbookingdatepickerdropdownselectorvanillajsresponsiveinteractivecss

Travel Search Bar with Destinations, Dates & Passengers

Интерактивная строка поиска для бронирования путешествий. Выбор направлений, дат, пассажиров. Адаптивный дизайн.

Prompt

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Travel Search Bar</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
      background: #f9fafb;
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 1rem;
    }

    .container {
      width: 100%;
      max-width: 80rem;
      position: relative;
    }

    .search-bar {
      background: rgba(243, 244, 246, 0.3);
      border-radius: 9999px;
      padding: 0.5rem;
      box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
      display: flex;
      align-items: center;
      gap: 0.5rem;
    }

    .search-field {
      flex: 1;
      padding: 1rem 1.5rem;
      border-radius: 9999px;
      border: none;
      background: transparent;
      cursor: pointer;
      text-align: left;
      transition: all 0.2s;
    }

    .search-field:hover {
      background: rgba(255, 255, 255, 0.5);
    }

    .search-field.active {
      background: white;
      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
    }

    .field-label {
      font-size: 0.75rem;
      font-weight: 600;
      color: #111827;
      margin-bottom: 0.25rem;
    }

    .field-value {
      font-size: 0.875rem;
      color: #6b7280;
    }

    .search-button {
      height: 3.5rem;
      width: 3.5rem;
      border-radius: 9999px;
      background: #0E7490;
      border: none;
      color: white;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      flex-shrink: 0;
      transition: background 0.2s;
    }

    .search-button:hover {
      background: #0c6481;
    }

    .overlay {
      position: absolute;
      top: calc(100% + 1.5rem);
      background: white;
      border-radius: 32px;
      box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
      padding: 1.5rem;
      z-index: 50;
      opacity: 0;
      transform: translateY(-10px);
      transition: opacity 0.2s, transform 0.2s;
      pointer-events: none;
    }

    .overlay.active {
      opacity: 1;
      transform: translateY(0);
      pointer-events: auto;
    }

    .overlay.destinations {
      left: 0;
      right: 0;
      max-width: 28rem;
    }

    .overlay.calendar {
      left: 0;
      right: 0;
      padding: 2rem;
    }

    .overlay.passengers {
      right: 0;
      width: 26.25rem;
      padding: 2.5rem;
    }

    .section-title {
      font-size: 0.875rem;
      font-weight: 700;
      color: #111827;
      margin-bottom: 0.75rem;
    }

    .destination-item {
      width: 100%;
      display: flex;
      align-items: center;
      gap: 0.75rem;
      padding: 0.5rem 0.75rem;
      border-radius: 0.75rem;
      border: none;
      background: transparent;
      cursor: pointer;
      text-align: left;
      transition: background 0.2s;
    }

    .destination-item:hover {
      background: #f9fafb;
    }

    .icon-wrapper {
      padding: 0.5rem;
      border-radius: 0.5rem;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .icon-wrapper.yellow {
      background: #fef3c7;
    }

    .icon-wrapper.blue {
      background: #dbeafe;
    }

    .icon-wrapper.green {
      background: #d1fae5;
    }

    .icon-wrapper.orange {
      background: #fed7aa;
    }

    .icon-wrapper.yellow svg {
      color: #fbbf24;
    }

    .icon-wrapper.blue svg {
      color: #3b82f6;
    }

    .icon-wrapper.green svg {
      color: #10b981;
    }

    .icon-wrapper.orange svg {
      color: #f97316;
    }

    .destination-name {
      font-size: 0.875rem;
      font-weight: 500;
      color: #111827;
    }

    .recent-item {
      flex: 1;
    }

    .recent-route {
      font-size: 0.875rem;
      font-weight: 700;
      color: #111827;
      line-height: 1.25;
    }

    .recent-details {
      font-size: 0.75rem;
      color: #6b7280;
      margin-top: 0.125rem;
    }

    .calendar-grid {
      display: flex;
      gap: 4rem;
      justify-content: center;
    }

    .month {
      flex: none;
    }

    .month-name {
      font-size: 1.125rem;
      font-weight: 700;
      text-align: center;
      margin-bottom: 1.25rem;
    }

    .weekdays {
      display: grid;
      grid-template-columns: repeat(7, 2.75rem);
      gap: 0.25rem;
      margin-bottom: 0.5rem;
    }

    .weekday {
      font-size: 0.875rem;
      color: #6b7280;
      text-align: center;
      padding: 0.25rem;
    }

    .days {
      display: grid;
      grid-template-columns: repeat(7, 2.75rem);
      gap: 0.25rem;
    }

    .day {
      height: 2.75rem;
      width: 2.75rem;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 0.5rem;
      border: none;
      background: transparent;
      cursor: pointer;
      font-size: 1rem;
      color: #111827;
      transition: background 0.2s;
    }

    .day:hover:not(.empty):not(.other-month) {
      background: #f3f4f6;
    }

    .day.selected {
      background: #0E7490;
      color: white;
    }

    .day.empty {
      cursor: default;
    }

    .day.other-month {
      color: #d1d5db;
    }

    .passenger-row {
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 1rem;
    }

    .passenger-info {
      flex: 1;
    }

    .passenger-label {
      font-size: 0.875rem;
      font-weight: 600;
      color: #111827;
    }

    .passenger-desc {
      font-size: 0.75rem;
      color: #6b7280;
    }

    .passenger-controls {
      display: flex;
      align-items: center;
      gap: 0.75rem;
    }

    .passenger-btn {
      height: 2rem;
      width: 2rem;
      border-radius: 9999px;
      border: 1px solid #e5e7eb;
      background: white;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 1rem;
      transition: all 0.2s;
    }

    .passenger-btn:hover {
      background: #f9fafb;
      border-color: #d1d5db;
    }

    .passenger-count {
      width: 2rem;
      text-align: center;
      font-weight: 500;
    }

    .space-y-5>*:not(:last-child) {
      margin-bottom: 1.25rem;
    }

    .space-y-1>*:not(:last-child) {
      margin-bottom: 0.25rem;
    }
  </style>
</head>

<body>
  <div class="container" id="container">
    <div class="search-bar">
      <button class="search-field" id="departure-field">
        <div class="field-label">Departure</div>
        <div class="field-value" id="departure-value">Search destinations</div>
      </button>

      <button class="search-field" id="arrival-field">
        <div class="field-label">Arrival</div>
        <div class="field-value" id="arrival-value">Search destinations</div>
      </button>

      <button class="search-field" id="date-field">
        <div class="field-label">Date</div>
        <div class="field-value" id="date-value">Add dates</div>
      </button>

      <button class="search-field" id="passengers-field">
        <div class="field-label">Passengers</div>
        <div class="field-value" id="passengers-value">Add passengers</div>
      </button>

      <button class="search-button" id="search-btn">
        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
      </button>
    </div>

    <!-- Destinations Overlay -->
    <div class="overlay destinations" id="destinations-overlay">
      <div class="space-y-5">
        <div>
          <h3 class="section-title">Recent Searches</h3>
          <div class="space-y-1" id="recent-searches"></div>
        </div>
        <div>
          <h3 class="section-title" id="destinations-title">Suggested Departure</h3>
          <div class="space-y-1" id="destinations-list"></div>
        </div>
      </div>
    </div>

    <!-- Calendar Overlay -->
    <div class="overlay calendar" id="calendar-overlay">
      <div class="calendar-grid" id="calendar-grid"></div>
    </div>

    <!-- Passengers Overlay -->
    <div class="overlay passengers" id="passengers-overlay">
      <div class="passenger-row">
        <div class="passenger-info">
          <div class="passenger-label">Children</div>
          <div class="passenger-desc">Below age 5</div>
        </div>
        <div class="passenger-controls">
          <button class="passenger-btn" id="children-minus">−</button>
          <span class="passenger-count" id="children-count">0</span>
          <button class="passenger-btn" id="children-plus">+</button>
        </div>
      </div>
      <div class="passenger-row">
        <div class="passenger-info">
          <div class="passenger-label">Members</div>
          <div class="passenger-desc">Above age 20</div>
        </div>
        <div class="passenger-controls">
          <button class="passenger-btn" id="members-minus">−</button>
          <span class="passenger-count" id="members-count">0</span>
          <button class="passenger-btn" id="members-plus">+</button>
        </div>
      </div>
    </div>
  </div>

  <script>
    // State
    let activeField = null;
    let departure = "Search destinations";
    let arrival = "Search destinations";
    let selectedDates = [];
    let passengers = { children: 0, members: 0 };

    // Data
    const recentSearches = [
      { id: "1", route: "New York → London", date: "Aug 15, 2025", passengers: "2 passengers", color: "yellow" },
      { id: "2", route: "Paris → Tokyo", date: "Sep 20, 2025", passengers: "1 passenger", color: "blue" },
    ];

    const destinations = [
      { id: "1", name: "New York", color: "yellow" },
      { id: "2", name: "London", color: "blue" },
      { id: "3", name: "Paris", color: "green" },
      { id: "4", name: "Tokyo", color: "orange" },
      { id: "5", name: "Dubai", color: "yellow" },
    ];

    // Elements
    const container = document.getElementById('container');
    const departureField = document.getElementById('departure-field');
    const arrivalField = document.getElementById('arrival-field');
    const dateField = document.getElementById('date-field');
    const passengersField = document.getElementById('passengers-field');
    const departureValue = document.getElementById('departure-value');
    const arrivalValue = document.getElementById('arrival-value');
    const dateValue = document.getElementById('date-value');
    const passengersValue = document.getElementById('passengers-value');
    const destinationsOverlay = document.getElementById('destinations-overlay');
    const calendarOverlay = document.getElementById('calendar-overlay');
    const passengersOverlay = document.getElementById('passengers-overlay');

    // Handle field clicks
    function handleFieldClick(field) {
      if (activeField === field) {
        closeAllOverlays();
        return;
      }

      closeAllOverlays();
      activeField = field;

      const fields = [departureField, arrivalField, dateField, passengersField];
      fields.forEach(f => f.classList.remove('active'));

      if (field === 'departure') {
        departureField.classList.add('active');
        destinationsOverlay.classList.add('active');
        document.getElementById('destinations-title').textContent = 'Suggested Departure';
        renderDestinations();
        renderRecentSearches();
      } else if (field === 'arrival') {
        arrivalField.classList.add('active');
        destinationsOverlay.classList.add('active');
        document.getElementById('destinations-title').textContent = 'Suggested Arrival';
        renderDestinations();
        renderRecentSearches();
      } else if (field === 'date') {
        dateField.classList.add('active');
        calendarOverlay.classList.add('active');
        renderCalendar();
      } else if (field === 'passengers') {
        passengersField.classList.add('active');
        passengersOverlay.classList.add('active');
      }
    }

    function closeAllOverlays() {
      activeField = null;
      [departureField, arrivalField, dateField, passengersField].forEach(f => f.classList.remove('active'));
      [destinationsOverlay, calendarOverlay, passengersOverlay].forEach(o => o.classList.remove('active'));
    }

    // Render destinations
    function renderDestinations() {
      const list = document.getElementById('destinations-list');
      list.innerHTML = destinations.map(dest => `
        <button class="destination-item" onclick="selectDestination('${dest.name}')">
          <div class="icon-wrapper ${dest.color}">
            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.8 19.2 16 11l3.5-3.5C21 6 21.5 4 21 3c-1-.5-3 0-4.5 1.5L13 8 4.8 6.2c-.5-.1-.9.1-1.1.5l-.3.5c-.2.5-.1 1 .3 1.3L9 12l-2 3H4l-1 1 3 2 2 3 1-1v-3l3-2 3.5 5.3c.3.4.8.5 1.3.3l.5-.2c.4-.3.6-.7.5-1.2z"/></svg>
          </div>
          <span class="destination-name">${dest.name}</span>
        </button>
      `).join('');
    }

    function renderRecentSearches() {
      const list = document.getElementById('recent-searches');
      list.innerHTML = recentSearches.map(search => {
        const cities = search.route.split(' → ');
        const city = activeField === 'departure' ? cities[0] : cities[1];
        return `
          <button class="destination-item" onclick="selectDestination('${city}')">
            <div class="icon-wrapper ${search.color}">
              <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.8 19.2 16 11l3.5-3.5C21 6 21.5 4 21 3c-1-.5-3 0-4.5 1.5L13 8 4.8 6.2c-.5-.1-.9.1-1.1.5l-.3.5c-.2.5-.1 1 .3 1.3L9 12l-2 3H4l-1 1 3 2 2 3 1-1v-3l3-2 3.5 5.3c.3.4.8.5 1.3.3l.5-.2c.4-.3.6-.7.5-1.2z"/></svg>
            </div>
            <div class="recent-item">
              <div class="recent-route">${search.route}</div>
              <div class="recent-details">${search.date} · ${search.passengers}</div>
            </div>
          </button>
        `;
      }).join('');
    }

    function selectDestination(name) {
      if (activeField === 'departure') {
        departure = name;
        departureValue.textContent = name;
      } else if (activeField === 'arrival') {
        arrival = name;
        arrivalValue.textContent = name;
      }
      closeAllOverlays();
    }

    // Calendar
    function renderCalendar() {
      const grid = document.getElementById('calendar-grid');
      const today = new Date();
      const months = [today, new Date(today.getFullYear(), today.getMonth() + 1)];

      grid.innerHTML = months.map(month => {
        const monthName = month.toLocaleDateString('en-US', { month: 'long', year: 'numeric' });
        const firstDay = new Date(month.getFullYear(), month.getMonth(), 1);
        const lastDay = new Date(month.getFullYear(), month.getMonth() + 1, 0);
        const startPadding = firstDay.getDay();
        const daysInMonth = lastDay.getDate();

        let daysHTML = '';
        for (let i = 0; i < startPadding; i++) {
          daysHTML += '<button class="day empty"></button>';
        }
        for (let day = 1; day <= daysInMonth; day++) {
          const date = new Date(month.getFullYear(), month.getMonth(), day);
          const isSelected = selectedDates.some(d => d.getTime() === date.getTime());
          daysHTML += `<button class="day ${isSelected ? 'selected' : ''}" onclick="toggleDate('${date.toISOString()}')">${day}</button>`;
        }

        return `
          <div class="month">
            <div class="month-name">${monthName}</div>
            <div class="weekdays">
              <div class="weekday">S</div>
              <div class="weekday">M</div>
              <div class="weekday">T</div>
              <div class="weekday">W</div>
              <div class="weekday">T</div>
              <div class="weekday">F</div>
              <div class="weekday">S</div>
            </div>
            <div class="days">${daysHTML}</div>
          </div>
        `;
      }).join('');
    }

    function toggleDate(dateStr) {
      const date = new Date(dateStr);
      const index = selectedDates.findIndex(d => d.getTime() === date.getTime());
      
      if (index > -1) {
        selectedDates.splice(index, 1);
      } else {
        selectedDates.push(date);
      }
      
      updateDateDisplay();
      renderCalendar();
    }

    function updateDateDisplay() {
      if (selectedDates.length === 0) {
        dateValue.textContent = 'Add dates';
      } else if (selectedDates.length === 1) {
        dateValue.textContent = selectedDates[0].toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
      } else {
        const sorted = [...selectedDates].sort((a, b) => a - b);
        dateValue.textContent = `${sorted[0].toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} - ${sorted[sorted.length - 1].toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}`;
      }
    }

    // Passengers
    function updatePassengerDisplay() {
      document.getElementById('children-count').textContent = passengers.children;
      document.getElementById('members-count').textContent = passengers.members;
      
      const total = passengers.children + passengers.members;
      passengersValue.textContent = total === 0 ? 'Add passengers' : `${total} passenger${total > 1 ? 's' : ''}`;
    }

    document.getElementById('children-minus').addEventListener('click', () => {
      passengers.children = Math.max(0, passengers.children - 1);
      updatePassengerDisplay();
    });

    document.getElementById('children-plus').addEventListener('click', () => {
      passengers.children++;
      updatePassengerDisplay();
    });

    document.getElementById('members-minus').addEventListener('click', () => {
      passengers.members = Math.max(0, passengers.members - 1);
      updatePassengerDisplay();
    });

    document.getElementById('members-plus').addEventListener('click', () => {
      passengers.members++;
      updatePassengerDisplay();
    });

    // Event listeners
    departureField.addEventListener('click', () => handleFieldClick('departure'));
    arrivalField.addEventListener('click', () => handleFieldClick('arrival'));
    dateField.addEventListener('click', () => handleFieldClick('date'));
    passengersField.addEventListener('click', () => handleFieldClick('passengers'));

    document.addEventListener('click', (e) => {
      if (!container.contains(e.target)) {
        closeAllOverlays();
      }
    });

    // Make functions global
    window.selectDestination = selectDestination;
    window.toggleDate = toggleDate;
  </script>
</body>

</html>
All Prompts