# Müşteri yorumları: ücretsiz Shopify bölümü

> Yıldız puanları, adlar ve baş harf avatarlarıyla müşteri yorumları; ızgara, masonry duvarı ya da ok düğmeli kaydırılabilir satır olarak.

Müşteri yorumları, müşteri alıntıları için ücretsiz bir Shopify bölümüdür: her kartta isteğe bağlı bir yıldız puanı, müşterinin adı ve konumu, bir fotoğraf ya da baş harfler ve isteğe bağlı bir ürün bağlantısı bulunur. Bunları ızgara, masonry duvarı ya da önceki ve sonraki düğmeli scroll-snap satırı olarak gösterin. Her Online Store 2.0 temasında uygulama olmadan çalışır.

- **Kategori:** Sosyal kanıt ve güven
- **Kullanıldığı yerler:** Ana sayfa, Ürün, Hakkımızda, Her sayfa
- **Okuduğu veri:** Yalnızca içerik
- **Boyut:** 3 dosyada 34 KB, küçük bir betikle
- **Lisans:** MIT, © 2026 Lintel
- **Sayfa:** https://lintelagency.com/tr/kaynaklar/shopify-bolumleri/musteri-yorumlari
- **Canlı demo:** https://lintelagency.com/resources/shopify-sections/demo/lib-testimonials.html
- **Eklenme tarihi:** 2026-10-02

## Ne işe yarar

- Puan özeti satırıyla ana sayfada müşteri yorumları duvarı
- Ürün sayfasında o ürünle ilgili, her biri ürüne bağlanan yorumlardan bir satır
- İş ortaklarından ve düzenli müşterilerden alıntılarla Hakkımızda ya da toptan satış sayfası

## Tema düzenleyici ayarları

Bölüm tema düzenleyicide “Lib · Testimonials” 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.

### Content

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `heading` | `inline_richtext` | Heading | Loved in homes like yours |  |
| `heading_tag` | `select` | Heading tag | h2 | `h1`, `h2`, `h3`, `p` |
| `heading_size` | `select` | Heading size | medium | `small`, `medium`, `large`, `xlarge` |
| `summary` | `text` | Rating summary | 4.8 average from 1,200 reviews |  |
| `text` | `richtext` | Intro | – |  |

### Button

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `button_label` | `text` | Button label | Read all reviews |  |
| `button_url` | `url` | Button link | – |  |
| `button_style` | `select` | Button style | outline | `primary`, `outline`, `text` |
| `button_new_tab` | `checkbox` | Open link in a new tab | `false` |  |

### Layout

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `layout` | `select` | Layout | masonry | `grid`, `masonry`, `scroll` |
| `columns` | `range` | Columns on desktop | `3` | 1–4, step 1 |
| `columns_mobile` | `select` | Columns on mobile | 1 | `1`, `2` |
| `card_style` | `select` | Card style | solid | `solid`, `border`, `none` |
| `card_radius` | `range` | Card corner radius | `16` | 0–32 px, step 2 |
| `quote_mark` | `checkbox` | Show a large quote mark | `true` |  |
| `section_width` | `select` | Width | page | `page`, `full` |
| `text_alignment` | `text_alignment` | Heading alignment on desktop | center |  |
| `text_alignment_mobile` | `select` | Heading alignment on mobile | left | `left`, `center`, `right` |

### Colors

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `color_bg` | `color` | Background | #F5F5F4 |  |
| `color_bg_gradient` | `color_background` | Background gradient | – |  |
| `color_text` | `color` | Text | #1C1917 |  |
| `color_card` | `color` | Card background | #FFFFFF |  |
| `color_border` | `color` | Card border | #E7E5E4 |  |
| `color_accent` | `color` | Accent (initials, quote mark, buttons) | #44403C |  |
| `color_accent_text` | `color` | Text on accent | #FAFAF9 |  |
| `color_star` | `color` | Stars | #D97706 |  |

