VibeCoderzVibeCoderz
All Prompts
Responsive Collapsible Help Banner with Intent CTAs preview
bannertailwindresponsiveinteractivecollapsiblectachipsservicelucide-icons

Responsive Collapsible Help Banner with Intent CTAs

Адаптивный баннер поддержки с интерактивными кнопками CTA. Показывает услуги (ремонт, установка), сворачивается. Tailwind CSS, иконки Lucide.

Prompt

<div class="xl:py-4 text-white bg-gradient-to-r from-slate-900 to-slate-800 border-slate-700 border-b pt-4 pb-4"
  data-element-locator="html &gt; body:nth-of-type(1) &gt; header:nth-of-type(1) &gt; div:nth-of-type(3)"
  id="helpBanner">
  <div class="sm:px-6 lg:px-8 sm:py-4 max-w-7xl mr-auto ml-auto pt-3 pr-4 pb-3 pl-4 relative" id="bannerContainer">
    <button aria-expanded="true" aria-controls="headerRow chipsMobile chipsDesktop intentCtas" class="inline-flex hover:bg-white/10 transition xl:top-22 xl:right-8 text-white w-7 h-7 border-white/20 border rounded-md absolute top-2 right-3 items-center justify-center" title="Collapse" id="bannerToggle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-lucide="chevron-up" class="lucide lucide-chevron-up w-4 h-4"><path d="m18 15-6-6-6 6" class=""></path></svg><span class="sr-only">Collapse banner</span></button>

    <div id="topSpacer" class="flex gap-3 gap-x-3 gap-y-3 items-start">
      <div class="flex-shrink-0 mt-0.5"></div>
    </div>

    <!-- Intent chips: mobile -->
    <div class="flex gap-4 pb-3 gap-x-4 gap-y-4 items-start justify-between" id="headerRow">
      <div class="flex items-center gap-3">
        <div class="grid place-items-center w-10 h-10 rounded-md bg-white/10 ring-1 ring-white/10">
          <svg xmlns="http://www.w3.org/2000/svg" class="lucide lucide-sparkles w-5 h-5" viewBox="0 0 24 24" fill="none"
            stroke="currentColor" stroke-width="1.5">
            <path
              d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"
              class="">
            </path>
            <path d="M20 2v4" class=""></path>
            <path d="M22 4h-4" class=""></path>
            <circle cx="4" cy="20" r="2" class=""></circle>
          </svg>
        </div>
        <div class="min-w-0">
          <h3 class="text-lg sm:text-2xl tracking-tight text-white/95 font-geist font-semibold">How can we help today?
          </h3>
          <p class="text-xs sm:text-sm text-white/70 font-geist">Choose an option to see quick actions and get help
            faster.</p>
        </div>
      </div>
    </div>
    <div id="chipsMobile" class="md:hidden flex gap-2 items-center flex-wrap" style="">
      <span class="text-xs font-medium uppercase text-white/60 font-geist">I need</span>
      <button type="button" data-intent="repair" aria-pressed="false" class="intent-pill inline-flex items-center gap-1.5 rounded-md border border-white/20 bg-white/10 px-3 py-1.5 text-xs text-white hover:bg-white/20 transition font-geist">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-lucide="wrench" class="lucide lucide-wrench w-3.5 h-3.5"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z" class=""></path></svg>
          Repair
        </button>
      <button type="button" data-intent="installation" aria-pressed="false" class="intent-pill inline-flex items-center gap-1.5 rounded-md border border-white/20 bg-white/10 px-3 py-1.5 text-xs text-white hover:bg-white/20 transition font-geist">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-lucide="home" class="lucide lucide-home w-3.5 h-3.5"><path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8" class=""></path><path d="M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" class=""></path></svg>
          Installation
        </button>
      <button type="button" data-intent="tuneup" aria-pressed="false" class="intent-pill inline-flex items-center gap-1.5 rounded-md border border-white/20 bg-white/10 px-3 py-1.5 text-xs text-white hover:bg-white/20 transition font-geist">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-lucide="gauge" class="lucide lucide-gauge w-3.5 h-3.5"><path d="m12 14 4-4" class=""></path><path d="M3.34 19a10 10 0 1 1 17.32 0" class=""></path></svg>
          Tune‑Up
        </button>
      <a href="tel:18055550134" data-intent="emergency" aria-pressed="false"
        class="inline-flex items-center gap-1.5 rounded-md border border-white/20 bg-white/10 px-3 py-1.5 text-xs text-white hover:bg-white/20 transition font-geist">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
          stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"
          data-lucide="alarm-clock-off" class="lucide lucide-alarm-clock-off w-3.5 h-3.5">
          <path d="M6.87 6.87a8 8 0 1 0 11.26 11.26" class=""></path>
          <path d="M19.9 14.25a8 8 0 0 0-9.15-9.15" class=""></path>
          <path d="m22 6-3-3" class=""></path>
          <path d="M6.26 18.67 4 21" class=""></path>
          <path d="m2 2 20 20" class=""></path>
          <path d="M4 4 2 6" class=""></path>
        </svg>
        Emergency
      </a>
    </div>

    <!-- Header Row with Title -->


    <!-- Intent chips: desktop -->
    <div id="chipsDesktop" class="hidden md:flex gap-2 max-w-7xl items-center flex-wrap" style="">
      <span class="text-xs font-medium uppercase text-white/60 font-geist">I need</span>
      <button type="button" data-intent="repair" aria-pressed="false" class="intent-pill inline-flex items-center gap-1.5 rounded-md border border-white/20 bg-white/10 px-3 py-1.5 text-xs text-white hover:bg-white/20 transition font-geist">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-lucide="wrench" class="lucide lucide-wrench w-3.5 h-3.5"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z" class=""></path></svg>
          Repair
        </button>
      <button type="button" data-intent="installation" aria-pressed="false" class="intent-pill inline-flex items-center gap-1.5 rounded-md border border-white/20 bg-white/10 px-3 py-1.5 text-xs text-white hover:bg-white/20 transition font-geist">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-lucide="home" class="lucide lucide-home w-3.5 h-3.5"><path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8" class=""></path><path d="M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" class=""></path></svg>
          Installation
        </button>
      <button type="button" data-intent="tuneup" aria-pressed="false" class="intent-pill inline-flex items-center gap-1.5 rounded-md border border-white/20 bg-white/10 px-3 py-1.5 text-xs text-white hover:bg-white/20 transition font-geist">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" data-lucide="gauge" class="lucide lucide-gauge w-3.5 h-3.5"><path d="m12 14 4-4" class=""></path><path d="M3.34 19a10 10 0 1 1 17.32 0" class=""></path></svg>
          Tune‑Up
        </button>
      <a href="tel:18055550134" data-intent="emergency" aria-pressed="false"
        class="inline-flex items-center gap-1.5 rounded-md border border-white/20 bg-white/10 px-3 py-1.5 text-xs text-white hover:bg-white/20 transition font-geist">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
          stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"
          data-lucide="alarm-clock-off" class="lucide lucide-alarm-clock-off w-3.5 h-3.5">
          <path d="M6.87 6.87a8 8 0 1 0 11.26 11.26" class=""></path>
          <path d="M19.9 14.25a8 8 0 0 0-9.15-9.15" class=""></path>
          <path d="m22 6-3-3" class=""></path>
          <path d="M6.26 18.67 4 21" class=""></path>
          <path d="m2 2 20 20" class=""></path>
          <path d="M4 4 2 6" class=""></path>
        </svg>
        Emergency
      </a>
    </div>

    <!-- Dynamic CTAs with Back Button -->
    <div class="flex flex-wrap gap-2 mt-3 gap-x-2 gap-y-2 items-center" role="region" aria-live="polite"
      aria-atomic="true" id="intentCtas">
      <span class="text-xs text-white/70 font-sans">Choose an option above to see quick actions.</span></div>

    <script>
      (function () {
          const banner = document.getElementById('helpBanner');
          if (!banner) return;

          const container = document.getElementById('bannerContainer');
          const ctaEl = banner.querySelector('#intentCtas');
          const pills = Array.from(banner.querySelectorAll('[data-intent]'));
          const toggle = banner.querySelector('#bannerToggle');
          const headerRow = banner.querySelector('#headerRow');
          const chipsMobile = banner.querySelector('#chipsMobile');
          const chipsDesktop = banner.querySelector('#chipsDesktop');
          const topSpacer = banner.querySelector('#topSpacer');

          let currentIntent = null;

          const CTAS = {
            repair: [
              { href: '#signs-repair', text: 'Scroll to repair section', icon: 'arrow-down', variant: 'ghost' },
              { href: '/ac-repair/camarillo-ca', text: 'Repairs landing page', icon: 'file-text', variant: 'ghost' },
              { href: 'tel:18055550134', text: 'Call for Repair', icon: 'phone', variant: 'primary' }
            ],
            installation: [
              { href: '#install-cost', text: 'See installation info', icon: 'arrow-down', variant: 'ghost' },
              { href: '/ac-installation/camarillo-ca', text: 'Installation page', icon: 'file-text', variant: 'ghost' },
              { href: 'tel:18055550134', text: 'Call about Installation', icon: 'phone', variant: 'primary' }
            ],
            tuneup: [
              { href: '#maintenance', text: 'See tune‑up details', icon: 'arrow-down', variant: 'ghost' },
              { href: '/ac-tune-up/camarillo-ca', text: 'Tune‑Up page', icon: 'file-text', variant: 'ghost' },
              { href: 'tel:18055550134', text: 'Call for Tune‑Up', icon: 'phone', variant: 'primary' }
            ],
            emergency: [
              { href: 'tel:18055550134', text: 'Call Emergency Service', icon: 'alarm-clock-off', variant: 'primary' },
              { href: '#quote', text: 'Request Urgent Callback', icon: 'message-square', variant: 'ghost' },
              { href: '/ac-repair/camarillo-ca', text: 'Repairs Page', icon: 'arrow-right', variant: 'ghost' }
            ]
          };

          function pillClasses(variant) {
            if (variant === 'primary') {
              return 'inline-flex items-center gap-2 h-9 px-3 rounded-md bg-white text-slate-900 hover:bg-white/90 text-[13px] font-medium font-sans';
            }
            return 'inline-flex items-center gap-2 h-9 px-3 rounded-md border border-white/20 text-white hover:bg-white/10 text-[13px] font-sans';
          }

          function renderCTAs(kind) {
            const items = CTAS[kind] || [];
            if (items.length) {
              const backBtn = '<button id="ctaBack" class="inline-flex items-center gap-2 h-9 px-3 rounded-md border border-white/20 text-white hover:bg-white/10 text-[13px] font-sans"><i data-lucide="arrow-left" class="w-4 h-4"></i>Back</button>';
              const ctaButtons = items.map(item => {
                const clickHandler = item.href.startsWith('#') ? `onclick="handleScrollClick(event, '${item.href}')"` : '';
                return `<a href="${item.href}" class="${pillClasses(item.variant)}" role="button" ${clickHandler}><i data-lucide="${item.icon}" class="w-4 h-4"></i>${item.text}</a>`;
              }).join('');
              ctaEl.innerHTML = backBtn + ctaButtons;
              
              // Add back button handler
              const backButton = ctaEl.querySelector('#ctaBack');
              if (backButton) {
                backButton.addEventListener('click', () => {
                  currentIntent = null;
                  setActivePill(null);
                  renderCTAs('');
                });
              }
            } else {
              ctaEl.innerHTML = '<span class="text-xs text-white/70 font-sans">Choose an option above to see quick actions.</span>';
            }
            if (window.lucide) window.lucide.createIcons({ attrs: { 'stroke-width': 1.5 } });
          }

          // Global scroll handler
          window.handleScrollClick = function(e, href) {
            e.preventDefault();
            const target = document.querySelector(href);
            if (target) {
              target.scrollIntoView({ behavior: 'smooth', block: 'start' });
            }
          };

          function setActivePill(activeIntent) {
            pills.forEach(btn => {
              const isActive = btn.getAttribute('data-intent') === activeIntent;
              btn.setAttribute('aria-pressed', isActive ? 'true' : 'false');
              if (isActive) {
                btn.classList.remove('bg-white/10', 'text-white');
                btn.classList.add('bg-white', 'text-slate-900');
              } else {
                btn.classList.remove('bg-white', 'text-slate-900');
                btn.classList.add('bg-white/10', 'text-white');
              }
            });
          }

          pills.forEach(btn => {
            btn.addEventListener('click', (e) => {
              const intent = btn.getAttribute('data-intent');
              
              // If it's an anchor with tel: link, let it proceed
              if (btn.tagName === 'A' && btn.getAttribute('href')?.startsWith('tel:')) {
                return;
              }
              
              e.preventDefault();
              currentIntent = intent;
              setActivePill(intent);
              renderCTAs(intent);
            });
          });

          function setChipRow(el, collapsed) {
            if (!el) return;
            if (collapsed) {
              el.classList.remove('flex-wrap');
              el.classList.add('whitespace-nowrap','overflow-x-auto');
              el.style.scrollbarWidth = 'none';
              el.style.msOverflowStyle = 'none';
              Array.from(el.querySelectorAll('*')).forEach(n => n.classList && n.classList.add('shrink-0'));
            } else {
              el.classList.add('flex-wrap');
              el.classList.remove('whitespace-nowrap','overflow-x-auto');
              el.style.scrollbarWidth = '';
              el.style.msOverflowStyle = '';
              Array.from(el.querySelectorAll('*')).forEach(n => n.classList && n.classList.remove('shrink-0'));
            }
          }

          function setCollapsed(collapsed) {
            toggle.setAttribute('aria-expanded', String(!collapsed));
            toggle.title = collapsed ? 'Expand' : 'Collapse';
            
            if (collapsed) {
              // Hide only the description paragraph
              const description = headerRow.querySelector('p');
              if (description) description.classList.add('hidden');
              
              ctaEl && ctaEl.classList.add('hidden');
              topSpacer && topSpacer.classList.add('hidden');
              setChipRow(chipsMobile, true);
              setChipRow(chipsDesktop, true);
              if (container) {
                container.classList.add('py-2');
                container.classList.remove('pt-3','pb-3','sm:py-4');
              }
              toggle.innerHTML = '<i data-lucide="chevron-down" class="w-4 h-4"></i><span class="sr-only">Expand banner</span>';
            } else {
              const description = headerRow.querySelector('p');
              if (description) description.classList.remove('hidden');
              
              ctaEl && ctaEl.classList.remove('hidden');
              topSpacer && topSpacer.classList.remove('hidden');
              setChipRow(chipsMobile, false);
              setChipRow(chipsDesktop, false);
              if (container) {
                container.classList.remove('py-2');
                container.classList.add('pt-3','pb-3','sm:py-4');
              }
              toggle.innerHTML = '<i data-lucide="chevron-up" class="w-4 h-4"></i><span class="sr-only">Collapse banner</span>';
            }
            if (window.lucide) window.lucide.createIcons({ attrs: { 'stroke-width': 1.5 } });
          }

          // Init
          renderCTAs('');
          setCollapsed(false);

          toggle.addEventListener('click', () => {
            const isExpanded = toggle.getAttribute('aria-expanded') === 'true';
            setCollapsed(isExpanded);
          });

          if (!window.lucide) {
            window.addEventListener('load', () => {
              if (window.lucide) window.lucide.createIcons({ attrs: { 'stroke-width': 1.5 } });
            });
          }
        })();
    </script>
  </div>
</div>
All Prompts