# Beden tablosu: ücretsiz Shopify bölümü

> Yan çekmecede, açılır pencerede ya da sayfada beden tablosu; cm / inç geçişi, ölçü alma notları ve görseli. Tabloyu yazın ya da bir sayfa seçin.

Bu ücretsiz Shopify beden tablosu bölümü, beden tablonuzu bir "Beden tablosu" bağlantısının ya da düğmesinin arkasında, yan çekmecede veya ortada açılan bir pencerede ya da doğrudan sayfada gösterir. Tabloyu tema düzenleyicide yazarsınız (her satır ayrı bir satıra, hücreler | ile ayrılır) ya da bir sayfayı seçersiniz; müşteriler santimetre ile inç arasında geçiş yapabilir. Ölçü alma notları ve isteğe bağlı bir ölçü görseli ekler, Online Store 2.0 temalarında uygulama olmadan çalışır.

- **Kategori:** Ürün sayfası
- **Kullanıldığı yerler:** Ürün, Koleksiyon, Her sayfa
- **Okuduğu veri:** Yalnızca içerik ya da bir sayfanın içeriği
- **Boyut:** 3 dosyada 35 KB, küçük bir betikle
- **Lisans:** MIT, © 2026 Lintel
- **Sayfa:** https://lintelagency.com/tr/kaynaklar/shopify-bolumleri/beden-tablosu
- **Canlı demo:** https://lintelagency.com/resources/shopify-sections/demo/lib-size-chart.html
- **Eklenme tarihi:** 2026-11-02

## Ne işe yarar

- Giyim, ayakkabı ya da yüzük ürün şablonlarında satın alma alanının altında bir "Beden tablosu" bağlantısı
- Ayrı bir Beden rehberi sayfasında, ölçü alma fotoğrafıyla birlikte sayfada gösterilen tam beden tablosu
- Bir sayfada tutulan ve birkaç ürün şablonunda yeniden kullanılan tek bir beden tablosu

## Tema düzenleyici ayarları

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

### Display

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `display` | `select` | Show the chart | drawer | `drawer`, `modal`, `inline` |
| `trigger_label` | `text` | Button label | Size chart |  |
| `trigger_style` | `select` | Button style | link | `link`, `primary`, `outline` |
| `close_label` | `text` | Close button (screen readers) | Close size chart |  |

### Heading

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `heading` | `inline_richtext` | Heading | Size chart |  |
| `heading_tag` | `select` | Heading tag | h2 | `h1`, `h2`, `h3`, `p` |
| `heading_size` | `select` | Heading size | medium | `small`, `medium`, `large`, `xlarge` |
| `text` | `richtext` | Intro text | – |  |

### Table

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `source` | `select` | Table source | table | `table`, `page` |
| `table` | `textarea` | Table | Size \| Chest \| Waist \| Length XS \| 82-86 \| 64-68 \| 66 S \| 86-90 \| 68-72 \| 68 M \| 90-96 \| 72-78 \| 70 L \| 96-102 \| 78-84 \| 72 XL \| 102-108 \| 84-90 \| 74 |  |
| `page` | `page` | Page | – |  |
| `caption` | `text` | Table caption | Body measurements |  |
| `scroll_label` | `text` | Table area name (screen readers) | Size chart table, scrolls sideways on small screens |  |
| `unit_toggle` | `checkbox` | Show a cm / in switch | `true` |  |
| `base_unit` | `select` | Values are typed in | cm | `cm`, `in` |
| `label_cm` | `text` | Centimetres label | cm |  |
| `label_in` | `text` | Inches label | in |  |
| `units_label` | `text` | Switch name (screen readers) | Units |  |

### How to measure

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `notes` | `richtext` | Measuring notes | `<p><strong>Chest:</strong> measure around the fullest part, keeping the tape level.</p><p><strong>Waist:</strong> measure around your natural waistline.</p><p><strong>Length:</strong> from the highest point of the shoulder to the hem.</p>` |  |
| `image` | `image_picker` | Desktop image | – |  |
| `image_mobile` | `image_picker` | Mobile image | – |  |

### Layout

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `section_width` | `select` | Width | page | `page`, `full` |
| `text_alignment` | `text_alignment` | Heading and button alignment on desktop | left |  |
| `text_alignment_mobile` | `select` | Heading and button alignment on mobile | left | `left`, `center`, `right` |