### Spacing and visibility

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `padding_top` | `range` | Top padding on desktop | `80` | 0–200 px, step 4 |
| `padding_bottom` | `range` | Bottom padding on desktop | `80` | 0–200 px, step 4 |
| `padding_top_mobile` | `range` | Top padding on mobile | `48` | 0–160 px, step 4 |
| `padding_bottom_mobile` | `range` | Bottom padding on mobile | `48` | 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` | Fade cards in on scroll | `false` |  |

## Bloklar

Toplamda en fazla 12 blok.

### Testimonial (`quote`, en fazla 12)

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `quote` | `richtext` | Quote | `<p>The glaze is even nicer in person. It has become the mug everyone reaches for first.</p>` |  |
| `name` | `text` | Name | Jamie R. |  |
| `role` | `text` | Role or location | Portland, OR |  |
| `rating` | `select` | Star rating | 5 | `0`, `1`, `2`, `3`, `4`, `5` |
| `avatar` | `image_picker` | Photo | – |  |
| `product_label` | `text` | Product label | – |  |
| `product_url` | `url` | Product link | – |  |

## 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-testimonials.liquid` adında yeni bir dosya ekleyin, aşağıdaki kaynak koddan `sections/lib-testimonials.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 · Testimonials** 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-testimonials.liquid https://lintelagency.com/resources/shopify-sections/files/lib-testimonials.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-testimonials.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-testimonials.liquid](https://lintelagency.com/resources/shopify-sections/files/lib-testimonials.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

### Bu bölüm Google arama sonuçlarına yorum yıldızları ekler mi?

Hayır. Bilerek hiç yapılandırılmış veri üretmez. Tema düzenleyiciye yazılan alıntılar bir yorum sistemi değildir ve Google, bir işletmenin kendisi hakkında işaretlediği kendi lehine yorumlar için yıldız göstermez. Zengin sonuçlara ihtiyacınız varsa bir yorum uygulaması kullanın.

### Alıntılar nereden gelir?

Onları blok olarak siz yazarsınız, en fazla 12 tane. Bölüm bir yorum uygulamasına bağlanmaz; puan özeti satırı da kendi yazdığınız düz metindir.

### Müşterinin fotoğrafı yoksa ne olur?

Kart, vurgu renklerini kullanarak adın baş harflerini içeren bir daire gösterir. Bir fotoğraf eklediğinizde onun yerini alır.

### Kayan satır telefonlarda ve klavyeyle nasıl çalışır?

Kartlar kaydırıldığında yerine oturur. Satır odaklanabilir bir bölgedir; ok tuşları onu kaydırır. Önceki ve sonraki düğmeleri birer kart ilerletir ve iki uçta devre dışı kalır. Düğmeler yalnızca sığandan fazla kart olduğunda görünür.

## Kaynak kod

### sections/lib-testimonials.liquid

```liquid
{%- comment -%}
  MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections
{%- endcomment -%}
{%- comment -%}
  Testimonials: quote cards with optional star rating, avatar (or initials) and product link.
  Three layouts: grid, masonry (CSS columns) or a horizontal scroll row with scroll snap and
  prev/next buttons (small custom element; the row still scrolls by touch, trackpad and keyboard without it).
  No review structured data on purpose: Google does not show self-serving reviews a store publishes about itself.
  Depends on: snippets/lib-button.liquid, snippets/lib-image.liquid
{%- endcomment -%}

{%- liquid
  assign s = section.settings
  assign heading_tag = s.heading_tag | default: 'h2'
  assign track_id = 'LibTestimonials-' | append: section.id
-%}

