Emberlyn About About Block - Let's templates
Unlock every premium block and template with All-Access from $20 / 3 months, cancel anytime. Get All-Access
All blocks
Free About

Emberlyn About

A about block extracted from the Emberlyn template, available in Tailwind CSS and Bootstrap.

0 2
Emberlyn About preview
emberlyn.html
<!DOCTYPE html>
<html lang="en">
<head>
  <script>
    window.FontAwesomeConfig = { autoReplaceSvg: 'nest' };
  </script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Emberlyn About | Tailwind CSS UI Block</title>
  <meta name="description" content="A about block extracted from the Emberlyn template, available in Tailwind CSS and Bootstrap.">
  <meta name="keywords" content="Emberlyn, Tailwind CSS template, HTML website template, portfolio template, wedding photographer website, photography portfolio, elopement photographer, photo studio template, editorial portfolio">
  <meta name="author" content="Let's templates">
  <link rel="canonical" href="">

  <meta property="og:type" content="product">
  <meta property="og:site_name" content="Let's templates">
  <meta property="og:locale" content="en_US">
  <meta property="og:url" content="">
  <meta property="og:title" content="Emberlyn | Tailwind CSS Portfolio Template">
  <meta property="og:description" content="A quiet, editorial Tailwind CSS portfolio template for wedding photographers, with a black-and-white hero slider, a staggered journal and a date availability calendar.">
  <meta property="og:image" content="">
  <meta property="og:image:alt" content="Emberlyn template preview">

  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:url" content="">
  <meta name="twitter:title" content="Emberlyn | Tailwind CSS Portfolio Template">
  <meta name="twitter:description" content="A quiet, editorial Tailwind CSS portfolio template for wedding photographers, with a black-and-white hero slider, a staggered journal and a date availability calendar.">
  <meta name="twitter:image" content="">
  <meta name="twitter:image:alt" content="Emberlyn template preview">
  <script src="https://cdn.tailwindcss.com/3.4.17"></script>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@400;500;600&family=Mrs+Saint+Delafield&family=Playfair+Display:wght@400;500&family=Poppins:wght@300;400;500&display=swap" rel="stylesheet">
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: { paper: '#f7f6f2', sand: '#efede8', sage: { DEFAULT: '#5f6c5f', deep: '#4b564b' }, ink: '#232323', mute: '#707070' },
          fontFamily: { sans: ['Poppins', 'sans-serif'], serif: ['Playfair Display', 'serif'], caps: ['Cormorant Garamond', 'serif'], script: ['Mrs Saint Delafield', 'cursive'] }
        }
      }
    }
  </script>
  <style>
    @view-transition { navigation: auto; }
    ::view-transition-old(root) { animation: 180ms ease-out both page-fade-out; }
    ::view-transition-new(root) { animation: 220ms ease-in both page-fade-in; }
    @keyframes page-fade-out { to { opacity: 0; } }
    @keyframes page-fade-in { from { opacity: 0; } }
    html { scroll-behavior: smooth; }
    [hidden] { display: none !important; }
    .slide { transition: opacity .7s ease, transform 6s ease; }
    .slide:not(.is-active) { opacity: 0; }
    .slide.is-active { transform: scale(1.04); }
    .notch { clip-path: polygon(0 0, 100% 0, 100% calc(100% - 1.25rem), calc(50% + 1.25rem) calc(100% - 1.25rem), 50% 100%, calc(50% - 1.25rem) calc(100% - 1.25rem), 0 calc(100% - 1.25rem)); }
    .reveal-ready [data-reveal] { opacity: 0; transform: translateY(24px); transition: opacity .7s ease, transform .7s ease; transition-delay: var(--reveal-delay, 0ms); }
    .reveal-ready [data-reveal].is-visible { opacity: 1; transform: none; }
    @media (prefers-reduced-motion: reduce) {
      html { scroll-behavior: auto; }
      .slide { transition: none; }
      .slide.is-active { transform: none; }
      ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
    }
  </style>
