Book a callGitHub147

Pick a time for your haircut

45 minutes with Rui · times in Porto (WET)

Tue 18 Nov

No free times

Wed 19 Nov

    No free times

    Thu 20 Nov

    No free times

    Last time left that day

    Live preview: try it.

    Source
    <style>
    .odl-time-slots { box-sizing: border-box; inline-size: 100%; max-inline-size: 40rem; margin-inline: auto; container-type: inline-size; display: grid; gap: var(--ds-space-stack-lg); padding: var(--ds-space-inset-xl);
      background: var(--ds-color-surface-raised); color: var(--ds-color-text-primary); border: var(--ds-border-width-default) solid var(--ds-color-border-subtle); border-radius: var(--ds-radius-container);
      box-shadow: var(--ds-elevation-raised); font: var(--ds-text-body-md); text-wrap: pretty; }
    .odl-time-slots *, .odl-time-slots *::before { box-sizing: border-box; }
    .odl-time-slots header { display: grid; gap: var(--ds-space-stack-xs); }
    .odl-time-slots h3 { margin: 0; font: var(--ds-text-title-md); overflow-wrap: anywhere; }
    .odl-time-slots .odl-tz { margin: 0; color: var(--ds-color-text-secondary); font: var(--ds-text-label-md); overflow-wrap: anywhere; }
    .odl-time-slots .odl-days { display: grid; }
    .odl-time-slots .odl-day { display: grid; grid-template-columns: 7.5rem minmax(0, 1fr); align-items: start; gap: var(--ds-space-stack-sm) var(--ds-space-inline-md); padding-block: var(--ds-space-stack-md); }
    .odl-time-slots .odl-day:first-child { padding-block-start: 0; }
    .odl-time-slots .odl-day:last-child { padding-block-end: 0; }
    .odl-time-slots .odl-day + .odl-day { border-block-start: var(--ds-border-width-default) solid var(--ds-color-border-separator); }
    .odl-time-slots .odl-dlabel { margin: 0; min-block-size: max(var(--ds-size-control-md), var(--ds-size-target-min)); display: flex; align-items: center; font: var(--ds-text-label-lg); font-weight: var(--ds-font-weight-label); overflow-wrap: anywhere; }
    .odl-time-slots ul { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr)); gap: var(--ds-space-target-gap) var(--ds-space-inline-sm); }
    .odl-time-slots li { display: grid; min-inline-size: 0; }
    .odl-time-slots .odl-wrap { display: grid; min-inline-size: 0; }
    .odl-time-slots .odl-slot { position: relative; display: inline-flex; align-items: center; justify-content: center; min-inline-size: 0; min-block-size: max(var(--ds-size-control-md), var(--ds-size-target-min)); padding: var(--ds-space-inset-xs) var(--ds-space-inset-sm);
      border: var(--ds-border-width-default) solid var(--ds-color-border-default); border-radius: var(--ds-radius-control); background: var(--ds-color-surface-raised); color: var(--ds-color-text-primary);
      font: var(--ds-text-label-lg); font-weight: var(--ds-font-weight-label); font-variant-numeric: tabular-nums; text-align: center; overflow-wrap: anywhere; cursor: pointer;
      transition: background-color var(--ds-motion-duration-short) var(--ds-motion-easing-standard), border-color var(--ds-motion-duration-short) var(--ds-motion-easing-standard); }
    .odl-time-slots .odl-slot:hover { background: var(--ds-color-bg-neutral-subtle); border-color: var(--ds-color-border-strong); }
    /* almost full: a small dot in the corner; say so in words too (the action's a11y_label) */
    .odl-time-slots [data-tone="neutral"] .odl-slot::after { content: none; }
    .odl-time-slots [data-tone="warning"] .odl-slot::after { content: ""; position: absolute; inset-block-start: var(--ds-space-inset-xs); inset-inline-end: var(--ds-space-inset-xs);
      inline-size: var(--ds-space-6); block-size: var(--ds-space-6); border-radius: var(--ds-radius-full); background: var(--ds-color-bg-warning-bold); }
    .odl-time-slots .odl-slot[aria-pressed="true"] { border-color: transparent; background: var(--ds-color-bg-action-primary); color: var(--ds-color-text-on-action); }
    .odl-time-slots .odl-slot:disabled { cursor: not-allowed; border-color: var(--ds-color-border-subtle); background: var(--ds-color-bg-neutral-subtle); color: var(--ds-color-text-secondary); text-decoration: line-through; }
    .odl-time-slots .odl-slot:focus-visible { outline: var(--ds-focus-ring-width) solid var(--ds-color-border-focus); outline-offset: var(--ds-focus-ring-offset); }
    /* a day with no times says so, in place of the buttons */
    .odl-time-slots .odl-none { display: none; margin: 0; min-block-size: max(var(--ds-size-control-md), var(--ds-size-target-min)); align-items: center; color: var(--ds-color-text-secondary); font: var(--ds-text-body-md); }
    .odl-time-slots .odl-day:not(:has(.odl-slot)) .odl-none { display: flex; }
    .odl-time-slots .odl-day:not(:has(.odl-slot)) ul { display: none; }
    .odl-time-slots .odl-legend { display: flex; align-items: center; gap: var(--ds-space-inline-sm); margin: 0; color: var(--ds-color-text-secondary); font: var(--ds-text-label-md); overflow-wrap: anywhere; }
    .odl-time-slots .odl-legend::before { content: ""; flex: none; inline-size: var(--ds-space-6); block-size: var(--ds-space-6); border-radius: var(--ds-radius-full); background: var(--ds-color-bg-warning-bold); }
    /* Phone: the day's name sits above its times. */
    @container (max-width: 30rem) {
      .odl-time-slots .odl-day { grid-template-columns: minmax(0, 1fr); }
      .odl-time-slots .odl-dlabel { min-block-size: 0; }
      .odl-time-slots ul { grid-template-columns: repeat(auto-fill, minmax(4.75rem, 1fr)); }
    }
    @media (max-width: 30rem) { .odl-time-slots { padding: var(--ds-space-inset-lg); } }
    /* the hidden template item (data-od-template) stays out of sight in the static file */
    .odl-time-slots [hidden] { display: none !important; }
    @media (prefers-reduced-motion: reduce) { .odl-time-slots, .odl-time-slots *, .odl-time-slots *::before, .odl-time-slots *::after { transition: none !important; animation: none !important; } }
    </style>
    <section class="odl-time-slots" aria-label="Pick a time for your haircut" data-od-label="title">
      <header><h3 data-od-slot="title">Pick a time for your haircut</h3><p class="odl-tz" data-od-slot="timezone" data-od-optional>45 minutes with Rui · times in Porto (WET)</p></header>
      <div class="odl-days" data-od-list="days">
        <div class="odl-day" role="group" data-od-label="label" data-od-item data-od-template hidden><p class="odl-dlabel" data-od-slot="label"></p>
          <ul data-od-list="slots"><li data-od-item><span class="odl-wrap" data-od-var="tone" data-tone="neutral"><button type="button" class="odl-slot" data-od-action="select"></button></span></li></ul>
          <p class="odl-none">No free times</p></div>
        <div class="odl-day" role="group" aria-label="Tue 18 Nov" data-od-item><p class="odl-dlabel">Tue 18 Nov</p>
          <ul><li><span class="odl-wrap" data-tone="neutral"><button type="button" class="odl-slot" aria-label="09:30, Tue 18 Nov">09:30</button></span></li>
            <li><span class="odl-wrap" data-tone="neutral"><button type="button" class="odl-slot" aria-label="11:00, Tue 18 Nov" aria-pressed="true">11:00</button></span></li>
            <li><span class="odl-wrap" data-tone="neutral"><button type="button" class="odl-slot" aria-label="14:15, Tue 18 Nov">14:15</button></span></li>
            <li><span class="odl-wrap" data-tone="warning"><button type="button" class="odl-slot" aria-label="17:45, Tue 18 Nov, last one">17:45</button></span></li></ul>
          <p class="odl-none">No free times</p></div>
        <div class="odl-day" role="group" aria-label="Wed 19 Nov" data-od-item><p class="odl-dlabel">Wed 19 Nov</p>
          <ul></ul><p class="odl-none">No free times</p></div>
        <div class="odl-day" role="group" aria-label="Thu 20 Nov" data-od-item><p class="odl-dlabel">Thu 20 Nov</p>
          <ul><li><span class="odl-wrap" data-tone="neutral"><button type="button" class="odl-slot" aria-label="10:00, Thu 20 Nov">10:00</button></span></li>
            <li><span class="odl-wrap" data-tone="warning"><button type="button" class="odl-slot" aria-label="12:30, Thu 20 Nov, last one">12:30</button></span></li>
            <li><span class="odl-wrap" data-tone="neutral"><button type="button" class="odl-slot" aria-label="15:00, Thu 20 Nov">15:00</button></span></li></ul>
          <p class="odl-none">No free times</p></div>
      </div>
      <p class="odl-legend" data-od-slot="legend" data-od-optional>Last time left that day</p>
    </section>
    <script>
    document.querySelectorAll(".odl-time-slots").forEach((root) => {
      if (root.dataset.odlReady) return; // wire once
      root.dataset.odlReady = "1";
      // the picked time stays marked until another is picked; the host gets the choice from the button itself
      const slots = [...root.querySelectorAll(".odl-slot")];
      slots.forEach((b) => b.addEventListener("click", () => {
        slots.forEach((x) => x.setAttribute("aria-pressed", String(x === b)));
      }));
    });
    </script>
    

    More like this

    B2BQuiet · Any product

    Date range picker

    Pick a start and end day from two months side by side.

    B2BDense · Finance

    Filter bar

    Search, filters and sort above a table.

    Your kit

    Nothing here yet. Add parts with Add to kit, and a look if you want the whole system.

      Parts
      0
      Files to fetch
      0 KB
      Licence
      MIT
      Total
      Free, now and later

      How do you want it?

      Your prompt

      No sign-up. Nothing leaves your browser until you paste it.

      Free