<div
  class="lib-testimonials lib-testimonials--{{ s.section_width }}"
  {% if s.anchor_id != blank %}
    id="{{ s.anchor_id | handleize }}"
  {% endif %}
  data-show="{{ s.show_on }}"
  data-layout="{{ s.layout }}"
  data-card="{{ s.card_style }}"
  {% if s.quote_mark %}
    data-quote-mark
  {% endif %}
  {% if s.animate %}
    data-animate
  {% endif %}
  style="
    --lib-bg: {{ s.color_bg }};
    {% if s.color_bg_gradient != blank %}--lib-bg-image: {{ s.color_bg_gradient }};{% endif %}
    --lib-text: {{ s.color_text }};
    --lib-card: {{ s.color_card }};
    --lib-border: {{ s.color_border }};
    --lib-accent: {{ s.color_accent }};
    --lib-accent-text: {{ s.color_accent_text }};
    --lib-star: {{ s.color_star }};
    --lib-cols: {{ s.columns }};
    --lib-cols-m: {{ s.columns_mobile }};
    --lib-radius-card: {{ s.card_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-testimonials__inner">
    {%- if s.heading != blank or s.text != blank or s.summary != blank -%}
      <header class="lib-testimonials__header" data-align="{{ s.text_alignment }}" data-align-m="{{ s.text_alignment_mobile }}">
        {%- if s.heading != blank -%}
          <{{ heading_tag }} class="lib-testimonials__heading lib-testimonials__heading--{{ s.heading_size }}">
            {{- s.heading -}}
          </{{ heading_tag }}>
        {%- endif -%}
        {%- if s.summary != blank -%}
          <p class="lib-testimonials__summary">
            <svg class="lib-testimonials__summary-star" viewBox="0 0 20 20" width="18" height="18" aria-hidden="true" focusable="false"><path d="M10 1.5l2.6 5.3 5.9.9-4.25 4.1 1 5.85L10 14.9l-5.25 2.75 1-5.85L1.5 7.7l5.9-.9z" fill="currentColor"/></svg>
            <span>{{ s.summary | escape }}</span>
          </p>
        {%- endif -%}
        {%- if s.text != blank -%}
          <div class="lib-testimonials__intro">{{ s.text }}</div>
        {%- endif -%}
      </header>
    {%- endif -%}

    <lib-testimonials-scroller class="lib-testimonials__body">
      <div
        class="lib-testimonials__list"
        id="{{ track_id }}"
        {% if s.layout == 'scroll' %}
          role="region" aria-label="{{ s.heading | strip_html | default: 'Testimonials' | escape }}" tabindex="0" data-track
        {% endif %}
      >
        {%- for block in section.blocks -%}
          {%- liquid
            assign b = block.settings
            assign rating = b.rating | plus: 0
            assign initials = ''
            assign name_parts = b.name | strip | split: ' '
            if name_parts.size > 0
              assign initials = name_parts.first | slice: 0 | upcase
              if name_parts.size > 1
                assign last_initial = name_parts.last | slice: 0 | upcase
                assign initials = initials | append: last_initial
              endif
            endif
          -%}
          <figure class="lib-testimonial" {{ block.shopify_attributes }}>
            {%- if rating > 0 -%}
              <div class="lib-testimonial__stars" role="img" aria-label="Rated {{ rating }} out of 5">
                {%- for i in (1..5) -%}
                  <svg class="lib-testimonial__star{% if i > rating %} lib-testimonial__star--off{% endif %}" viewBox="0 0 20 20" width="18" height="18" aria-hidden="true" focusable="false"><path d="M10 1.5l2.6 5.3 5.9.9-4.25 4.1 1 5.85L10 14.9l-5.25 2.75 1-5.85L1.5 7.7l5.9-.9z" fill="currentColor"/></svg>
                {%- endfor -%}
              </div>
            {%- endif -%}

            <blockquote class="lib-testimonial__quote">{{ b.quote }}</blockquote>

            <figcaption class="lib-testimonial__author">
              <span class="lib-testimonial__avatar" aria-hidden="true">
                {%- if b.avatar != blank -%}
                  {%- render 'lib-image', image: b.avatar, class: 'lib-testimonial__avatar-img', sizes: '48px' -%}
                {%- else -%}
                  {{- initials -}}
                {%- endif -%}
              </span>
              <span class="lib-testimonial__meta">
                {%- if b.name != blank -%}
                  <span class="lib-testimonial__name">{{ b.name | escape }}</span>
                {%- endif -%}
                {%- if b.role != blank -%}
                  <span class="lib-testimonial__role">{{ b.role | escape }}</span>
                {%- endif -%}
                {%- if b.product_label != blank -%}
                  {%- if b.product_url != blank -%}
                    <a class="lib-testimonial__product" href="{{ b.product_url }}">{{ b.product_label | escape }}<span aria-hidden="true"> →</span></a>
                  {%- else -%}
                    <span class="lib-testimonial__product">{{ b.product_label | escape }}</span>
                  {%- endif -%}
                {%- endif -%}
              </span>
            </figcaption>
          </figure>
        {%- endfor -%}
      </div>

      {%- if s.layout == 'scroll' and section.blocks.size > 1 -%}
        <div class="lib-testimonials__nav">
          <button type="button" class="lib-testimonials__arrow" data-dir="-1" aria-controls="{{ track_id }}" aria-label="Previous testimonials">
            <svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true" focusable="false"><path d="M10 3.5 5.5 8l4.5 4.5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
          </button>
          <button type="button" class="lib-testimonials__arrow" data-dir="1" aria-controls="{{ track_id }}" aria-label="Next testimonials">
            <svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true" focusable="false"><path d="M6 3.5 10.5 8 6 12.5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
          </button>
        </div>
      {%- endif -%}
    </lib-testimonials-scroller>

    {%- if s.button_label != blank -%}
      <div class="lib-testimonials__actions" data-align="{{ s.text_alignment }}" data-align-m="{{ s.text_alignment_mobile }}">
        {%- render 'lib-button', label: s.button_label, url: s.button_url, style: s.button_style, new_tab: s.button_new_tab -%}
      </div>
    {%- endif -%}
  </div>
</div>

{% stylesheet %}
  .lib-testimonials {
    background-color: var(--lib-bg);
    background-image: var(--lib-bg-image, none);
    color: var(--lib-text);
    padding: var(--lib-pt) 1rem var(--lib-pb);
  }
  .lib-testimonials__inner { max-width: 1200px; margin: 0 auto; }
  .lib-testimonials--full .lib-testimonials__inner { max-width: none; }
  @media (max-width: 749px) {
    .lib-testimonials { padding-top: var(--lib-pt-m); padding-bottom: var(--lib-pb-m); }
    .lib-testimonials[data-show='desktop'] { display: none; }
  }
  @media (min-width: 750px) {
    .lib-testimonials[data-show='mobile'] { display: none; }
  }

  /* Header: alignment for desktop, then mobile. */
  .lib-testimonials__header { display: flex; flex-direction: column; align-items: center; max-width: 42rem; margin: 0 auto 3rem; text-align: center; }
  .lib-testimonials__header[data-align='left'] { align-items: flex-start; margin-left: 0; text-align: left; }
  .lib-testimonials__header[data-align='right'] { align-items: flex-end; margin-right: 0; text-align: right; }
  @media (max-width: 749px) {
    .lib-testimonials__header { margin-bottom: 2rem; }
    .lib-testimonials__header[data-align-m='left'] { align-items: flex-start; margin-inline: 0 auto; text-align: left; }
    .lib-testimonials__header[data-align-m='center'] { align-items: center; margin-inline: auto; text-align: center; }
    .lib-testimonials__header[data-align-m='right'] { align-items: flex-end; margin-inline: auto 0; text-align: right; }
  }
  .lib-testimonials__heading {
    margin: 0;
    font-size: clamp(1.75rem, 3.5vw, 2.75rem);
    line-height: 1.1;
    letter-spacing: -0.02em;
    text-wrap: balance;
  }
  .lib-testimonials__heading--small { font-size: clamp(1.4rem, 2.5vw, 2rem); }
  .lib-testimonials__heading--large { font-size: clamp(2rem, 4.5vw, 3.5rem); }
  .lib-testimonials__heading--xlarge { font-size: clamp(2.5rem, 6vw, 4.5rem); }
  .lib-testimonials__summary {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin: 1rem 0 0;
    font-size: 0.95rem;
    font-weight: 600;
  }
  .lib-testimonials__summary-star { flex-shrink: 0; color: var(--lib-star); }
  .lib-testimonials__intro { margin-top: 1rem; font-size: 1.05rem; line-height: 1.6; opacity: 0.72; }
  .lib-testimonials__intro > * { margin: 0; }

  /* Layouts */
  .lib-testimonials__list { --lib-gap: 1rem; }
  @media (min-width: 750px) {
    .lib-testimonials__list { --lib-gap: 1.25rem; }
  }
  .lib-testimonials[data-layout='grid'] .lib-testimonials__list {
    display: grid;
    gap: var(--lib-gap);
    grid-template-columns: repeat(var(--lib-cols-m), minmax(0, 1fr));
  }
  .lib-testimonials[data-layout='masonry'] .lib-testimonials__list {
    column-count: var(--lib-cols-m);
    column-gap: var(--lib-gap);
  }
  .lib-testimonials[data-layout='masonry'] .lib-testimonial {
    break-inside: avoid;
    margin-bottom: var(--lib-gap);
  }
  @media (min-width: 750px) {
    .lib-testimonials[data-layout='grid'] .lib-testimonials__list { grid-template-columns: repeat(min(var(--lib-cols), 2), minmax(0, 1fr)); }
    .lib-testimonials[data-layout='masonry'] .lib-testimonials__list { column-count: min(var(--lib-cols), 2); }
  }
  @media (min-width: 990px) {
    .lib-testimonials[data-layout='grid'] .lib-testimonials__list { grid-template-columns: repeat(var(--lib-cols), minmax(0, 1fr)); }
    .lib-testimonials[data-layout='masonry'] .lib-testimonials__list { column-count: var(--lib-cols); }
  }

  /* Scroll row: cards snap; a slice of the next card shows that the row continues. */
  .lib-testimonials[data-layout='scroll'] .lib-testimonials__list {
    --lib-per-view: calc(var(--lib-cols-m) * 1);
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: calc((100% - (var(--lib-per-view) - 1) * var(--lib-gap)) / var(--lib-per-view) - 2.5rem);
    gap: var(--lib-gap);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: 0;
    scrollbar-width: none;
    padding-block: 2px;
  }
  .lib-testimonials[data-layout='scroll'] .lib-testimonials__list::-webkit-scrollbar { display: none; }
  .lib-testimonials[data-layout='scroll'] .lib-testimonial { scroll-snap-align: start; }
  @media (min-width: 750px) {
    .lib-testimonials[data-layout='scroll'] .lib-testimonials__list { --lib-per-view: min(var(--lib-cols), 2); }
  }
  @media (min-width: 990px) {
    .lib-testimonials[data-layout='scroll'] .lib-testimonials__list {
      --lib-per-view: var(--lib-cols);
      grid-auto-columns: calc((100% - (var(--lib-per-view) - 1) * var(--lib-gap)) / var(--lib-per-view));
    }
  }
  .lib-testimonials__list:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 4px; border-radius: 4px; }

  .lib-testimonials__nav { display: none; justify-content: flex-end; gap: 0.5rem; margin-top: 1.25rem; }
  .lib-testimonials__body[data-overflow] .lib-testimonials__nav { display: flex; }
  .lib-testimonials__arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    border: 1px solid color-mix(in srgb, var(--lib-text) 22%, transparent);
    border-radius: 50%;
    background: transparent;
    color: var(--lib-text);
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease, opacity 0.2s ease;
  }
  .lib-testimonials__arrow:hover:not(:disabled) { background: var(--lib-accent); border-color: var(--lib-accent); color: var(--lib-accent-text); }
  .lib-testimonials__arrow:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 2px; }
  .lib-testimonials__arrow:disabled { opacity: 0.35; cursor: default; }

  /* Card */
  .lib-testimonial {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 1.1rem;
    margin: 0;
    padding: clamp(1.25rem, 2.5vw, 1.75rem);
    border-radius: var(--lib-radius-card);
    min-width: 0;
  }
  .lib-testimonials[data-card='solid'] .lib-testimonial { background: var(--lib-card); }
  .lib-testimonials[data-card='border'] .lib-testimonial { box-shadow: inset 0 0 0 1px var(--lib-border); }
  .lib-testimonials[data-card='none'] .lib-testimonial { padding-inline: 0; }
  .lib-testimonials[data-quote-mark] .lib-testimonial::before {
    content: '\201C';
    position: absolute;
    inset-block-start: 0.6rem;
    inset-inline-end: 1.25rem;
    font-family: Georgia, 'Times New Roman', serif;
    font-size: 4.5rem;
    line-height: 1;
    color: var(--lib-accent);
    opacity: 0.18;
    pointer-events: none;
  }

  .lib-testimonial__stars { display: flex; gap: 2px; color: var(--lib-star); }
  .lib-testimonial__star { display: block; }
  .lib-testimonial__star--off { color: color-mix(in srgb, var(--lib-text) 18%, transparent); }

  .lib-testimonial__quote { margin: 0; font-size: 1.05rem; line-height: 1.6; }
  .lib-testimonial__quote > :first-child { margin-top: 0; }
  .lib-testimonial__quote > :last-child { margin-bottom: 0; }

  .lib-testimonial__author { display: flex; align-items: center; gap: 0.75rem; margin-top: auto; }
  .lib-testimonials[data-layout='masonry'] .lib-testimonial__author { margin-top: 0; }
  .lib-testimonial__avatar {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    overflow: hidden;
    background: var(--lib-accent);
    color: var(--lib-accent-text);
    font-size: 0.9rem;
    font-weight: 600;
    letter-spacing: 0.02em;
  }
  .lib-testimonial__avatar-img { display: block; width: 100%; height: 100%; object-fit: cover; }
  .lib-testimonial__meta { display: flex; flex-direction: column; min-width: 0; gap: 0.1rem; font-size: 0.9rem; line-height: 1.35; }
  .lib-testimonial__name { font-weight: 600; }
  .lib-testimonial__role { opacity: 0.65; }
  .lib-testimonial__product { color: inherit; font-size: 0.85rem; opacity: 0.8; text-underline-offset: 0.2em; }
  a.lib-testimonial__product:hover { opacity: 1; }
  a.lib-testimonial__product:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 2px; border-radius: 2px; }

  .lib-testimonials__actions { display: flex; justify-content: center; margin-top: 2.5rem; }
  .lib-testimonials__actions[data-align='left'] { justify-content: flex-start; }
  .lib-testimonials__actions[data-align='right'] { justify-content: flex-end; }
  @media (max-width: 749px) {
    .lib-testimonials__actions { margin-top: 2rem; }
    .lib-testimonials__actions[data-align-m='left'] { justify-content: flex-start; }
    .lib-testimonials__actions[data-align-m='center'] { justify-content: center; }
    .lib-testimonials__actions[data-align-m='right'] { justify-content: flex-end; }
  }

  /* Motion: cards fade up as they scroll into view, where the browser supports scroll-driven animations. */
  @supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
      .lib-testimonials[data-animate]:not([data-layout='scroll']) .lib-testimonial {
        animation: lib-testimonials-rise linear both;
        animation-timeline: view();
        animation-range: entry 0% entry 60%;
      }
    }
  }
  @keyframes lib-testimonials-rise {
    from { opacity: 0; transform: translateY(24px); }
  }
  @media (prefers-reduced-motion: reduce) {
    .lib-testimonials__arrow { transition: none; }
  }
{% endstylesheet %}