</head>
<body class="bg-paper font-sans font-light text-ink antialiased">
<% active_page = "index" %>
<% left_nav = { "about" => "meet us", "story" => "our story", "services" => "services" } %>
<% right_nav = { "portfolio" => "portfolio", "blog" => "the journal", "contact" => "hire us" } %>
<% left_nav.each do |slug, label| %>
<% active = active_page == slug %>
<% end %>
<% right_nav.each do |slug, label| %>
<% active = active_page == slug %>
<% end %>
<% { "index" => "home" }.merge(left_nav).merge(right_nav).each do |slug, label| %>
<% active = active_page == slug %>
<% end %>
<% slides = [["1460978812857-470ed1c77af0", "Couple kissing on a windy shore, the bride's veil lifting in black and white"], ["1537633552985-df8429e8048b", "Bride and groom embracing by the sea, her long veil trailing on the pebbles"], ["1532712938310-34cb3982ef74", "Newlyweds walking hand in hand across a hilltop at dusk"]] %>
<% slides.each_with_index do |(photo, alt), index| %>
<% end %>
<% slides.each_index do |index| %>
<% end %>
<% [["fa-instagram", "Instagram", "https://www.instagram.com"], ["fa-facebook-f", "Facebook", "https://www.facebook.com"], ["fa-pinterest-p", "Pinterest", "https://www.pinterest.com"]].each do |icon, label, url| %>
<% end %>
<!-- block:start about -->
  <section id="welcome" class="relative">
    <div class="mx-auto h-24 w-px bg-ink/60 md:h-28" aria-hidden="true"></div>
    <p class="mx-auto max-w-3xl px-6 pb-20 pt-12 text-center font-caps text-base font-medium uppercase leading-relaxed tracking-[0.25em] md:pb-28 md:text-lg" data-reveal>
      We exist to share the joy of a celebration. Every story we tell is shaped around yours: tender or playful, wild or quietly classic. We look after every small detail so you can stay inside the moments that matter.
    </p>
    <div class="relative">
      <div class="absolute inset-x-0 bottom-0 top-28 bg-white md:top-36" aria-hidden="true"></div>
      <div class="relative mx-auto grid max-w-6xl gap-10 px-5 pb-20 md:grid-cols-[0.8fr_1fr] md:gap-16 md:px-10 md:pb-28">
        <img src="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=900&q=80" alt="Portrait of photographer Elias Marlowe in black and white" class="aspect-[3/4] w-full object-cover grayscale" loading="lazy" data-reveal>
        <div class="md:pt-6">
          <h2 class="font-script text-6xl leading-none md:text-8xl">Hi, I'm Elias</h2>
          <div class="relative mt-16 border-l border-ink/60 pb-10 pl-8 md:ml-10 md:mt-24 md:pl-12">
            <p class="max-w-md text-sm leading-[2] text-ink/80">For ten years I worked in newsrooms, chasing deadlines across three countries. A friend's wedding in Porto changed the plan: I came home with four hundred photos and a new job. Today I photograph around thirty weddings a year, mostly couples who want honest pictures that still feel like them in thirty years.</p>
            <a href="contact.html" class="absolute -bottom-5 -left-5 bg-sage px-9 py-3 text-[11px] uppercase tracking-[0.4em] text-white transition hover:bg-sage-deep md:-left-14">Contact</a>
          </div>
        </div>
      </div>
    </div>
  </section>
  <!-- block:end about -->