### Colors

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `color_bg` | `color` | Background | #FFFFFF |  |
| `color_bg_gradient` | `color_background` | Background gradient | – |  |
| `color_text` | `color` | Text | #231F1B |  |
| `color_accent` | `color` | Accent (button, icon, unit switch) | #231F1B |  |
| `color_accent_text` | `color` | Text on accent | #FFFFFF |  |
| `color_panel` | `color` | Table and drawer background | #FFFFFF |  |
| `color_head` | `color` | Table header background | #F4EFE8 |  |
| `color_line` | `color` | Lines | #E7E0D6 |  |

### Spacing and visibility

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `padding_top` | `range` | Top padding on desktop | `16` | 0–200 px, step 4 |
| `padding_bottom` | `range` | Bottom padding on desktop | `16` | 0–200 px, step 4 |
| `padding_top_mobile` | `range` | Top padding on mobile | `12` | 0–160 px, step 4 |
| `padding_bottom_mobile` | `range` | Bottom padding on mobile | `12` | 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` | Slide the drawer in | `true` |  |

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

### Bedenlerimi nasıl eklerim?

Tablo ayarına yazın: her satır ayrı bir satırda, hücreler dikey çizgiyle (|) ayrılır. İlk satır başlıktır, her satırın ilk hücresi de bedendir; örneğin "S | 86-90 | 68-72". Ya da tablo kaynağını bir sayfa yapın; sayfanın içeriği (genellikle sayfa düzenleyicide hazırlanmış bir tablo) beden tablosu olur.

### Müşteriler santimetre ile inç arasında geçiş yapabilir mi?

Evet. cm / inç geçişini açın ve değerleri hangi birimde yazdığınızı seçin. Sayı hücreleri ve 86-90 gibi aralıklar tek ondalığa çevrilir; beden adları ya da notlar gibi diğer metinler yazdığınız gibi kalır. JavaScript yoksa geçiş gizlenir ve yazdığınız değerler görünür.

### Çekmece erişilebilir mi?

Tarayıcının kendi diyalog öğesidir: odak içine taşınır, Escape ve kapat düğmesi onu kapatır, açıkken sayfanın geri kalanına ulaşılamaz, sayfa kaydırması kilitlenir ve kapanınca odak düğmeye döner. Tablonun bir başlığı ve başlık hücreleri vardır; küçük ekranlarda etiketli bir alan içinde yana kayar, beden sütunu ise görünür kalır.

### Farklı ürünler için farklı tablolar kullanabilir miyim?

Evet. Bölümü kendi tablosu olması gereken her ürün şablonuna ekleyin ya da her tabloyu ayrı bir sayfada tutup bölümde o sayfayı seçin; sayfayı düzenlediğinizde onu kullanan tüm şablonlar güncellenir.

### Tüm metinler çevrilebilir mi?

Müşterinin gördüğü her kelime bir ayardır: düğme metni, başlık, tablo açıklaması, birim etiketleri ve kapat düğmesi, birim geçişi ve tablo alanı için ekran okuyucu adları. Bunları tema düzenleyicide değiştirebilir ya da Shopify’ın Translate & Adapt uygulamasıyla çevirebilirsiniz.

## Kaynak kod

### sections/lib-size-chart.liquid

```liquid
{%- comment -%}
  MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections
{%- endcomment -%}
{%- comment -%}
  Size chart: a size table with measuring notes and an optional how-to-measure image, shown inline
  or behind a button that opens it in a native <dialog> as a side drawer or a centred modal.
  The table is typed in the section (one row per line, cells separated by |, first line = header)
  or comes from a page. Optional cm / in switch converts numeric cells (also ranges like 86-90);
  without JavaScript the typed values show. Modern browsers open the dialog without JavaScript too
  (button commands); the script adds it elsewhere, plus backdrop click and the unit switch.
  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 display = s.display | default: 'drawer'
  assign uid = 'LibSizeChart-' | append: section.id
  assign heading_id = uid | append: '-title'
  assign eager = false
  if section.index <= 2 and display == 'inline'
    assign eager = true
  endif

  assign rows = ''
  if s.source == 'table' and s.table != blank
    assign rows = s.table | newline_to_br | split: '<br />'
  endif
  assign has_page = false
  if s.source == 'page' and s.page != blank and s.page.content != blank
    assign has_page = true
  endif

  assign heading_text = s.heading | strip_html | strip
  if heading_text == blank
    assign heading_text = s.trigger_label | escape
  endif