{% javascript %}
  if (!customElements.get('lib-testimonials-scroller')) {
    customElements.define(
      'lib-testimonials-scroller',
      class extends HTMLElement {
        connectedCallback() {
          this.track = this.querySelector('[data-track]');
          this.buttons = this.querySelectorAll('.lib-testimonials__arrow');
          if (!this.track || !this.buttons.length || this.observer) return;
          this.onScroll = () => this.update();
          this.track.addEventListener('scroll', this.onScroll, { passive: true });
          this.buttons.forEach((button) => button.addEventListener('click', () => this.step(Number(button.dataset.dir))));
          this.observer = new ResizeObserver(() => this.update());
          this.observer.observe(this.track);
          this.update();
        }

        disconnectedCallback() {
          this.observer?.disconnect();
          this.observer = null;
          this.track?.removeEventListener('scroll', this.onScroll);
        }

        step(dir) {
          const card = this.track.firstElementChild;
          const gap = parseFloat(getComputedStyle(this.track).columnGap) || 0;
          const width = card ? card.getBoundingClientRect().width + gap : this.track.clientWidth;
          const rtl = getComputedStyle(this.track).direction === 'rtl';
          const smooth = !matchMedia('(prefers-reduced-motion: reduce)').matches;
          this.track.scrollBy({ left: dir * width * (rtl ? -1 : 1), behavior: smooth ? 'smooth' : 'auto' });
        }

        update() {
          const max = this.track.scrollWidth - this.track.clientWidth;
          const x = Math.abs(this.track.scrollLeft);
          this.toggleAttribute('data-overflow', max > 2);
          const [prev, next] = this.buttons;
          if (prev) prev.disabled = x <= 2;
          if (next) next.disabled = x >= max - 2;
        }
      }
    );
  }
{% endjavascript %}