<script>
    document.querySelectorAll('[data-menu-toggle]').forEach((button) => {
      const menu = document.getElementById(button.getAttribute('aria-controls'));
      if (!menu) return;
      button.addEventListener('click', () => {
        const open = button.getAttribute('aria-expanded') === 'true';
        button.setAttribute('aria-expanded', String(!open));
        menu.classList.toggle('hidden', open);
      });
    });

    document.querySelectorAll('[data-slider]').forEach((slider) => {
      const slides = [...slider.querySelectorAll('[data-slide]')];
      const dots = [...slider.querySelectorAll('[data-slider-dot]')];
      let current = 0;
      let timer;
      const show = (index) => {
        current = (index + slides.length) % slides.length;
        slides.forEach((slide, i) => {
          slide.classList.toggle('is-active', i === current);
          slide.toggleAttribute('aria-hidden', i !== current);
        });
        dots.forEach((dot, i) => dot.setAttribute('aria-pressed', String(i === current)));
      };
      const restart = () => {
        clearInterval(timer);
        if (!matchMedia('(prefers-reduced-motion: reduce)').matches) timer = setInterval(() => show(current + 1), 6000);
      };
      slider.querySelector('[data-slider-prev]')?.addEventListener('click', () => { show(current - 1); restart(); });
      slider.querySelector('[data-slider-next]')?.addEventListener('click', () => { show(current + 1); restart(); });
      dots.forEach((dot, i) => dot.addEventListener('click', () => { show(i); restart(); }));
      restart();
    });

    document.querySelectorAll('[data-carousel]').forEach((carousel) => {
      const slides = [...carousel.querySelectorAll('[data-carousel-slide]')];
      const index = carousel.querySelector('[data-carousel-index]');
      let current = 0;
      const show = (next) => {
        current = (next + slides.length) % slides.length;
        slides.forEach((slide, i) => { slide.hidden = i !== current; });
        if (index) index.textContent = current + 1;
      };
      carousel.querySelector('[data-carousel-prev]')?.addEventListener('click', () => show(current - 1));
      carousel.querySelector('[data-carousel-next]')?.addEventListener('click', () => show(current + 1));
    });

    document.querySelectorAll('[data-hover-list]').forEach((list) => {
      const preview = list.querySelector('[data-hover-preview]');
      if (!preview || !matchMedia('(hover: hover)').matches) return;
      list.querySelectorAll('[data-hover-item]').forEach((item) => {
        item.addEventListener('mouseenter', () => { preview.src = item.dataset.image; preview.style.opacity = '1'; });
        item.addEventListener('mouseleave', () => { preview.style.opacity = '0'; });
        item.addEventListener('mousemove', (event) => { preview.style.transform = `translate(${event.clientX + 28}px, ${event.clientY - 90}px) rotate(-3deg)`; });
      });
    });

    document.querySelectorAll('[data-availability]').forEach((root) => {
      const months = [...root.querySelectorAll('[data-month]')];
      const label = root.querySelector('[data-month-label]');
      const prev = root.querySelector('[data-month-prev]');
      const next = root.querySelector('[data-month-next]');
      const summary = root.querySelector('[data-availability-summary]');
      const note = root.querySelector('[data-availability-note]');
      let current = 0;
      const showMonth = (index) => {
        current = Math.max(0, Math.min(months.length - 1, index));
        months.forEach((month, i) => { month.hidden = i !== current; });
        label.textContent = months[current].dataset.month;
        prev.disabled = current === 0;
        next.disabled = current === months.length - 1;
      };
      prev.addEventListener('click', () => showMonth(current - 1));
      next.addEventListener('click', () => showMonth(current + 1));
      root.addEventListener('click', (event) => {
        const day = event.target.closest('[data-day]');
        if (!day || day.disabled) return;
        root.querySelectorAll('[data-day]').forEach((other) => other.setAttribute('aria-pressed', String(other === day)));
        summary.textContent = `${day.dataset.day} is free`;
        note.textContent = 'Lovely choice. Hold it now and I will keep it for you for seven days.';
      });
      showMonth(0);
    });

    document.querySelectorAll('[data-filter-group]').forEach((group) => {
      const items = document.querySelectorAll(group.dataset.filterGroup);
      group.querySelectorAll('[data-filter]').forEach((chip) => {
        chip.addEventListener('click', () => {
          group.querySelectorAll('[data-filter]').forEach((other) => other.setAttribute('aria-pressed', String(other === chip)));
          items.forEach((item) => { item.hidden = chip.dataset.filter !== 'all' && item.dataset.role !== chip.dataset.filter; });
        });
      });
    });

    document.querySelectorAll('[data-lightbox]').forEach((dialog) => {
      const image = dialog.querySelector('img');
      const caption = dialog.querySelector('[data-lightbox-caption]');
      document.querySelectorAll('[data-lightbox-open]').forEach((button) => {
        button.addEventListener('click', () => {
          image.src = button.dataset.full;
          image.alt = button.querySelector('img')?.alt || '';
          caption.textContent = button.dataset.caption;
          dialog.showModal();
        });
      });
      dialog.addEventListener('click', (event) => { if (event.target === dialog) dialog.close(); });
    });

    document.querySelectorAll('[data-contact-form]').forEach((form) => {
      form.addEventListener('submit', (event) => {
        event.preventDefault();
        const status = form.querySelector('[data-form-status]');
        if (!form.checkValidity()) {
          status.textContent = form.dataset.error;
          form.querySelector(':invalid')?.focus();
          return;
        }
        status.textContent = form.dataset.success;
        form.reset();
      });
    });

    document.querySelectorAll('[data-current-year]').forEach((el) => { el.textContent = new Date().getFullYear(); });

    (() => {
      const items = document.querySelectorAll('[data-reveal]');
      const skip = navigator.webdriver || !('IntersectionObserver' in window) || matchMedia('(prefers-reduced-motion: reduce)').matches;
      if (!items.length || skip) return;
      document.documentElement.classList.add('reveal-ready');
      const observer = new IntersectionObserver((entries) => {
        entries.forEach((entry) => {
          if (!entry.isIntersecting) return;
          entry.target.classList.add('is-visible');
          observer.unobserve(entry.target);
        });
      }, { rootMargin: '0px 0px -10% 0px' });
      items.forEach((item) => observer.observe(item));
    })();
  </script>
</body>
</html>

From this template

Emberlyn screenshot

Portfolio

Emberlyn

Unlimited access to all products

Unlock the entire library of premium templates and blocks. Renews automatically, cancel anytime.

$20 / 3 months or $60 / year
Get Unlimited Access