-%}

{%- capture chart -%}
  <div class="lib-size-chart__body">
    {%- if s.unit_toggle -%}
      <div class="lib-size-chart__units" role="group" aria-label="{{ s.units_label | escape }}" data-units hidden>
        <button type="button" class="lib-size-chart__unit" data-unit="cm" aria-pressed="{% if s.base_unit == 'cm' %}true{% else %}false{% endif %}">
          {{- s.label_cm | escape -}}
        </button>
        <button type="button" class="lib-size-chart__unit" data-unit="in" aria-pressed="{% if s.base_unit == 'in' %}true{% else %}false{% endif %}">
          {{- s.label_in | escape -}}
        </button>
      </div>
    {%- endif -%}

    {%- if rows != blank -%}
      <div class="lib-size-chart__scroll" role="region" tabindex="0" aria-label="{{ s.scroll_label | escape }}">
        <table class="lib-size-chart__table">
          {%- if s.caption != blank -%}
            <caption class="lib-size-chart__caption">{{ s.caption | escape }}</caption>
          {%- endif -%}
          {%- liquid
            assign header = ''
            for row in rows
              assign line = row | strip
              if line != blank
                assign header = line
                break
              endif
            endfor
          -%}
          <thead>
            <tr>
              {%- assign cells = header | split: '|' -%}
              {%- for cell in cells -%}
                <th scope="col">{{ cell | strip | escape }}</th>
              {%- endfor -%}
            </tr>
          </thead>
          <tbody>
            {%- assign header_seen = false -%}
            {%- for row in rows -%}
              {%- assign line = row | strip -%}
              {%- if line == blank -%}{%- continue -%}{%- endif -%}
              {%- if header_seen == false -%}
                {%- assign header_seen = true -%}
                {%- continue -%}
              {%- endif -%}
              {%- assign cells = line | split: '|' -%}
              <tr>
                {%- for cell in cells -%}
                  {%- if forloop.first -%}
                    <th scope="row">{{ cell | strip | escape }}</th>
                  {%- else -%}
                    <td data-measure>{{ cell | strip | escape }}</td>
                  {%- endif -%}
                {%- endfor -%}
              </tr>
            {%- endfor -%}
          </tbody>
        </table>
      </div>
    {%- elsif has_page -%}
      <div class="lib-size-chart__scroll lib-size-chart__page" role="region" tabindex="0" aria-label="{{ s.scroll_label | escape }}">
        {{ s.page.content }}
      </div>
    {%- endif -%}

    {%- if s.notes != blank or s.image != blank or s.image_mobile != blank -%}
      <div class="lib-size-chart__guide">
        {%- if s.image != blank or s.image_mobile != blank -%}
          <div class="lib-size-chart__media">
            {%- render 'lib-image',
              image: s.image,
              image_mobile: s.image_mobile,
              class: 'lib-size-chart__img',
              sizes: '(min-width: 990px) 360px, 100vw',
              eager: eager
            -%}
          </div>
        {%- endif -%}
        {%- if s.notes != blank -%}
          <div class="lib-size-chart__notes">{{ s.notes }}</div>
        {%- endif -%}
      </div>
    {%- endif -%}
  </div>
{%- endcapture -%}

