--- /dev/null
+# sleepy-operators
+
+An assortment of sleep-based operators to make your programs sleepier.
+
+Or: `sleepsort` but for everything.
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <link rel="icon" href="data:,">
+ <link rel="stylesheet" href="/style.css">
+ <title>sleepy-operators</title>
+</head>
+
+<body>
+ <div>
+ <header>
+ <h1>sleepy-operators</h1>
+
+ <a href="https://github.com/ardislu/sleepy-operators">
+ <svg role="img" aria-labelledby="github" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+ <title id="github">GitHub repository</title>
+ <path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"></path>
+ <path d="M9 18c-4.51 2-5-2-7-2"></path>
+ </svg>
+ </a>
+ </header>
+
+ <main>
+ <p>Open the <span><abbr title="Developer Tools">DevTools</abbr> console</span> to start the demo.</p>
+
+ <table>
+ <thead>
+ <tr>
+ <th><abbr title="Operating System">OS</abbr></th>
+ <th>Browser</th>
+ <th>Shortcut</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Windows/Linux</td>
+ <td>Chrome/Edge</td>
+ <td><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>J</kbd></td>
+ </tr>
+ <tr>
+ <td>Windows/Linux</td>
+ <td>Firefox</td>
+ <td><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>K</kbd></td>
+ </tr>
+ <tr>
+ <td>macOS</td>
+ <td>Chrome/Edge</td>
+ <td><abbr title="Command"><kbd>⌘</kbd></abbr> + <kbd>Option</kbd> + <kbd>J</kbd></td>
+ </tr>
+ <tr>
+ <td>macOS</td>
+ <td>Firefox</td>
+ <td><abbr title="Command"><kbd>⌘</kbd></abbr> + <kbd>Option</kbd> + <kbd>K</kbd></td>
+ </tr>
+ <tr>
+ <td>macOS</td>
+ <td>Safari</td>
+ <td><abbr title="Command"><kbd>⌘</kbd></abbr> + <kbd>Option</kbd> + <kbd>C</kbd></td>
+ </tr>
+ </tbody>
+ </table>
+ </main>
+ </div>
+
+ <script type="module" src="/script.js"></script>
+</body>
+
+</html>
\ No newline at end of file
--- /dev/null
+import * as sleepy from '/sleepy-operators.js';
+
+const ascii =
+ ` _
+ | |
+ ___ | | ___ ___ _____ _ _
+| __|| || _ || _ || _ || | | |_____
+|__ || || __|| __|| |_| || |_| |_____|
+|___||_||___||___|| ___||__ |
+ | | _| |
+ |_| |____|
+ _____ _____ ___ ____ ____ | |_ _____ _____ ___
+| _ | _ | _ || _|/ _ || __|| _ || _ | __|
+| |_| | |_| | __|| | | |_| || |__| |_| || | |__ |
+|_____| ___|___||__| |_____||____|_____||_| |___|
+ | |
+ |_|`;
+
+function help() {
+ console.log(`%c ${ascii}`, 'font-weight: bold');
+ // TODO: print a helpful demo message
+}
+globalThis.help = help;
+help();
+
+globalThis.sleepy = sleepy;
--- /dev/null
+/** @module sleepy-operators */
+
+/** Internal helper function that converts setTimeout into a promise. */
+async function sleep(ms) {
+ return new Promise(resolve => setTimeout(resolve, ms));
+}
+
+/**
+ * The classic sleep sort!
+ * @param {number[]} arr - An array of numbers to sort. Works best with small numbers :)
+ * @returns {Promise<number[]>} A promise that resolves to the sorted array.
+ */
+export async function sort(arr) {
+ const output = [];
+
+ await Promise.all(arr.map(i => (async () => {
+ await sleep(Math.abs(i));
+ i >= 0 ? output.push(i) : output.unshift(i);
+ })()));
+
+ return output;
+}
+
+/**
+ * Sleepily add together a bunch of numbers to get an approximate sum. The returned sum will
+ * be greater than the true sum by about 5-15 per input number.
+ * @param {number[]} arr An array of numbers to sum together.
+ * @returns {Promise<number>} A promise that resolves to the approximate sum of all the numbers in the input array.
+ */
+export async function sum(arr) {
+ const start = performance.now();
+ for (const i of arr) {
+ await sleep(i);
+ }
+ const end = performance.now();
+
+ return end - start;
+}
\ No newline at end of file
--- /dev/null
+body {
+ font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
+ background: radial-gradient(circle at min(300px, 50% - 8px) 50%, hsl(222deg 50% 20%) 300px, hsl(240deg 50% 5%));
+ color: hsl(222deg 50% 80%);
+ block-size: 100dvh;
+ inline-size: min(720px, 100% - 16px);
+ margin-block: 0;
+ margin-inline: 8px auto;
+ display: grid;
+ place-items: center;
+}
+
+header {
+ display: flex;
+ align-items: center;
+}
+
+p {
+ font-size: 1.2rem;
+}
+
+span {
+ font-weight: 700;
+}
+
+table {
+ border-collapse: collapse;
+}
+
+tr {
+ transition: background-color 400ms;
+}
+
+tr:hover,
+tr:focus-within {
+ background: hsl(222deg 50% 15%);
+ transition: background-color 200ms;
+}
+
+th,
+td {
+ line-height: 2;
+ padding-block: 8px;
+ padding-inline: 4px 16px;
+}
+
+/* Optically center the shortcut cell vertically (due to <kbd> styling) */
+td:has(kbd) {
+ transform: translateY(-2px);
+}
+
+kbd {
+ background: linear-gradient(180deg, hsl(0deg 0% 20%), hsl(0deg 0% 10%));
+ font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace;
+ font-weight: bold;
+ font-size: 0.75em;
+ padding-block: 3px;
+ padding-inline: 6px;
+ border: 1px solid;
+ border-radius: 8px;
+ margin-inline: 4px;
+}
+
+a {
+ text-decoration: none;
+ font-weight: 700;
+ color: inherit;
+}
+
+a>svg {
+ inline-size: 24px;
+ block-size: 24px;
+ padding: 12px;
+ padding-block-end: 0;
+ border-radius: 16px;
+ transition: transform 600ms, filter 800ms;
+}
+
+a>svg:hover,
+a>svg:focus-within {
+ filter: brightness(130%);
+ transform: translateY(-4px);
+ transition: transform 200ms, filter 300ms;
+}
+
+abbr:has(kbd) {
+ text-decoration: none;
+}
\ No newline at end of file