# Videolu hero: ücretsiz Shopify bölümü

> Metin ve düğmelerin arkasında tam genişlik, sessiz arka plan videosu; ayrı mobil video, kapak görselleri, duraklatma düğmesi. Video ekrana gelince yüklenir.

Videolu hero, bir başlık, metin ve en fazla iki düğmenin arkasında Shopify’da barındırılan sessiz bir videoyu döngüyle oynatan ücretsiz bir Shopify bölümüdür; mobil için isteğe bağlı ayrı bir video da ekleyebilirsiniz. Önce kapak görselleri görünür ve hareketin azaltılması istendiğinde yerinde kalır, duraklatma düğmesi her zaman oradadır ve video dosyası yalnızca bölüm ekrana geldiğinde yüklenir. Online Store 2.0 temalarında uygulama olmadan çalışır.

- **Kategori:** Hero ve bannerlar
- **Kullanıldığı yerler:** Ana sayfa, Koleksiyon, Açılış sayfaları
- **Okuduğu veri:** Shopify’da barındırılan video
- **Boyut:** 3 dosyada 34 KB, küçük bir betikle
- **Lisans:** MIT, © 2026 Lintel
- **Sayfa:** https://lintelagency.com/tr/kaynaklar/shopify-bolumleri/videolu-hero
- **Canlı demo:** https://lintelagency.com/resources/shopify-sections/demo/lib-video-hero.html
- **Eklenme tarihi:** 2026-11-02

## Ne işe yarar

- Bir ürünün yapılışını, giyilişini ya da kullanımını gösteren ana sayfa açılışı
- Başlığın arkasında kısa bir marka filmi olan kampanya ya da lansman sayfası
- Ürün serisini kullanımda gösteren döngülü bir klipli koleksiyon sayfası başlığı

## Tema düzenleyici ayarları

Bölüm tema düzenleyicide “Lib · Video hero” adıyla görünür. Kimlikler, türler, etiketler ve varsayılan değerler bölümün şemasından gelir. Etiketler tema düzenleyicide göründüğü gibi İngilizcedir.

### Video

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `video` | `video` | Desktop video | – |  |
| `video_mobile` | `video` | Mobile video | – |  |
| `image` | `image_picker` | Desktop poster image | – |  |
| `image_mobile` | `image_picker` | Mobile poster image | – |  |
| `pause_label` | `text` | Pause button label | Pause background video |  |
| `play_label` | `text` | Play button label | Play background video |  |
| `overlay_color` | `color` | Overlay color | #1C1917 |  |
| `overlay_opacity` | `range` | Overlay opacity | `35` | 0–90 %, step 5 |

### Content

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `eyebrow` | `text` | Eyebrow | Made in our studio |  |
| `heading` | `inline_richtext` | Heading | `Shaped by hand, <em>fired with care</em>` |  |
| `heading_tag` | `select` | Heading tag | h2 | `h1`, `h2`, `h3`, `p` |
| `heading_size` | `select` | Heading size | large | `small`, `medium`, `large`, `xlarge` |
| `text` | `richtext` | Text | `<p>Small-batch stoneware for everyday tables, glazed in earthy tones and made to last.</p>` |  |

### Layout

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `height` | `select` | Height on desktop | large | `small`, `medium`, `large`, `full` |
| `height_mobile` | `select` | Height on mobile | large | `small`, `medium`, `large`, `full` |
| `section_width` | `select` | Width | full | `page`, `full` |
| `corner_radius` | `range` | Corner radius | `12` | 0–40 px, step 2 |
| `content_position` | `select` | Content position on desktop | middle-left | `top-left`, `top-center`, `top-right`, `middle-left`, `middle-center`, `middle-right`, `bottom-left`, `bottom-center`, `bottom-right` |
| `content_position_mobile` | `select` | Content position on mobile | bottom | `top`, `middle`, `bottom` |
| `text_alignment_mobile` | `select` | Text alignment on mobile | left | `left`, `center`, `right` |
| `content_width` | `range` | Content max width | `620` | 320–960 px, step 20 |
| `content_box` | `select` | Content box | none | `none`, `solid` |

### Colors

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `color_bg` | `color` | Background | #F5EFE6 |  |
| `color_text` | `color` | Text | #FFFFFF |  |
| `color_accent` | `color` | Solid button | #FFFFFF |  |
| `color_accent_text` | `color` | Text on solid button | #1C1917 |  |
| `color_box` | `color` | Content box | #F5EFE6 |  |
| `color_box_text` | `color` | Text in content box | #2A211B |  |

### Spacing and visibility

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `padding_top` | `range` | Top padding on desktop | `0` | 0–200 px, step 4 |
| `padding_bottom` | `range` | Bottom padding on desktop | `0` | 0–200 px, step 4 |
| `padding_top_mobile` | `range` | Top padding on mobile | `0` | 0–160 px, step 4 |
| `padding_bottom_mobile` | `range` | Bottom padding on mobile | `0` | 0–160 px, step 4 |
| `show_on` | `select` | Show on | all | `all`, `desktop`, `mobile` |
| `anchor_id` | `text` | Anchor ID | – |  |

### Motion

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `animate` | `checkbox` | Animate text on load | `true` |  |

## Bloklar

### Button (`button`, en fazla 2)

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `label` | `text` | Label | Shop new pieces |  |
| `url` | `url` | Link | – |  |
| `style` | `select` | Style | primary | `primary`, `outline`, `text` |
| `new_tab` | `checkbox` | Open link in a new tab | `false` |  |

## Kurulum