{% schema %}
{
  "name": "Lib · Testimonials",
  "tag": "section",
  "class": "lib-section",
  "max_blocks": 12,
  "settings": [
    { "type": "header", "content": "Content" },
    { "type": "inline_richtext", "id": "heading", "label": "Heading", "default": "Loved in homes like yours" },
    {
      "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": "medium"
    },
    {
      "type": "text",
      "id": "summary",
      "label": "Rating summary",
      "info": "Optional line under the heading. Use your store's real figures; the default is sample text.",
      "default": "4.8 average from 1,200 reviews"
    },
    { "type": "richtext", "id": "text", "label": "Intro" },

    { "type": "header", "content": "Button" },
    { "type": "text", "id": "button_label", "label": "Button label", "default": "Read all reviews" },
    { "type": "url", "id": "button_url", "label": "Button link" },
    {
      "type": "select",
      "id": "button_style",
      "label": "Button style",
      "options": [
        { "value": "primary", "label": "Solid" },
        { "value": "outline", "label": "Outline" },
        { "value": "text", "label": "Text link" }
      ],
      "default": "outline"
    },
    { "type": "checkbox", "id": "button_new_tab", "label": "Open link in a new tab", "default": false },

    { "type": "header", "content": "Layout" },
    {
      "type": "select",
      "id": "layout",
      "label": "Layout",
      "options": [
        { "value": "grid", "label": "Grid" },
        { "value": "masonry", "label": "Masonry" },
        { "value": "scroll", "label": "Scrolling row" }
      ],
      "default": "masonry"
    },
    { "type": "range", "id": "columns", "label": "Columns on desktop", "info": "In the scrolling row, the number of cards in view.", "min": 1, "max": 4, "step": 1, "default": 3 },
    {
      "type": "select",
      "id": "columns_mobile",
      "label": "Columns on mobile",
      "options": [
        { "value": "1", "label": "1" },
        { "value": "2", "label": "2" }
      ],
      "default": "1"
    },
    {
      "type": "select",
      "id": "card_style",
      "label": "Card style",
      "options": [
        { "value": "solid", "label": "Filled" },
        { "value": "border", "label": "Outline" },
        { "value": "none", "label": "No card" }
      ],
      "default": "solid"
    },
    { "type": "range", "id": "card_radius", "label": "Card corner radius", "min": 0, "max": 32, "step": 2, "unit": "px", "default": 16 },
    { "type": "checkbox", "id": "quote_mark", "label": "Show a large quote mark", "default": true },
    {
      "type": "select",
      "id": "section_width",
      "label": "Width",
      "options": [
        { "value": "page", "label": "Page width" },
        { "value": "full", "label": "Full width" }
      ],
      "default": "page"
    },
    { "type": "text_alignment", "id": "text_alignment", "label": "Heading alignment on desktop", "default": "center" },
    {
      "type": "select",
      "id": "text_alignment_mobile",
      "label": "Heading alignment on mobile",
      "options": [
        { "value": "left", "label": "Left" },
        { "value": "center", "label": "Center" },
        { "value": "right", "label": "Right" }
      ],
      "default": "left"
    },

    { "type": "header", "content": "Colors" },
    { "type": "color", "id": "color_bg", "label": "Background", "default": "#F5F5F4" },
    { "type": "color_background", "id": "color_bg_gradient", "label": "Background gradient", "info": "Optional. Covers the background color." },
    { "type": "color", "id": "color_text", "label": "Text", "default": "#1C1917" },
    { "type": "color", "id": "color_card", "label": "Card background", "default": "#FFFFFF", "visible_if": "{{ section.settings.card_style == 'solid' }}" },
    { "type": "color", "id": "color_border", "label": "Card border", "default": "#E7E5E4", "visible_if": "{{ section.settings.card_style == 'border' }}" },
    { "type": "color", "id": "color_accent", "label": "Accent (initials, quote mark, buttons)", "default": "#44403C" },
    { "type": "color", "id": "color_accent_text", "label": "Text on accent", "default": "#FAFAF9" },
    { "type": "color", "id": "color_star", "label": "Stars", "default": "#D97706" },

    { "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": 80 },
    { "type": "range", "id": "padding_bottom", "label": "Bottom padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 80 },
    { "type": "range", "id": "padding_top_mobile", "label": "Top padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 48 },
    { "type": "range", "id": "padding_bottom_mobile", "label": "Bottom padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 48 },
    {
      "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": "Fade cards in on scroll", "info": "Grid and masonry layouts, in browsers that support scroll-driven animations.", "default": false }
  ],
  "blocks": [
    {
      "type": "quote",
      "name": "Testimonial",
      "limit": 12,
      "settings": [
        { "type": "richtext", "id": "quote", "label": "Quote", "default": "<p>The glaze is even nicer in person. It has become the mug everyone reaches for first.</p>" },
        { "type": "text", "id": "name", "label": "Name", "default": "Jamie R." },
        { "type": "text", "id": "role", "label": "Role or location", "default": "Portland, OR" },
        {
          "type": "select",
          "id": "rating",
          "label": "Star rating",
          "options": [
            { "value": "0", "label": "No stars" },
            { "value": "1", "label": "1 star" },
            { "value": "2", "label": "2 stars" },
            { "value": "3", "label": "3 stars" },
            { "value": "4", "label": "4 stars" },
            { "value": "5", "label": "5 stars" }
          ],
          "default": "5"
        },
        { "type": "image_picker", "id": "avatar", "label": "Photo", "info": "Optional. Without a photo, the initials of the name are shown." },
        { "type": "text", "id": "product_label", "label": "Product label", "info": "Optional, for example the product they bought." },
        { "type": "url", "id": "product_url", "label": "Product link", "visible_if": "{{ block.settings.product_label != blank }}" }
      ]
    }
  ],
  "presets": [
    {
      "name": "Lib · Testimonials",
      "blocks": [
        {
          "type": "quote",
          "settings": {
            "quote": "<p>The glaze is even nicer in person. It has become the mug everyone reaches for first.</p>",
            "name": "Jamie Rowe",
            "role": "Portland, OR",
            "rating": "5",
            "product_label": "Speckled stoneware mug"
          }
        },
        {
          "type": "quote",
          "settings": {
            "quote": "<p>I ordered the linen throw on a Monday and it was on my sofa by Thursday. Soft from the first wash, and it has only got better.</p>",
            "name": "Priya Nair",
            "role": "Austin, TX",
            "rating": "5",
            "product_label": "Washed linen throw"
          }
        },
        {
          "type": "quote",
          "settings": {
            "quote": "<p>Lovely candles with a clean, slow burn.</p>",
            "name": "Tom",
            "role": "Repeat customer",
            "rating": "4"
          }
        },
        {
          "type": "quote",
          "settings": {
            "quote": "<p>One of the bowls arrived chipped. I sent a photo and a replacement was sent the same day, no questions asked. That is why I keep coming back.</p>",
            "name": "Elena Martín",
            "role": "Chicago, IL",
            "rating": "5"
          }
        },
        {
          "type": "quote",
          "settings": {
            "quote": "<p>Heavier and better made than I expected for the price. The colors match the photos.</p>",
            "name": "Marcus Lee",
            "role": "Seattle, WA",
            "rating": "5",
            "product_label": "Oak serving board"
          }
        },
        {
          "type": "quote",
          "settings": {
            "quote": "<p>Gift-wrapped beautifully. My sister loved her vase.</p>",
            "name": "Hannah Brooks",
            "role": "Denver, CO",
            "rating": "5"
          }
        }
      ]
    }
  ]
}
{% 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.
