JSFiddle - React, Tailwind, and code Playground

by romantonoff

HTML

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ionic/core@6.2.2/css/ionic.bundle.css">
<script src="https://unpkg.com/cupertino-pane@1.2.7/dist/cupertino-pane.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@ionic/core@6.2.2/dist/ionic/ionic.js"></script>
<!DOCTYPE html>
<html dir="ltr" mode="ios">
<body class="dark">
  <ion-content scroll-y="false">
    <ion-list>      
      <ion-item>
        <ion-range color="medium" min="1" max="20" step="1" id="cardsValue">
          <ion-label color="medium" slot="start">Cards</ion-label>
          <ion-label color="medium" slot="end" id="cardsValueResult"></ion-label>
        </ion-range>
      </ion-item>
      <ion-item>
        <ion-range color="medium" min="0" max="3000" step="5" id="angleValue">
          <ion-label color="medium" slot="start">Angle</ion-label>
          <ion-label color="medium" slot="end" id="angleValueResult"></ion-label>
        </ion-range>
      </ion-item>
      <ion-item>
        <ion-range color="medium" min="0" max="100" step="1" id="offsetYValue">
          <ion-label color="medium" slot="start">Offset Y</ion-label>
          <ion-label color="medium" slot="end" id="offsetYValueResult"></ion-label>
        </ion-range>
      </ion-item>
      <ion-item>
        <ion-range color="medium" min="0" max="100" step="1" id="scaleValue">
          <ion-label color="medium" slot="start">Scale</ion-label>
          <ion-label color="medium" slot="end" id="scaleValueResult"></ion-label>
        </ion-range>
      </ion-item>
      <ion-item>
        <ion-range color="medium" min="0" max="100" step="1" id="contrastValue">
          <ion-label color="medium" slot="start">Contrast</ion-label>
          <ion-label color="medium" slot="end" id="contrastValueResult"></ion-label>
        </ion-range>
      </ion-item>
    </ion-list>

    <div id="z-stack"></div>
  </ion-content>
  
</body>
</html>

CSS

body.dark{--ion-color-primary:#428cff;--ion-color-primary-rgb:66,140,255;--ion-color-primary-contrast:#ffffff;--ion-color-primary-contrast-rgb:255,255,255;--ion-color-primary-shade:#3a7be0;--ion-color-primary-tint:#5598ff;--ion-color-secondary:#50c8ff;--ion-color-secondary-rgb:80,200,255;--ion-color-secondary-contrast:#ffffff;--ion-color-secondary-contrast-rgb:255,255,255;--ion-color-secondary-shade:#46b0e0;--ion-color-secondary-tint:#62ceff;--ion-color-tertiary:#6a64ff;--ion-color-tertiary-rgb:106,100,255;--ion-color-tertiary-contrast:#ffffff;--ion-color-tertiary-contrast-rgb:255,255,255;--ion-color-tertiary-shade:#5d58e0;--ion-color-tertiary-tint:#7974ff;--ion-color-success:#2fdf75;--ion-color-success-rgb:47,223,117;--ion-color-success-contrast:#000000;--ion-color-success-contrast-rgb:0,0,0;--ion-color-success-shade:#29c467;--ion-color-success-tint:#44e283;--ion-color-warning:#ffd534;--ion-color-warning-rgb:255,213,52;--ion-color-warning-contrast:#000000;--ion-color-warning-contrast-rgb:0,0,0;--ion-color-warning-shade:#e0bb2e;--ion-color-warning-tint:#ffd948;--ion-color-danger:#ff4961;--ion-color-danger-rgb:255,73,97;--ion-color-danger-contrast:#ffffff;--ion-color-danger-contrast-rgb:255,255,255;--ion-color-danger-shade:#e04055;--ion-color-danger-tint:#ff5b71;--ion-color-dark:#f4f5f8;--ion-color-dark-rgb:244,245,248;--ion-color-dark-contrast:#000000;--ion-color-dark-contrast-rgb:0,0,0;--ion-color-dark-shade:#d7d8da;--ion-color-dark-tint:#f5f6f9;--ion-color-medium:#989aa2;--ion-color-medium-rgb:152,154,162;--ion-color-medium-contrast:#000000;--ion-color-medium-contrast-rgb:0,0,0;--ion-color-medium-shade:#86888f;--ion-color-medium-tint:#a2a4ab;--ion-color-light:#222428;--ion-color-light-rgb:34,36,40;--ion-color-light-contrast:#ffffff;--ion-color-light-contrast-rgb:255,255,255;--ion-color-light-shade:#1e2023;--ion-color-light-tint:#383a3e}.ios...

JavaScript

const cardsValue = document.getElementById('cardsValue');
const angleValue = document.getElementById('angleValue');
const offsetYValue = document.getElementById('offsetYValue');
const scaleValue = document.getElementById('scaleValue');
const contrastValue = document.getElementById('contrastValue');
const stackEl = document.getElementById('z-stack');

// defaults
cardsValue.value = 5;
angleValue.value= 160;
offsetYValue.value = 12;
scaleValue.value = 93;
contrastValue.value = 93;
let cardsArray = {};

const ranges = [cardsValue, angleValue, offsetYValue, scaleValue, contrastValue];
for (let i = 0; i < ranges.length; i++) {
  let el = ranges[i];
  updateRangeResult(el);

  el.addEventListener('ionChange', function (ev) {
    updateRangeResult(ev.target);
    render();
  });
}

function updateRangeResult(el) {
  var resultEl = document.getElementById(`${el.id}Result`);

  if (el.id === 'scaleValue' || el.id === 'contrastValue') {
    resultEl.innerHTML = Math.round(el.value) / 100;  
    return;
  }

  resultEl.innerHTML = Math.round(el.value);
}

function openCardZStack(index, animate) {
  for (let i = cardsValue.value - 1; i > index; i--) {
    let isCardExist = (!!document.querySelector(`.cupertino-pane-wrapper.card-${i}`));
    if (isCardExist) {
      cardsArray[i].destroy({animate}); 
    }    
  }

  for (let i = 0; i <= index; i++) {
    let isCardExist = (!!document.querySelector(`.cupertino-pane-wrapper.card-${i}`));
    if (!isCardExist) {
      cardsArray[i].present({ animate });
    }
  }
}

function dragZStack(ev, current) {
  if (current === cardsValue.value - 1) {
    return;
  }

  if (ev.delta > 70) {
    cardsArray[current].disableDrag();
    openCardZStack(current + 1, true);
  }
}

function dismissZStack(ev, current) {    
  cardsArray[current - 1]?.enableDrag();
}

function render() {
  cardsArray = {};
  stackEl.innerHTML = '';

  let settings = { 
    initialBreak: 'top',
    breaks: {
      top: { enabled: true, height: window.innerHeight -...