### Shopify yönetim panelinde

1. Canlı temanızda değil, bir kopyasında çalışın: Shopify yönetim panelinde **Online Mağaza > Temalar** sayfasına gidin, mevcut temanızın **…** menüsünü açın ve **Kopya oluştur**’u seçin.
2. Kopyada **…** menüsünü açın ve **Kodu düzenle**’yi seçin.
3. `sections` klasörüne `lib-video-hero.liquid` adında yeni bir dosya ekleyin, aşağıdaki kaynak koddan `sections/lib-video-hero.liquid` içeriğini yapıştırıp kaydedin.
4. `lib-image.liquid` ve `lib-button.liquid` dosyalarını da aynı şekilde `snippets` klasörüne ekleyin. Başka bir Lib bölümünden gelen aynı adlı bir snippet zaten varsa aynı dosyadır; tek kopya yeterli.
5. Kopyada **Özelleştir**’i açın, **Bölüm ekle**’yi seçin ve **Lib · Video hero** bölümünü ekleyin. Örnek içeriği kendi içeriğinizle değiştirin, renkleri ayarlayın.
6. Kopyayı önizleyin, her şey doğru göründüğünde yayınlayın.

### Shopify CLI ile

Yerel tema klasörünüzde dosyaları indirin ve yalnızca bunları yayında olmayan bir temaya gönderin (temanın kimliğini `shopify theme list` gösterir):

```sh
curl -fsSL -o sections/lib-video-hero.liquid https://lintelagency.com/resources/shopify-sections/files/lib-video-hero.liquid
curl -fsSL -o snippets/lib-image.liquid https://lintelagency.com/resources/shopify-sections/files/lib-image.liquid
curl -fsSL -o snippets/lib-button.liquid https://lintelagency.com/resources/shopify-sections/files/lib-button.liquid
shopify theme push --theme <unpublished-theme-id> --only sections/lib-video-hero.liquid --only snippets/lib-image.liquid --only snippets/lib-button.liquid
```

Canlı temaya asla göndermeyin: her zaman yayında olmayan bir temanın kimliğini verin, `--live` ya da `--allow-live` kullanmayın. Ardından bölümü yukarıdaki gibi tema düzenleyicide ekleyin.

## Dosyalar

