JSFiddle - React, Tailwind, and code Playground

by Nicholas Berlette

HTML

<div id="app" class="!opacity-100">
  <div class="controls">
    <button class="btn">Randomize</button>
    <button class="timer-btn">start timer</button>
  </div>
  <div class="box">
    <p>
      <span>Box</span>
    </p>
  </div>
</div>
<script>
window.windicssRuntimeOptions = {
		timing: 'immediate',
		// enabled preflight
		preflight: true,
		// scan the entire dom tree to infer the classnames on page loaded
		extractInitial: true,
		// generate mock classes for browser to do the auto-completeion 
		mockClasses: true,
		// the windi config you are used to put in `windi.config.js`
		config: {
			darkMode: 'media',
      safelist: ['btn-download', 'todo-list', 'hidden', 'pb-2', 'mb-2'],
			shortcuts: {
				'app-divider': 'border-dashed border-blue-700/30 dark:border-cyan-400/30',
				'app-text': 'text-gray-900 dark:text-gray-50',
				'app': 'w-full h-auto sm:rounded-xl px-10 pb-10 pt-14 mb-16 !leading-12 ring-1 ring-offset-1 ring-offset-gray-100 ring-white bg-white text-gray-900 dark:(bg-gray-800 text-gray-50 ring-offset-gray-800 ring-emerald-700/20) !opacity-100 shadow-lg hover:shadow-xl transition-shadow duration-500 ease-in',
				'wrapper': 'max-w-2xl mx-auto mt-20',
				'h1': 'text-3xl my-0 p-0 mb-6 lowercase flex flex-row justify-between place-items-center align-center !text-primary-500',
				'title': 'text-4xl tracking-tighter font-thin',
				'page': 'font-medium text-2xl app-text opacity-50 hover:opacity-80 transition-opacity duration-500 ease-in cursor-default relative top-1',
				'link': 'text-[1.05em] app-text font-semibold',
				'input-ring': 'ring-1 ring-offset-1 ring-gray-400/20 ring-offset-white dark:(ring-white/15 ring-offset-gray-800) focus:(!ring-1.5 outline-blue-400/40 dark:!outline-blue-400/30 outline-solid)',
				'input-text': 'rounded mr-4 px-3 pt-[9px] pb-2 text-sm border-none bg-gray-200/10 dark:!bg-gray-900/10 text-black dark:!text-white input-ring shadow-sm hover:shadow transition-all duration-500 ease-in w-full...

CSS

@import "https://unpkg.com/@typehaus/[email protected]/400.css";
@import "https://unpkg.com/@typehaus/[email protected]/600.css";

#app {
  max-width: 40vw;
  margin: 40% auto;
  text-align: center;
}
.box p {
  border: 10px solid rgb(0, 0, 0);
  background-color: #8dddff;
  color: #123;
  font-size: 2.5rem;
  padding: 1rem 2rem;
  border-radius: 1rem;
  display: inline-block;
  transition: all 500ms ease-out;
  background-clip: padding-box;
  text-shadow: 0 3px 0 #fff;
  outline: 10px 0 #fff;
  filter: saturation(0.5) contrast(0.5);
}
.box p span {
  filter: saturation(150%);
  transition: all 333ms ease-in;
}
.controls {
  display: flex;
  flex-direction: row;
  gap: 1rem;
  justify-items: space-evenly;
}
.controls button {
  font-size: 1.2rem;
  text-transform: lowercase;
  letter-spacing: -0.02rem;
  font-weight: 400;
  line-height: 1.2rem;
  font-family: 'Metropolis', sans-serif;
  padding: 0.6rem 1.5rem 0.45rem;
  border-radius: 9999px;
  border: 1.5px solid #ddd;
  box-shadow: inset 0px 1px 0 #fff;
  background: linear-gradient(0deg, #e3e3e3, #f0f0f0);
  cursor: pointer;
  transition: background 500ms ease-in, color 400ms ease-in;
  white-space: nowrap;
}
.controls button:hover {
  background: #f0f0f0;
}
.timer-active {
  color: #900;
  border-color: #c44 !important;
  font-weight: 600 !important;
  background: linear-gradient(0deg, #fee, #fff0f0) !important;
}

JavaScript

const btn = document.querySelector('.btn');
const timerBtn = document.querySelector('.timer-btn');
const box = document.querySelector('.box');
const text = document.querySelector('.box p span');

const stylesheet = document.styleSheets[2];
let boxParaRule;

for (let i = 0; i < stylesheet.cssRules.length; i++) {
  if (stylesheet.cssRules[i].selectorText === '.box p') {
    boxParaRule = stylesheet.cssRules[i];
  }
}

function randomize() {
  function random(min, max) {
    const num = Math.floor(Math.random() * (max - min)) + min;
    return num;
  }

  function randomColor() {
    return `rgb(${random(0, 255)}, ${random(0, 255)}, ${random(0, 255)})`;
  }

  function setRandomBorder() {
    const borderStyles = ['single', 'solid', 'double', 'dotted', 'dashed', 'dotted', 'solid', 'grooved', 'doubled'];
    //    const borderStyle = borderStyles[random(0, borderStyles.length - 1)];
    const borderStyle = 'solid';
    const borderColor = randomColor();
    text.style.setProperty('color', borderColor);

    const newBorder = `${random(1, 20)}px ${borderStyle} ${borderColor}`;
    boxParaRule.style.setProperty('border', newBorder);
  }

  function setRandomBorderRadius() {
    const radii = [0, 2, 3, 4, 5, 6, 8, 10, 12, 15, 18, 20, 25, 35, 100, 200];
    const newBorderRadius = random(0, 100) % 3 ? `${radii[random(0, radii.length - 1)]}px ${radii[random(0, radii.length - 1)]}px` : `${radii[random(0, radii.length -1)]}px`;
    boxParaRule.style.setProperty('border-radius', newBorderRadius, "important");
  }

  function setRandomColor() {
    const newBgColor = randomColor();
    boxParaRule.style.setProperty('background-color', newBgColor);
  }

  function setRandomPadding() {
    const pX = random(20, 50);
    const pY = pX * random(0.5, 2.5);;
    const newPadding = `${pX}px ${pY}px`;
    boxParaRule.style.setProperty('padding', newPadding, "important");
  }

  setRandomPadding();
  setRandomColor();
  setRandomBorder();
 ...