<lib-size-chart
  class="lib-size-chart lib-size-chart--{{ s.section_width }}"
  {% if s.anchor_id != blank %}
    id="{{ s.anchor_id | handleize }}"
  {% endif %}
  data-show="{{ s.show_on }}"
  data-display="{{ display }}"
  data-base-unit="{{ s.base_unit }}"
  {% 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-accent: {{ s.color_accent }};
    --lib-accent-text: {{ s.color_accent_text }};
    --lib-panel: {{ s.color_panel }};
    --lib-head: {{ s.color_head }};
    --lib-line: {{ s.color_line }};
    --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-size-chart__inner" data-align="{{ s.text_alignment }}" data-align-m="{{ s.text_alignment_mobile }}">
    {%- if display == 'inline' -%}
      {%- if s.heading != blank -%}
        <{{ heading_tag }} class="lib-size-chart__heading lib-size-chart__heading--{{ s.heading_size }}">
          {{- s.heading -}}
        </{{ heading_tag }}>
      {%- endif -%}
      {%- if s.text != blank -%}
        <div class="lib-size-chart__text">{{ s.text }}</div>
      {%- endif -%}
      {{ chart }}
    {%- else -%}
      <div class="lib-size-chart__trigger-row">
        {%- if s.trigger_style == 'link' -%}
          <button
            type="button"
            class="lib-size-chart__link"
            aria-haspopup="dialog"
            aria-controls="{{ uid }}"
            command="show-modal"
            commandfor="{{ uid }}"
            data-open
          >
            <svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8h18v8H3z"/><path d="M7 8v3M11 8v4M15 8v3M19 8v4"/></svg>
            <span>{{ s.trigger_label | escape }}</span>
          </button>
        {%- else -%}
          <button
            type="button"
            class="lib-btn lib-btn--{{ s.trigger_style }} lib-size-chart__button"
            aria-haspopup="dialog"
            aria-controls="{{ uid }}"
            command="show-modal"
            commandfor="{{ uid }}"
            data-open
          >
            <span class="lib-btn__label">{{ s.trigger_label | escape }}</span>
          </button>
          {%- comment -%}Prints nothing. Shopify bundles every snippet stylesheet anyway; this keeps the button styles in previews that only load rendered snippets.{%- endcomment -%}
          {%- render 'lib-button', label: '' -%}
        {%- endif -%}
      </div>

      <dialog class="lib-size-chart__dialog" id="{{ uid }}" aria-labelledby="{{ heading_id }}" closedby="any" data-dialog>
        <div class="lib-size-chart__panel">
          <div class="lib-size-chart__bar">
            <{{ heading_tag }} id="{{ heading_id }}" class="lib-size-chart__heading lib-size-chart__heading--{{ s.heading_size }}">
              {{- heading_text -}}
            </{{ heading_tag }}>
            <button type="button" class="lib-size-chart__close" command="close" commandfor="{{ uid }}" data-close>
              <svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" focusable="false"><path d="M6 6l12 12M18 6 6 18" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
              <span class="lib-size-chart__sr">{{ s.close_label | escape }}</span>
            </button>
          </div>
          {%- if s.text != blank -%}
            <div class="lib-size-chart__text">{{ s.text }}</div>
          {%- endif -%}
          {{ chart }}
        </div>
      </dialog>
    {%- endif -%}
  </div>
</lib-size-chart>

{% stylesheet %}
  .lib-size-chart {
    display: block;
    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-size-chart__inner { max-width: 1200px; margin: 0 auto; }
  .lib-size-chart--full { padding-inline: clamp(1rem, 3vw, 2.5rem); }
  .lib-size-chart--full .lib-size-chart__inner { max-width: none; }
  @media (max-width: 749px) {
    .lib-size-chart { padding-top: var(--lib-pt-m); padding-bottom: var(--lib-pb-m); }
    .lib-size-chart[data-show='desktop'] { display: none; }
  }
  @media (min-width: 750px) {
    .lib-size-chart[data-show='mobile'] { display: none; }
  }

  /* Heading, intro and trigger follow the alignment; the table always reads left to right. */
  .lib-size-chart__inner[data-align='center'] > .lib-size-chart__heading,
  .lib-size-chart__inner[data-align='center'] > .lib-size-chart__text { text-align: center; margin-inline: auto; }
  .lib-size-chart__inner[data-align='right'] > .lib-size-chart__heading,
  .lib-size-chart__inner[data-align='right'] > .lib-size-chart__text { text-align: right; margin-inline-start: auto; }
  .lib-size-chart__inner[data-align='center'] .lib-size-chart__trigger-row { justify-content: center; }
  .lib-size-chart__inner[data-align='right'] .lib-size-chart__trigger-row { justify-content: flex-end; }
  @media (max-width: 749px) {
    .lib-size-chart__inner[data-align-m='left'] > .lib-size-chart__heading,
    .lib-size-chart__inner[data-align-m='left'] > .lib-size-chart__text { text-align: left; margin-inline: 0 auto; }
    .lib-size-chart__inner[data-align-m='center'] > .lib-size-chart__heading,
    .lib-size-chart__inner[data-align-m='center'] > .lib-size-chart__text { text-align: center; margin-inline: auto; }
    .lib-size-chart__inner[data-align-m='right'] > .lib-size-chart__heading,
    .lib-size-chart__inner[data-align-m='right'] > .lib-size-chart__text { text-align: right; margin-inline: auto 0; }
    .lib-size-chart__inner[data-align-m='left'] .lib-size-chart__trigger-row { justify-content: flex-start; }
    .lib-size-chart__inner[data-align-m='center'] .lib-size-chart__trigger-row { justify-content: center; }
    .lib-size-chart__inner[data-align-m='right'] .lib-size-chart__trigger-row { justify-content: flex-end; }
  }

  .lib-size-chart__heading {
    margin: 0;
    font-size: clamp(1.75rem, 3vw, 2.5rem);
    line-height: 1.1;
    letter-spacing: -0.02em;
    text-wrap: balance;
  }
  .lib-size-chart__heading--small { font-size: clamp(1.25rem, 2vw, 1.5rem); }
  .lib-size-chart__heading--large { font-size: clamp(2rem, 4vw, 3.25rem); }
  .lib-size-chart__heading--xlarge { font-size: clamp(2.5rem, 6vw, 4.5rem); }
  .lib-size-chart__text { max-width: 40rem; margin-top: 0.875rem; font-size: 1rem; line-height: 1.65; opacity: 0.85; }
  .lib-size-chart__text > :first-child { margin-top: 0; }
  .lib-size-chart__text > :last-child { margin-bottom: 0; }
  .lib-size-chart__inner > .lib-size-chart__body { margin-top: 2rem; }

  /* Trigger */
  .lib-size-chart__trigger-row { display: flex; }
  .lib-size-chart__button { border: 0; cursor: pointer; }
  .lib-size-chart__link {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 2.75rem;
    padding: 0.25rem 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    font-weight: 500;
    text-decoration: underline;
    text-underline-offset: 0.3em;
    cursor: pointer;
  }
  .lib-size-chart__link svg { flex: none; color: var(--lib-accent); }
  .lib-size-chart__link:hover { text-decoration-thickness: 2px; }
  .lib-size-chart__link:focus-visible,
  .lib-size-chart__close:focus-visible,
  .lib-size-chart__unit:focus-visible,
  .lib-size-chart__scroll:focus-visible {
    outline: 2px solid var(--lib-accent);
    outline-offset: 3px;
  }

  /* Units */
  .lib-size-chart__units {
    display: inline-flex;
    margin-bottom: 1rem;
    padding: 3px;
    border-radius: 999px;
    background: var(--lib-head);
  }
  .lib-size-chart__units[hidden] { display: none; }
  .lib-size-chart__unit {
    min-width: 3.25rem;
    min-height: 2.25rem;
    padding: 0.25rem 1rem;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 0.875rem;
    font-weight: 600;
    cursor: pointer;
  }
  .lib-size-chart__unit[aria-pressed='true'] { background: var(--lib-accent); color: var(--lib-accent-text); }

  /* Table: scrolls inside its own region; the size column stays put on narrow screens. */
  .lib-size-chart__scroll {
    max-width: 100%;
    overflow-x: auto;
    border: 1px solid var(--lib-line);
    border-radius: 12px;
    background: var(--lib-panel);
  }
  .lib-size-chart__table,
  .lib-size-chart__page table {
    width: 100%;
    min-width: 28rem;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 0.9375rem;
    font-variant-numeric: tabular-nums;
  }
  .lib-size-chart__caption {
    padding: 0.875rem 1.25rem;
    caption-side: top;
    text-align: left;
    font-size: 0.8125rem;
    opacity: 0.75;
    border-bottom: 1px solid var(--lib-line);
  }
  .lib-size-chart__table th,
  .lib-size-chart__table td,
  .lib-size-chart__page th,
  .lib-size-chart__page td {
    padding: 0.8rem 1.25rem;
    text-align: left;
    white-space: nowrap;
    border-bottom: 1px solid var(--lib-line);
  }
  .lib-size-chart__table thead th,
  .lib-size-chart__page thead th {
    background: var(--lib-head);
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.02em;
  }
  .lib-size-chart__table tbody tr:last-child > *,
  .lib-size-chart__page tbody tr:last-child > * { border-bottom: 0; }
  .lib-size-chart__table tbody th { font-weight: 600; }
  .lib-size-chart__table tr > :first-child {
    position: sticky;
    left: 0;
    z-index: 1;
    background: var(--lib-panel);
    border-right: 1px solid var(--lib-line);
  }
  .lib-size-chart__table thead tr > :first-child { background: var(--lib-head); }
  .lib-size-chart__page > :first-child { margin-top: 0; }
  .lib-size-chart__page > :not(table) { padding-inline: 1.25rem; }

  /* Measuring guide */
  .lib-size-chart__guide {
    display: grid;
    gap: 1.5rem;
    margin-top: 1.75rem;
    align-items: start;
  }
  .lib-size-chart__media { border-radius: 12px; overflow: hidden; background: var(--lib-head); }
  .lib-size-chart__img { display: block; width: 100%; height: auto; }
  .lib-size-chart__notes { font-size: 0.9375rem; line-height: 1.65; }
  .lib-size-chart__notes > :first-child { margin-top: 0; }
  .lib-size-chart__notes > :last-child { margin-bottom: 0; }
  .lib-size-chart__notes h3, .lib-size-chart__notes h4 { margin: 1.25rem 0 0.25rem; font-size: 1rem; }
  @media (min-width: 990px) {
    .lib-size-chart[data-display='inline'] .lib-size-chart__guide:has(.lib-size-chart__media) { grid-template-columns: minmax(0, 360px) 1fr; gap: 2.5rem; }
  }

  /* Dialog: side drawer or centred modal. */
  html:has(.lib-size-chart__dialog[open]) { overflow: hidden; }
  .lib-size-chart__dialog {
    box-sizing: border-box;
    width: min(100%, 36rem);
    max-width: 100%;
    max-height: 100%;
    padding: 0;
    border: 0;
    background: var(--lib-panel);
    color: var(--lib-text);
    box-shadow: 0 24px 60px -20px rgb(0 0 0 / 0.4);
  }
  .lib-size-chart__dialog::backdrop { background: rgb(12 10 9 / 0.55); }
  .lib-size-chart[data-display='drawer'] .lib-size-chart__dialog {
    height: 100%;
    margin: 0 0 0 auto;
  }
  .lib-size-chart[data-display='modal'] .lib-size-chart__dialog {
    width: min(100% - 2rem, 48rem);
    max-height: min(100% - 2rem, 52rem);
    border-radius: 16px;
  }
  .lib-size-chart__panel { padding: 0 clamp(1.25rem, 4vw, 2rem) 2rem; }
  .lib-size-chart__bar {
    position: sticky;
    top: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin: 0 calc(-1 * clamp(1.25rem, 4vw, 2rem)) 1.25rem;
    padding: 1rem clamp(1.25rem, 4vw, 2rem);
    background: var(--lib-panel);
    border-bottom: 1px solid var(--lib-line);
  }
  .lib-size-chart__dialog .lib-size-chart__heading { font-size: clamp(1.25rem, 2vw, 1.5rem); }
  .lib-size-chart__dialog .lib-size-chart__text { margin: 0 0 1.25rem; }
  .lib-size-chart__close {
    flex: none;
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--lib-head);
    color: inherit;
    cursor: pointer;
  }
  .lib-size-chart__close:hover { background: var(--lib-line); }
  .lib-size-chart__sr {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  /* Motion: the drawer slides in, the modal rises (never under reduced motion). */
  @media (prefers-reduced-motion: no-preference) {
    .lib-size-chart[data-animate] .lib-size-chart__dialog[open] { animation: lib-size-chart-rise 0.28s cubic-bezier(0.2, 0.7, 0.2, 1); }
    .lib-size-chart[data-animate][data-display='drawer'] .lib-size-chart__dialog[open] { animation-name: lib-size-chart-slide; }
    .lib-size-chart[data-animate] .lib-size-chart__dialog[open]::backdrop { animation: lib-size-chart-fade 0.28s ease; }
  }
  @keyframes lib-size-chart-slide { from { transform: translateX(100%); } }
  @keyframes lib-size-chart-rise { from { opacity: 0; transform: translateY(16px); } }
  @keyframes lib-size-chart-fade { from { opacity: 0; } }
{% endstylesheet %}

{% javascript %}
  if (!customElements.get('lib-size-chart')) {
    customElements.define(
      'lib-size-chart',
      class extends HTMLElement {
        connectedCallback() {
          this.dialog = this.querySelector('[data-dialog]');
          this.opener = this.querySelector('[data-open]');
          this.cleanup = [];
          this.setupDialog();
          this.setupUnits();
        }

        disconnectedCallback() {
          this.cleanup.forEach((fn) => fn());
          this.cleanup = [];
        }

        on(target, type, handler) {
          target.addEventListener(type, handler);
          this.cleanup.push(() => target.removeEventListener(type, handler));
        }

        setupDialog() {
          if (!this.dialog || !this.opener) return;
          // Browsers with button commands open and close the dialog on their own.
          const native = 'commandForElement' in HTMLButtonElement.prototype;
          if (!native) {
            this.on(this.opener, 'click', () => {
              if (!this.dialog.open) this.dialog.showModal();
            });
            const close = this.dialog.querySelector('[data-close]');
            if (close) this.on(close, 'click', () => this.dialog.close());
          }
          // A click on the backdrop (the dialog box itself, outside the panel) closes it.
          this.on(this.dialog, 'click', (e) => {
            if (e.target === this.dialog) this.dialog.close();
          });
          this.on(this.dialog, 'close', () => {
            if (!this.contains(document.activeElement) || document.activeElement === document.body) {
              this.opener.focus({ preventScroll: true });
            }
          });
        }

        // cm <-> in for numeric cells and ranges ("86", "86.5", "86-90"); other text is left alone.
        setupUnits() {
          const groups = this.querySelectorAll('[data-units]');
          if (!groups.length) return;
          const base = this.dataset.baseUnit === 'in' ? 'in' : 'cm';
          const cells = [...this.querySelectorAll('[data-measure], .lib-size-chart__page td')];
          const pattern = /^\s*(\d+(?:[.,]\d+)?)(?:\s*([-–])\s*(\d+(?:[.,]\d+)?))?\s*$/;
          cells.forEach((cell) => {
            if (pattern.test(cell.textContent)) cell.dataset.original = cell.textContent.trim();
          });
          const convert = (value, unit) => {
            const n = parseFloat(value.replace(',', '.'));
            const out = unit === base ? n : base === 'cm' ? n / 2.54 : n * 2.54;
            return String(Math.round(out * 10) / 10);
          };
          const apply = (unit) => {
            cells.forEach((cell) => {
              const original = cell.dataset.original;
              if (!original) return;
              if (unit === base) {
                cell.textContent = original;
                return;
              }
              const m = original.match(pattern);
              cell.textContent = m[3] ? `${convert(m[1], unit)}${m[2]}${convert(m[3], unit)}` : convert(m[1], unit);
            });
            this.querySelectorAll('[data-unit]').forEach((btn) => {
              btn.setAttribute('aria-pressed', String(btn.dataset.unit === unit));
            });
          };
          groups.forEach((group) => {
            group.hidden = false;
            group.querySelectorAll('[data-unit]').forEach((btn) => {
              this.on(btn, 'click', () => apply(btn.dataset.unit));
            });
          });
        }
      }
    );
  }
{% endjavascript %}

{% schema %}
{
  "name": "Lib · Size chart",
  "tag": "section",
  "class": "lib-section",
  "settings": [
    { "type": "header", "content": "Display" },
    {
      "type": "select",
      "id": "display",
      "label": "Show the chart",
      "options": [
        { "value": "drawer", "label": "In a side drawer, behind a button" },
        { "value": "modal", "label": "In a pop-up, behind a button" },
        { "value": "inline", "label": "On the page" }
      ],
      "default": "drawer"
    },
    { "type": "text", "id": "trigger_label", "label": "Button label", "default": "Size chart", "visible_if": "{{ section.settings.display != 'inline' }}" },
    {
      "type": "select",
      "id": "trigger_style",
      "label": "Button style",
      "options": [
        { "value": "link", "label": "Text link with icon" },
        { "value": "primary", "label": "Solid" },
        { "value": "outline", "label": "Outline" }
      ],
      "default": "link",
      "visible_if": "{{ section.settings.display != 'inline' }}"
    },
    { "type": "text", "id": "close_label", "label": "Close button (screen readers)", "default": "Close size chart", "visible_if": "{{ section.settings.display != 'inline' }}" },

    { "type": "header", "content": "Heading" },
    { "type": "inline_richtext", "id": "heading", "label": "Heading", "info": "In a drawer or pop-up the button label is used when this is empty.", "default": "Size chart" },
    {
      "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": "richtext", "id": "text", "label": "Intro text" },

    { "type": "header", "content": "Table" },
    {
      "type": "select",
      "id": "source",
      "label": "Table source",
      "options": [
        { "value": "table", "label": "Typed below" },
        { "value": "page", "label": "A page" }
      ],
      "default": "table"
    },
    {
      "type": "textarea",
      "id": "table",
      "label": "Table",
      "info": "One row per line, cells separated by |. The first line is the header, the first cell of each row the size.",
      "default": "Size | Chest | Waist | Length\nXS | 82-86 | 64-68 | 66\nS | 86-90 | 68-72 | 68\nM | 90-96 | 72-78 | 70\nL | 96-102 | 78-84 | 72\nXL | 102-108 | 84-90 | 74",
      "visible_if": "{{ section.settings.source == 'table' }}"
    },
    { "type": "page", "id": "page", "label": "Page", "info": "Used when the table source is A page. Its content (usually a table) is shown as the chart." },
    { "type": "text", "id": "caption", "label": "Table caption", "default": "Body measurements" },
    { "type": "text", "id": "scroll_label", "label": "Table area name (screen readers)", "default": "Size chart table, scrolls sideways on small screens" },
    { "type": "checkbox", "id": "unit_toggle", "label": "Show a cm / in switch", "info": "Converts number cells and ranges like 86-90. Other text stays as typed.", "default": true },
    {
      "type": "select",
      "id": "base_unit",
      "label": "Values are typed in",
      "options": [
        { "value": "cm", "label": "Centimetres" },
        { "value": "in", "label": "Inches" }
      ],
      "default": "cm"
    },
    { "type": "text", "id": "label_cm", "label": "Centimetres label", "default": "cm", "visible_if": "{{ section.settings.unit_toggle }}" },
    { "type": "text", "id": "label_in", "label": "Inches label", "default": "in", "visible_if": "{{ section.settings.unit_toggle }}" },
    { "type": "text", "id": "units_label", "label": "Switch name (screen readers)", "default": "Units", "visible_if": "{{ section.settings.unit_toggle }}" },

    { "type": "header", "content": "How to measure" },
    { "type": "richtext", "id": "notes", "label": "Measuring notes", "default": "<p><strong>Chest:</strong> measure around the fullest part, keeping the tape level.</p><p><strong>Waist:</strong> measure around your natural waistline.</p><p><strong>Length:</strong> from the highest point of the shoulder to the hem.</p>" },
    { "type": "image_picker", "id": "image", "label": "Desktop image" },
    { "type": "image_picker", "id": "image_mobile", "label": "Mobile image", "info": "Optional. Shown below 750px." },

    { "type": "header", "content": "Layout" },
    {
      "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 and button alignment on desktop", "default": "left" },
    {
      "type": "select",
      "id": "text_alignment_mobile",
      "label": "Heading and button 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": "#FFFFFF" },
    { "type": "color_background", "id": "color_bg_gradient", "label": "Background gradient", "info": "Optional. Covers the background color." },
    { "type": "color", "id": "color_text", "label": "Text", "default": "#231F1B" },
    { "type": "color", "id": "color_accent", "label": "Accent (button, icon, unit switch)", "default": "#231F1B" },
    { "type": "color", "id": "color_accent_text", "label": "Text on accent", "default": "#FFFFFF" },
    { "type": "color", "id": "color_panel", "label": "Table and drawer background", "default": "#FFFFFF" },
    { "type": "color", "id": "color_head", "label": "Table header background", "default": "#F4EFE8" },
    { "type": "color", "id": "color_line", "label": "Lines", "default": "#E7E0D6" },

    { "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": 16 },
    { "type": "range", "id": "padding_bottom", "label": "Bottom padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 16 },
    { "type": "range", "id": "padding_top_mobile", "label": "Top padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 12 },
    { "type": "range", "id": "padding_bottom_mobile", "label": "Bottom padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 12 },
    {
      "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": "Slide the drawer in", "info": "Never when reduced motion is on.", "default": true }
  ],
  "presets": [
    { "name": "Lib · Size chart" }
  ]
}
{% 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.