- [sections/lib-video-hero.liquid](https://lintelagency.com/resources/shopify-sections/files/lib-video-hero.liquid): `sections/` klasörüne
- [snippets/lib-image.liquid](https://lintelagency.com/resources/shopify-sections/files/lib-image.liquid): `snippets/` klasörüne
- [snippets/lib-button.liquid](https://lintelagency.com/resources/shopify-sections/files/lib-button.liquid): `snippets/` klasörüne

## Sık sorulan sorular

### Video nereden geliyor?

Videoyu bölümün video ayarından Shopify’a yüklersiniz; yani Shopify’da barındırılır, YouTube ya da Vimeo oynatıcısı yüklenmez. Bölüm, Shopify’ın yüklemenizden ürettiği MP4 dosyalarından ekranın ihtiyacını aşmayan en büyüğünü seçer: masaüstünde en fazla 1920px, mobil videoda 1080px.

### Mobilde farklı bir video kullanabilir miyim?

Evet. Bir mobil video ekleyin; 750px altında masaüstü videosunun yerine oynar ve masaüstü videosu telefonlarda hiç indirilmez. Mobil video yoksa masaüstü videosu her yerde oynar. Masaüstü ve mobil kapak görselleri de her biri kendi odak noktasıyla ayrı ayrı belirlenir.

### Erişilebilir mi?

Video sessizdir, dekoratiftir ve ekran okuyuculardan gizlenir. Bir video oynayabildiği sürece köşede bir duraklatma ve oynatma düğmesi durur; etiketlerini düzenleyicide değiştirebilirsiniz. Cihazı azaltılmış hareket isteyen ziyaretçiler kapak görselini görür ve videoyu oynat düğmesiyle başlatabilir.

### Sayfamı yavaşlatır mı?

Kapak görseli her hero görseli gibi yüklenir (bölüm sayfanın üst kısmındaysa hemen). Video dosyası ancak bölüm ekrana geldiğinde istenir; sayfa kaydırılıp bölüm görünümden çıkınca ya da tarayıcı sekmesi gizlenince duraklar. Betik, kütüphane içermeyen küçük bir custom element’tir.

### JavaScript kapalıysa ya da otomatik oynatma engellenirse ne olur?

Kapak görseli, üzerindeki metin ve düğmelerle yerinde kalır. Tarayıcı otomatik oynatmayı reddederse (örneğin veri tasarrufu modunda) düğme oynat konumuna geçer ve ziyaretçi videoyu kendisi başlatabilir.

## Kaynak kod

### sections/lib-video-hero.liquid

```liquid
{%- comment -%}
  MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections
{%- endcomment -%}
{%- comment -%}
  Video hero: a full-bleed, muted, looping Shopify-hosted background video (with an optional
  separate mobile video) under an overlay, with eyebrow, heading, text and up to two buttons (blocks) on top.
  Desktop and mobile poster images (each with its focal point) show first, and stay when there
  is no JavaScript, no video, or the visitor prefers reduced motion. A pause / play button is
  always shown while a video can play. The video file only loads when the section is on screen,
  and it pauses when scrolled away or when the tab is hidden.
  Depends on: snippets/lib-image.liquid, snippets/lib-button.liquid
{%- endcomment -%}

{%- liquid
  assign s = section.settings
  assign heading_tag = s.heading_tag | default: 'h2'
  assign eager = false
  if section.index <= 2
    assign eager = true
  endif

  comment
    Which video plays where: one video for every device, or a desktop and a mobile one.
  endcomment
  assign desktop_device = 'all'
  if s.video_mobile != blank
    assign desktop_device = 'desktop'
  endif
  assign has_video = false
  if s.video != blank or s.video_mobile != blank
    assign has_video = true
  endif
-%}

<lib-video-hero
  class="lib-video-hero lib-video-hero--{{ s.section_width }}"
  {% if s.anchor_id != blank %}
    id="{{ s.anchor_id | handleize }}"
  {% endif %}
  data-show="{{ s.show_on }}"
  data-height="{{ s.height }}"
  data-height-m="{{ s.height_mobile }}"
  {% if s.animate %}
    data-animate
  {% endif %}
  style="
    --lib-bg: {{ s.color_bg }};
    --lib-text: {{ s.color_text }};
    --lib-accent: {{ s.color_accent }};
    --lib-accent-text: {{ s.color_accent_text }};
    --lib-box: {{ s.color_box }};
    --lib-box-text: {{ s.color_box_text }};
    --lib-overlay: {{ s.overlay_color }};
    --lib-overlay-o: {{ s.overlay_opacity | divided_by: 100.0 }};
    --lib-content-w: {{ s.content_width }}px;
    --lib-radius-frame: {{ s.corner_radius }}px;
    --lib-pt: {{ s.padding_top }}px;
    --lib-pb: {{ s.padding_bottom }}px;
    --lib-pt-m: {{ s.padding_top_mobile }}px;
    --lib-pb-m: {{ s.padding_bottom_mobile }}px;
  "
>
  <div class="lib-video-hero__frame">
    <div class="lib-video-hero__media">
      {%- render 'lib-image',
        image: s.image,
        image_mobile: s.image_mobile,
        class: 'lib-video-hero__img',
        sizes: '100vw',
        eager: eager,
        placeholder: 'hero-apparel-1'
      -%}

      {%- for device in (1..2) -%}
        {%- liquid
          if device == 1
            assign video = s.video
            assign max_width = 1920
            assign device_name = desktop_device
            assign media = '(min-width: 750px)'
            if desktop_device == 'all'
              assign media = 'all'
            endif
          else
            assign video = s.video_mobile
            assign max_width = 1080
            assign device_name = 'mobile'
            assign media = '(max-width: 749px)'
          endif

          comment
            Shopify transcodes every upload into several MP4 sizes (and HLS); take the largest MP4
            that is still no wider than the device needs.
          endcomment
          assign source_url = ''
          assign source_width = 0
          if video != blank
            for source in video.sources
              if source.mime_type == 'video/mp4' and source.width <= max_width and source.width > source_width
                assign source_url = source.url
                assign source_width = source.width
              endif
            endfor
            if source_url == blank
              for source in video.sources
                if source.mime_type == 'video/mp4'
                  assign source_url = source.url
                  break
                endif
              endfor
            endif
          endif
        -%}
        {%- if source_url != blank -%}
          <video
            class="lib-video-hero__video"
            data-device="{{ device_name }}"
            data-media="{{ media }}"
            muted
            loop
            playsinline
            disablepictureinpicture
            preload="none"
            aria-hidden="true"
            tabindex="-1"
          >
            <source data-src="{{ source_url }}" type="video/mp4">
          </video>
        {%- endif -%}
      {%- endfor -%}
    </div>
    <div class="lib-video-hero__overlay" aria-hidden="true"></div>

    <div
      class="lib-video-hero__content"
      data-pos="{{ s.content_position }}"
      data-pos-m="{{ s.content_position_mobile }}"
      data-align-m="{{ s.text_alignment_mobile }}"
    >
      <div
        class="lib-video-hero__box"
        data-box="{{ s.content_box }}"
        data-align="{{ s.content_position | split: '-' | last }}"
        data-align-m="{{ s.text_alignment_mobile }}"
      >
        {%- if s.eyebrow != blank -%}
          <p class="lib-video-hero__eyebrow">{{ s.eyebrow | escape }}</p>
        {%- endif -%}

        {%- if s.heading != blank -%}
          <{{ heading_tag }} class="lib-video-hero__heading lib-video-hero__heading--{{ s.heading_size }}">
            {{- s.heading -}}
          </{{ heading_tag }}>
        {%- endif -%}

        {%- if s.text != blank -%}
          <div class="lib-video-hero__text">{{ s.text }}</div>
        {%- endif -%}

        {%- if section.blocks.size > 0 -%}
          <div class="lib-video-hero__actions">
            {%- for block in section.blocks -%}
              {%- liquid
                assign arrow = true
                if forloop.index > 1
                  assign arrow = false
                endif
              -%}
              <span class="lib-video-hero__action" {{ block.shopify_attributes }}>
                {%- render 'lib-button',
                  label: block.settings.label,
                  url: block.settings.url,
                  style: block.settings.style,
                  new_tab: block.settings.new_tab,
                  arrow: arrow
                -%}
              </span>
            {%- endfor -%}
          </div>
        {%- endif -%}
      </div>
    </div>

    {%- if has_video -%}
      <button
        type="button"
        class="lib-video-hero__toggle"
        data-state="paused"
        data-pause-label="{{ s.pause_label | escape }}"
        data-play-label="{{ s.play_label | escape }}"
        aria-label="{{ s.play_label | escape }}"
        hidden
      >
        <svg class="lib-video-hero__icon lib-video-hero__icon--pause" viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false">
          <path d="M6.5 4.5v11M13.5 4.5v11" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/>
        </svg>
        <svg class="lib-video-hero__icon lib-video-hero__icon--play" viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false">
          <path d="M6.5 4.2v11.6L16 10z" fill="currentColor"/>
        </svg>
      </button>
    {%- endif -%}
  </div>
</lib-video-hero>

{% stylesheet %}
  .lib-video-hero {
    display: block;
    background-color: var(--lib-bg);
    color: var(--lib-text);
    padding: var(--lib-pt-m) 0 var(--lib-pb-m);
  }
  .lib-video-hero--page { padding-inline: 1rem; }
  .lib-video-hero__frame {
    position: relative;
    display: grid;
    min-height: 480px;
    isolation: isolate;
    overflow: hidden;
    background: color-mix(in srgb, var(--lib-text) 12%, #1c1917);
  }
  .lib-video-hero--page .lib-video-hero__frame {
    max-width: 1200px;
    margin-inline: auto;
    border-radius: var(--lib-radius-frame);
  }

  /* Height: mobile first, then desktop. */
  .lib-video-hero[data-height-m='small'] .lib-video-hero__frame { min-height: 360px; }
  .lib-video-hero[data-height-m='medium'] .lib-video-hero__frame { min-height: 480px; }
  .lib-video-hero[data-height-m='large'] .lib-video-hero__frame { min-height: 600px; }
  .lib-video-hero[data-height-m='full'] .lib-video-hero__frame { min-height: 100vh; min-height: 100svh; }
  @media (min-width: 750px) {
    .lib-video-hero { padding-top: var(--lib-pt); padding-bottom: var(--lib-pb); }
    .lib-video-hero[data-height='small'] .lib-video-hero__frame { min-height: 440px; }
    .lib-video-hero[data-height='medium'] .lib-video-hero__frame { min-height: 600px; }
    .lib-video-hero[data-height='large'] .lib-video-hero__frame { min-height: 760px; }
    .lib-video-hero[data-height='full'] .lib-video-hero__frame { min-height: 100vh; min-height: 100svh; }
  }

  /* Visibility */
  @media (max-width: 749px) {
    .lib-video-hero[data-show='desktop'] { display: none; }
    .lib-video-hero__video[data-device='desktop'] { display: none; }
  }
  @media (min-width: 750px) {
    .lib-video-hero[data-show='mobile'] { display: none; }
    .lib-video-hero__video[data-device='mobile'] { display: none; }
  }

  /* Poster, video and overlay fill the frame; the video fades in over the poster once it plays. */
  .lib-video-hero__media,
  .lib-video-hero__overlay {
    position: absolute;
    inset: 0;
  }
  .lib-video-hero__media { z-index: -2; overflow: hidden; border-radius: inherit; }
  .lib-video-hero__img,
  .lib-video-hero__video {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  .lib-video-hero__img:is(svg) { fill: color-mix(in srgb, #fff 18%, transparent); background: #57534e; }
  .lib-video-hero__video { opacity: 0; transition: opacity 0.6s ease; }
  .lib-video-hero__video.is-ready { opacity: 1; }
  .lib-video-hero__overlay {
    z-index: -1;
    border-radius: inherit;
    background: var(--lib-overlay);
    opacity: var(--lib-overlay-o);
    pointer-events: none;
  }

  /* Content position: mobile uses data-pos-m (top / middle / bottom), desktop the 9-way data-pos. */
  .lib-video-hero__content {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    min-width: 0;
    padding: 2rem 1.25rem 5rem;
  }
  .lib-video-hero__content[data-pos-m='top'] { justify-content: flex-start; }
  .lib-video-hero__content[data-pos-m='middle'] { justify-content: center; }
  .lib-video-hero__content[data-pos-m='bottom'] { justify-content: flex-end; }
  .lib-video-hero__content[data-align-m='left'] { align-items: flex-start; }
  .lib-video-hero__content[data-align-m='center'] { align-items: center; }
  .lib-video-hero__content[data-align-m='right'] { align-items: flex-end; }
  @media (min-width: 750px) {
    .lib-video-hero__content { padding: clamp(2.5rem, 5vw, 4.5rem) clamp(2rem, 5vw, 4.5rem); }
    .lib-video-hero--full .lib-video-hero__content {
      padding-inline: max(clamp(2rem, 5vw, 4.5rem), calc((100% - 1200px) / 2 + 1rem));
    }
    .lib-video-hero__content[data-pos^='top'] { justify-content: flex-start; }
    .lib-video-hero__content[data-pos^='middle'] { justify-content: center; }
    .lib-video-hero__content[data-pos^='bottom'] { justify-content: flex-end; }
    .lib-video-hero__content[data-pos$='left'] { align-items: flex-start; }
    .lib-video-hero__content[data-pos$='center'] { align-items: center; }
    .lib-video-hero__content[data-pos$='right'] { align-items: flex-end; }
  }

  /* Content box: transparent, or a solid card with its own colors. */
  .lib-video-hero__box {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    width: 100%;
    max-width: var(--lib-content-w);
    text-align: left;
  }
  .lib-video-hero__box[data-box='solid'] {
    --lib-text: var(--lib-box-text);
    --lib-accent: var(--lib-box-text);
    --lib-accent-text: var(--lib-box);
    color: var(--lib-box-text);
    background: var(--lib-box);
    padding: clamp(1.5rem, 4vw, 2.75rem);
    border-radius: 4px;
    box-shadow: 0 24px 48px -28px rgb(0 0 0 / 0.45);
  }
  .lib-video-hero__box[data-align-m='center'] { align-items: center; text-align: center; }
  .lib-video-hero__box[data-align-m='right'] { align-items: flex-end; text-align: right; }
  @media (min-width: 750px) {
    .lib-video-hero__box { width: auto; }
    .lib-video-hero__box[data-align='left'] { align-items: flex-start; text-align: left; }
    .lib-video-hero__box[data-align='center'] { align-items: center; text-align: center; }
    .lib-video-hero__box[data-align='right'] { align-items: flex-end; text-align: right; }
  }

  .lib-video-hero__eyebrow {
    margin: 0 0 1rem;
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
  }
  .lib-video-hero__heading {
    margin: 0;
    font-size: clamp(2.25rem, 5vw, 4rem);
    line-height: 1.05;
    letter-spacing: -0.025em;
    text-wrap: balance;
    overflow-wrap: anywhere;
  }
  .lib-video-hero__heading--small { font-size: clamp(1.75rem, 3vw, 2.5rem); }
  .lib-video-hero__heading--medium { font-size: clamp(2rem, 4vw, 3.25rem); }
  .lib-video-hero__heading--xlarge { font-size: clamp(2.75rem, 7vw, 5.5rem); }
  .lib-video-hero__text {
    margin-top: 1.125rem;
    font-size: 1.0625rem;
    line-height: 1.6;
    opacity: 0.9;
  }
  .lib-video-hero__text > :first-child { margin-top: 0; }
  .lib-video-hero__text > :last-child { margin-bottom: 0; }
  .lib-video-hero__text a { color: inherit; }
  .lib-video-hero__action { display: contents; }
  .lib-video-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 1.75rem;
  }
  .lib-video-hero__box[data-align-m='center'] .lib-video-hero__actions { justify-content: center; }
  .lib-video-hero__box[data-align-m='right'] .lib-video-hero__actions { justify-content: flex-end; }
  @media (min-width: 750px) {
    .lib-video-hero__box[data-align='left'] .lib-video-hero__actions { justify-content: flex-start; }
    .lib-video-hero__box[data-align='center'] .lib-video-hero__actions { justify-content: center; }
    .lib-video-hero__box[data-align='right'] .lib-video-hero__actions { justify-content: flex-end; }
  }

  /* Pause / play: a 44px round button in the bottom corner, always above the overlay. */
  .lib-video-hero__toggle {
    position: absolute;
    right: 1rem;
    bottom: 1rem;
    z-index: 2;
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgb(20 18 16 / 0.6);
    color: #fff;
    cursor: pointer;
    transition: background-color 0.2s ease;
  }
  .lib-video-hero__toggle[hidden] { display: none; }
  .lib-video-hero__toggle:hover { background: rgb(20 18 16 / 0.8); }
  .lib-video-hero__toggle:focus-visible { outline: 2px solid #fff; outline-offset: 3px; box-shadow: 0 0 0 5px rgb(20 18 16 / 0.7); }
  .lib-video-hero__toggle[data-state='playing'] .lib-video-hero__icon--play,
  .lib-video-hero__toggle[data-state='paused'] .lib-video-hero__icon--pause { display: none; }
  @media (min-width: 750px) {
    .lib-video-hero__toggle { right: 1.5rem; bottom: 1.5rem; }
  }

  /* Motion: the copy rises once on load. */
  .lib-video-hero[data-animate] .lib-video-hero__box > * { animation: lib-video-hero-rise 0.8s cubic-bezier(0.2, 0.7, 0.2, 1) both; }
  .lib-video-hero[data-animate] .lib-video-hero__box > :nth-child(2) { animation-delay: 0.08s; }
  .lib-video-hero[data-animate] .lib-video-hero__box > :nth-child(3) { animation-delay: 0.16s; }
  .lib-video-hero[data-animate] .lib-video-hero__box > :nth-child(n + 4) { animation-delay: 0.24s; }
  @keyframes lib-video-hero-rise {
    from { opacity: 0; transform: translateY(14px); }
  }
  @media (prefers-reduced-motion: reduce) {
    .lib-video-hero[data-animate] .lib-video-hero__box > * { animation: none; }
    .lib-video-hero__video { transition: none; }
  }
{% endstylesheet %}

{% javascript %}
  if (!customElements.get('lib-video-hero')) {
    customElements.define(
      'lib-video-hero',
      class extends HTMLElement {
        connectedCallback() {
          this.videos = [...this.querySelectorAll('video[data-media]')];
          this.button = this.querySelector('.lib-video-hero__toggle');
          if (!this.videos.length || !this.button) return;
          this.queries = this.videos.map((video) => window.matchMedia(video.dataset.media));
          // Visitors who ask for reduced motion start paused; they can still press play.
          this.userPaused = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
          this.visible = false;
          this.cleanup = [];

          const listen = (target, type, fn) => {
            target.addEventListener(type, fn);
            this.cleanup.push(() => target.removeEventListener(type, fn));
          };
          const update = () => this.update();
          listen(this.button, 'click', () => {
            this.userPaused = !this.userPaused;
            this.update();
          });
          this.queries.forEach((query) => listen(query, 'change', update));
          listen(document, 'visibilitychange', update);
          this.videos.forEach((video) => listen(video, 'playing', () => video.classList.add('is-ready')));

          this.observer = new IntersectionObserver(
            ([entry]) => {
              this.visible = entry.isIntersecting;
              this.update();
            },
            {rootMargin: '200px 0px'},
          );
          this.observer.observe(this);
          this.button.hidden = false;
          this.update();
        }

        disconnectedCallback() {
          this.observer?.disconnect();
          (this.cleanup || []).forEach((fn) => fn());
          this.cleanup = [];
        }

        update() {
          const active = this.videos.find((video, i) => this.queries[i].matches);
          this.videos.forEach((video) => {
            if (video !== active) video.pause();
          });
          const shouldPlay = Boolean(active) && this.visible && !this.userPaused && !document.hidden;
          if (active && shouldPlay) {
            // The file is only requested the first time this video should play.
            const source = active.querySelector('source[data-src]');
            if (source) {
              source.src = source.dataset.src;
              source.removeAttribute('data-src');
              active.load();
            }
            const playing = active.play();
            if (playing) {
              playing.catch(() => {
                // Autoplay refused (data saver, browser policy): show the play button instead.
                this.userPaused = true;
                this.setButton(false);
              });
            }
          } else if (active) {
            active.pause();
          }
          this.button.hidden = !active;
          this.setButton(!this.userPaused);
        }

        setButton(playing) {
          this.button.dataset.state = playing ? 'playing' : 'paused';
          this.button.setAttribute('aria-label', playing ? this.button.dataset.pauseLabel : this.button.dataset.playLabel);
        }
      },
    );
  }
{% endjavascript %}

{% schema %}
{
  "name": "Lib · Video hero",
  "tag": "section",
  "class": "lib-section",
  "settings": [
    { "type": "header", "content": "Video" },
    { "type": "video", "id": "video", "label": "Desktop video", "info": "Upload to Shopify. Plays muted and looped; keep it short (10–30 s) and without important text." },
    { "type": "video", "id": "video_mobile", "label": "Mobile video", "info": "Optional. Plays below 750px; a portrait video works best. Without it the desktop video plays everywhere." },
    { "type": "image_picker", "id": "image", "label": "Desktop poster image", "info": "Shows while the video loads, and instead of it when motion is reduced or JavaScript is off." },
    { "type": "image_picker", "id": "image_mobile", "label": "Mobile poster image", "info": "Optional. Shown below 750px." },
    { "type": "text", "id": "pause_label", "label": "Pause button label", "info": "Read by screen readers.", "default": "Pause background video" },
    { "type": "text", "id": "play_label", "label": "Play button label", "info": "Read by screen readers.", "default": "Play background video" },
    { "type": "color", "id": "overlay_color", "label": "Overlay color", "default": "#1C1917" },
    { "type": "range", "id": "overlay_opacity", "label": "Overlay opacity", "min": 0, "max": 90, "step": 5, "unit": "%", "default": 35 },

    { "type": "header", "content": "Content" },
    { "type": "text", "id": "eyebrow", "label": "Eyebrow", "default": "Made in our studio" },
    { "type": "inline_richtext", "id": "heading", "label": "Heading", "default": "Shaped by hand, <em>fired with care</em>" },
    {
      "type": "select",
      "id": "heading_tag",
      "label": "Heading tag",
      "info": "Use H1 only when this is the page's main heading.",
      "options": [
        { "value": "h1", "label": "H1" },
        { "value": "h2", "label": "H2" },
        { "value": "h3", "label": "H3" },
        { "value": "p", "label": "Paragraph" }
      ],
      "default": "h2"
    },
    {
      "type": "select",
      "id": "heading_size",
      "label": "Heading size",
      "options": [
        { "value": "small", "label": "Small" },
        { "value": "medium", "label": "Medium" },
        { "value": "large", "label": "Large" },
        { "value": "xlarge", "label": "Extra large" }
      ],
      "default": "large"
    },
    { "type": "richtext", "id": "text", "label": "Text", "default": "<p>Small-batch stoneware for everyday tables, glazed in earthy tones and made to last.</p>" },

    { "type": "header", "content": "Layout" },
    {
      "type": "select",
      "id": "height",
      "label": "Height on desktop",
      "options": [
        { "value": "small", "label": "Small" },
        { "value": "medium", "label": "Medium" },
        { "value": "large", "label": "Large" },
        { "value": "full", "label": "Full screen" }
      ],
      "default": "large"
    },
    {
      "type": "select",
      "id": "height_mobile",
      "label": "Height on mobile",
      "options": [
        { "value": "small", "label": "Small" },
        { "value": "medium", "label": "Medium" },
        { "value": "large", "label": "Large" },
        { "value": "full", "label": "Full screen" }
      ],
      "default": "large"
    },
    {
      "type": "select",
      "id": "section_width",
      "label": "Width",
      "options": [
        { "value": "page", "label": "Page width" },
        { "value": "full", "label": "Full width" }
      ],
      "default": "full"
    },
    {
      "type": "range",
      "id": "corner_radius",
      "label": "Corner radius",
      "min": 0,
      "max": 40,
      "step": 2,
      "unit": "px",
      "default": 12,
      "visible_if": "{{ section.settings.section_width == 'page' }}"
    },
    {
      "type": "select",
      "id": "content_position",
      "label": "Content position on desktop",
      "info": "Text aligns to the same side: left, center or right.",
      "options": [
        { "value": "top-left", "label": "Top left" },
        { "value": "top-center", "label": "Top center" },
        { "value": "top-right", "label": "Top right" },
        { "value": "middle-left", "label": "Middle left" },
        { "value": "middle-center", "label": "Middle center" },
        { "value": "middle-right", "label": "Middle right" },
        { "value": "bottom-left", "label": "Bottom left" },
        { "value": "bottom-center", "label": "Bottom center" },
        { "value": "bottom-right", "label": "Bottom right" }
      ],
      "default": "middle-left"
    },
    {
      "type": "select",
      "id": "content_position_mobile",
      "label": "Content position on mobile",
      "options": [
        { "value": "top", "label": "Top" },
        { "value": "middle", "label": "Middle" },
        { "value": "bottom", "label": "Bottom" }
      ],
      "default": "bottom"
    },
    {
      "type": "select",
      "id": "text_alignment_mobile",
      "label": "Text alignment on mobile",
      "options": [
        { "value": "left", "label": "Left" },
        { "value": "center", "label": "Center" },
        { "value": "right", "label": "Right" }
      ],
      "default": "left"
    },
    { "type": "range", "id": "content_width", "label": "Content max width", "min": 320, "max": 960, "step": 20, "unit": "px", "default": 620 },
    {
      "type": "select",
      "id": "content_box",
      "label": "Content box",
      "options": [
        { "value": "none", "label": "None (text on video)" },
        { "value": "solid", "label": "Solid card" }
      ],
      "default": "none"
    },

    { "type": "header", "content": "Colors" },
    { "type": "color", "id": "color_bg", "label": "Background", "info": "Shows around the hero when it has padding or page width.", "default": "#F5EFE6" },
    { "type": "color", "id": "color_text", "label": "Text", "default": "#FFFFFF" },
    { "type": "color", "id": "color_accent", "label": "Solid button", "default": "#FFFFFF" },
    { "type": "color", "id": "color_accent_text", "label": "Text on solid button", "default": "#1C1917" },
    {
      "type": "color",
      "id": "color_box",
      "label": "Content box",
      "default": "#F5EFE6",
      "visible_if": "{{ section.settings.content_box == 'solid' }}"
    },
    {
      "type": "color",
      "id": "color_box_text",
      "label": "Text in content box",
      "info": "Also used for the solid button inside the box.",
      "default": "#2A211B",
      "visible_if": "{{ section.settings.content_box == 'solid' }}"
    },

    { "type": "header", "content": "Spacing and visibility" },
    { "type": "range", "id": "padding_top", "label": "Top padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 0 },
    { "type": "range", "id": "padding_bottom", "label": "Bottom padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 0 },
    { "type": "range", "id": "padding_top_mobile", "label": "Top padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 0 },
    { "type": "range", "id": "padding_bottom_mobile", "label": "Bottom padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 0 },
    {
      "type": "select",
      "id": "show_on",
      "label": "Show on",
      "options": [
        { "value": "all", "label": "All devices" },
        { "value": "desktop", "label": "Desktop only" },
        { "value": "mobile", "label": "Mobile only" }
      ],
      "default": "all"
    },
    { "type": "text", "id": "anchor_id", "label": "Anchor ID", "info": "Optional. Link to this section with #your-id." },

    { "type": "header", "content": "Motion" },
    { "type": "checkbox", "id": "animate", "label": "Animate text on load", "info": "Never when reduced motion is on.", "default": true }
  ],
  "blocks": [
    {
      "type": "button",
      "name": "Button",
      "limit": 2,
      "settings": [
        { "type": "text", "id": "label", "label": "Label", "default": "Shop new pieces" },
        { "type": "url", "id": "url", "label": "Link" },
        {
          "type": "select",
          "id": "style",
          "label": "Style",
          "options": [
            { "value": "primary", "label": "Solid" },
            { "value": "outline", "label": "Outline" },
            { "value": "text", "label": "Text link" }
          ],
          "default": "primary"
        },
        { "type": "checkbox", "id": "new_tab", "label": "Open link in a new tab", "default": false }
      ]
    }
  ],
  "presets": [
    {
      "name": "Lib · Video hero",
      "blocks": [
        { "type": "button", "settings": { "label": "Shop new pieces", "style": "primary" } },
        { "type": "button", "settings": { "label": "Our story", "style": "outline" } }
      ]
    }
  ]
}
{% endschema %}
```

### snippets/lib-image.liquid

```liquid
{%- comment -%}
  MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections
{%- endcomment -%}
{% doc %}
  Responsive image with optional art direction: a separate mobile image (below 750px),
  each honouring its own focal point from the theme editor. Falls back to a placeholder.

  @param {image} [image] - Desktop image (also used on mobile when no mobile image is set)
  @param {image} [image_mobile] - Mobile image, below 750px
  @param {string} [class] - Class for the img element
  @param {string} [sizes] - sizes attribute for the desktop image (default 100vw)
  @param {boolean} [eager] - Load immediately with high fetch priority (use for the first sections on a page)
  @param {string} [placeholder] - placeholder_svg_tag name when no image is set (default 'lifestyle-1')

  @example
  {% render 'lib-image', image: section.settings.image, image_mobile: section.settings.image_mobile, class: 'lib-hero__img', sizes: '(min-width: 990px) 50vw, 100vw', eager: true %}
{% enddoc %}

{%- liquid
  assign desktop = image
  if desktop == blank
    assign desktop = image_mobile
  endif
  assign img_sizes = sizes | default: '100vw'
  assign img_loading = 'lazy'
  assign img_priority = 'auto'
  if eager
    assign img_loading = 'eager'
    assign img_priority = 'high'
  endif
  assign art = false
  if image != blank and image_mobile != blank
    assign art = true
  endif
-%}

{%- if desktop != blank -%}
  <picture
    class="lib-picture{% if art %} lib-picture--art{% endif %}"
    {% if art %}
      style="--lib-pos-m: {{ image_mobile.presentation.focal_point | default: '50% 50%' }};"
    {% endif %}
  >
    {%- if art -%}
      <source
        media="(max-width: 749px)"
        srcset="
          {{ image_mobile | image_url: width: 375 }} 375w,
          {{ image_mobile | image_url: width: 750 }} 750w,
          {{ image_mobile | image_url: width: 1100 }} 1100w,
          {{ image_mobile | image_url: width: 1500 }} 1500w
        "
        sizes="100vw"
        width="{{ image_mobile.width }}"
        height="{{ image_mobile.height }}"
      >
    {%- endif -%}
    {{
      desktop
      | image_url: width: 2400
      | image_tag:
        class: class,
        loading: img_loading,
        fetchpriority: img_priority,
        sizes: img_sizes,
        widths: '600, 900, 1200, 1600, 2000, 2400'
    }}
  </picture>
{%- else -%}
  {{ placeholder | default: 'lifestyle-1' | placeholder_svg_tag: class }}
{%- endif -%}

{% stylesheet %}
  .lib-picture { display: contents; }
  @media (max-width: 749px) {
    /* image_tag sets the desktop focal point inline; the mobile image needs its own. */
    .lib-picture--art img { object-position: var(--lib-pos-m) !important; }
  }
{% endstylesheet %}
```

### snippets/lib-button.liquid

```liquid
{%- comment -%}
  MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections
{%- endcomment -%}
{% doc %}
  Animated call-to-action link. Light sweep on hover, arrow slides right.
  Colors come from the parent section's --lib-accent / --lib-accent-text / --lib-text vars.
  Inspired by Uiverse.io button patterns; rewritten for themes, no dependencies.

  @param {string} label - Button text
  @param {string} [url] - Link target; renders a disabled-looking span when blank
  @param {string} [style] - 'primary' (default), 'outline' or 'text'
  @param {boolean} [new_tab] - Open the link in a new tab
  @param {boolean} [arrow] - Show the trailing arrow (default true)

  @example
  {% render 'lib-button', label: section.settings.button_label, url: section.settings.button_url, style: 'outline' %}
{% enddoc %}

{%- liquid
  assign btn_style = style | default: 'primary'
  assign show_arrow = true
  if arrow == false
    assign show_arrow = false
  endif
-%}

{%- unless label == blank -%}
{%- capture inner -%}
  <span class="lib-btn__label">{{ label | escape }}</span>
  {%- if show_arrow -%}
    <svg class="lib-btn__arrow" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true" focusable="false">
      <path d="M3 8h9M8.5 4.5 12 8l-3.5 3.5" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
    </svg>
  {%- endif -%}
{%- endcapture -%}

{%- if url != blank -%}
  <a
    class="lib-btn lib-btn--{{ btn_style }}"
    href="{{ url }}"
    {% if new_tab %}
      target="_blank" rel="noopener"
    {% endif %}
  >
    {{- inner -}}
  </a>
{%- else -%}
  <span class="lib-btn lib-btn--{{ btn_style }}" aria-disabled="true">{{ inner }}</span>
{%- endif -%}
{%- endunless -%}

{% stylesheet %}
  .lib-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
    padding: 0.85em 1.5em;
    border-radius: var(--lib-radius, 999px);
    font: inherit;
    font-weight: 600;
    line-height: 1;
    text-decoration: none;
    overflow: hidden;
    isolation: isolate;
    transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
  }
  .lib-btn--primary {
    background: var(--lib-accent, #111);
    color: var(--lib-accent-text, #fff);
    box-shadow: 0 1px 2px rgb(0 0 0 / 0.12);
  }
  .lib-btn--outline {
    background: transparent;
    color: var(--lib-text, #111);
    box-shadow: inset 0 0 0 1.5px currentColor;
  }
  .lib-btn--text {
    padding-inline: 0;
    background: none;
    color: var(--lib-text, #111);
    text-decoration: underline;
    text-underline-offset: 0.3em;
    overflow: visible;
  }
  .lib-btn--text::before { display: none; }
  .lib-btn--text:hover { transform: none; box-shadow: none; }
  .lib-btn::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(110deg, transparent 30%, rgb(255 255 255 / 0.35) 50%, transparent 70%);
    transform: translateX(-120%);
    transition: transform 0.6s ease;
  }
  .lib-btn--outline::before {
    background: linear-gradient(110deg, transparent 30%, rgb(127 127 127 / 0.18) 50%, transparent 70%);
  }
  .lib-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 20px -8px rgb(0 0 0 / 0.35);
  }
  .lib-btn:hover::before { transform: translateX(120%); }
  .lib-btn__arrow { transition: transform 0.2s ease; }
  .lib-btn:hover .lib-btn__arrow { transform: translateX(3px); }
  .lib-btn:focus-visible {
    outline: 2px solid var(--lib-accent, #111);
    outline-offset: 3px;
  }
  .lib-btn[aria-disabled='true'] { pointer-events: none; }
  @media (prefers-reduced-motion: reduce) {
    .lib-btn, .lib-btn::before, .lib-btn__arrow { transition: none; }
    .lib-btn:hover { transform: none; }
  }
{% endstylesheet %}
```

## Lisans

MIT Lisansı, © 2026 Lintel. Kendi mağazanızda ya da müşteri işlerinde ücretsiz kullanabilir, değiştirebilir ve yayınlayabilirsiniz; her dosyanın başındaki lisans satırını koruyun.
