<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Clavier One — Virtual Keyboard</title>

<style>
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  min-height: 100vh;
  background:
    radial-gradient(circle at 20% 20%, #172554 0, transparent 35%),
    radial-gradient(circle at 80% 80%, #312e81 0, transparent 35%),
    #050816;
  color: #fff;
  font-family: Arial, Helvetica, sans-serif;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 25px;
}

.wrapper {
  width: min(1100px, 100%);
}

.header {
  text-align: center;
  margin-bottom: 22px;
}

.logo {
  font-size: 34px;
  font-weight: 800;
  letter-spacing: 2px;
}

.logo span {
  color: #7c3aed;
}

.subtitle {
  color: #94a3b8;
  margin-top: 7px;
}

.panel {
  background: rgba(15, 23, 42, .82);
  border: 1px solid rgba(148, 163, 184, .15);
  border-radius: 24px;
  padding: 22px;
  box-shadow: 0 25px 80px rgba(0,0,0,.45);
  backdrop-filter: blur(18px);
}

textarea {
  width: 100%;
  height: 115px;
  resize: vertical;
  border: 1px solid rgba(148,163,184,.18);
  outline: none;
  border-radius: 16px;
  padding: 18px;
  background: #020617;
  color: #f8fafc;
  font-size: 19px;
  line-height: 1.5;
  margin-bottom: 22px;
}

textarea:focus {
  border-color: #7c3aed;
  box-shadow: 0 0 0 3px rgba(124,58,237,.15);
}

.keyboard {
  background: #020617;
  border-radius: 20px;
  padding: 16px;
  overflow-x: auto;
}

.row {
  display: flex;
  gap: 7px;
  margin-bottom: 7px;
  min-width: 780px;
}

.key {
  height: 55px;
  min-width: 55px;
  flex: 1;
  border: 1px solid #263244;
  border-radius: 10px;
  background: linear-gradient(145deg, #182235, #0d1525);
  color: #e2e8f0;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  box-shadow:
    0 5px 0 #050a13,
    0 8px 14px rgba(0,0,0,.3);
  transition: .08s ease;
  user-select: none;
}

.key:hover {
  border-color: #7c3aed;
  color: #fff;
  box-shadow:
    0 5px 0 #050a13,
    0 0 18px rgba(124,58,237,.25);
}

.key:active,
.key.active {
  transform: translateY(5px);
  box-shadow: 0 0 0 #050a13;
  background: linear-gradient(145deg, #7c3aed, #4f46e5);
}

.wide {
  flex: 1.8;
}

.extra-wide {
  flex: 2.7;
}

.space {
  flex: 6;
}

.controls {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-top: 18px;
  flex-wrap: wrap;
}

button.control {
  border: 0;
  border-radius: 10px;
  padding: 11px 17px;
  cursor: pointer;
  background: #172033;
  color: #cbd5e1;
  border: 1px solid #263244;
}

button.control:hover {
  border-color: #7c3aed;
  color: white;
}

.rgb {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #94a3b8;
}

.rgb input {
  width: 45px;
  height: 28px;
  border: 0;
  background: transparent;
  cursor: pointer;
}

.status {
  text-align: center;
  color: #64748b;
  font-size: 13px;
  margin-top: 15px;
}

@media (max-width: 700px) {
  body {
    padding: 12px;
  }

  .panel {
    padding: 12px;
  }

  .logo {
    font-size: 27px;
  }

  textarea {
    height: 100px;
  }

  .keyboard {
    padding: 10px;
  }
}
</style>
</head>

<body>

<div class="wrapper">

  <div class="header">
    <div class="logo">clavier<span>.one</span></div>
    <div class="subtitle">Professional Virtual Keyboard</div>
  </div>

  <div class="panel">

    <textarea
      id="editor"
      placeholder="Start typing here..."
      autofocus
    ></textarea>

    <div class="keyboard">

      <div class="row">
        <button class="key" data-key="Escape">Esc</button>
        <button class="key" data-key="F1">F1</button>
        <button class="key" data-key="F2">F2</button>
        <button class="key" data-key="F3">F3</button>
        <button class="key" data-key="F4">F4</button>
        <button class="key" data-key="F5">F5</button>
        <button class="key" data-key="F6">F6</button>
        <button class="key" data-key="F7">F7</button>
        <button class="key" data-key="F8">F8</button>
        <button class="key" data-key="F9">F9</button>
        <button class="key" data-key="F10">F10</button>
        <button class="key" data-key="F11">F11</button>
        <button class="key" data-key="F12">F12</button>
      </div>

      <div class="row">
        <button class="key" data-value="`">~<br>`</button>
        <button class="key" data-value="1">!<br>1</button>
        <button class="key" data-value="2">@<br>2</button>
        <button class="key" data-value="3">#<br>3</button>
        <button class="key" data-value="4">$<br>4</button>
        <button class="key" data-value="5">%<br>5</button>
        <button class="key" data-value="6">^<br>6</button>
        <button class="key" data-value="7">&<br>7</button>
        <button class="key" data-value="8">*<br>8</button>
        <button class="key" data-value="9">(<br>9</button>
        <button class="key" data-value="0">)<br>0</button>
        <button class="key" data-value="-">_<br>-</button>
        <button class="key" data-value="=">+<br>=</button>
        <button class="key wide" data-key="Backspace">Backspace</button>
      </div>

      <div class="row">
        <button class="key wide" data-key="Tab">Tab</button>
        <button class="key" data-value="q">Q</button>
        <button class="key" data-value="w">W</button>
        <button class="key" data-value="e">E</button>
        <button class="key" data-value="r">R</button>
        <button class="key" data-value="t">T</button>
        <button class="key" data-value="y">Y</button>
        <button class="key" data-value="u">U</button>
        <button class="key" data-value="i">I</button>
        <button class="key" data-value="o">O</button>
        <button class="key" data-value="p">P</button>
        <button class="key" data-value="[">{<br>[</button>
        <button class="key" data-value="]">}<br>]</button>
        <button class="key" data-value="\">|<br>\</button>
      </div>

      <div class="row">
        <button class="key wide" data-key="CapsLock">Caps Lock</button>
        <button class="key" data-value="a">A</button>
        <button class="key" data-value="s">S</button>
        <button class="key" data-value="d">D</button>
        <button class="key" data-value="f">F</button>
        <button class="key" data-value="g">G</button>
        <button class="key" data-value="h">H</button>
        <button class="key" data-value="j">J</button>
        <button class="key" data-value="k">K</button>
        <button class="key" data-value="l">L</button>
        <button class="key" data-value=";">:<br>;</button>
        <button class="key" data-value="'">"<br>'</button>
        <button class="key wide" data-key="Enter">Enter</button>
      </div>

      <div class="row">
        <button class="key extra-wide" data-key="Shift">Shift</button>
        <button class="key" data-value="z">Z</button>
        <button class="key" data-value="x">X</button>
        <button class="key" data-value="c">C</button>
        <button class="key" data-value="v">V</button>
        <button class="key" data-value="b">B</button>
        <button class="key" data-value="n">N</button>
        <button class="key" data-value="m">M</button>
        <button class="key" data-value=",">&lt;<br>,</button>
        <button class="key" data-value=".">&gt;<br>.</button>
        <button class="key" data-value="/">?<br>/</button>
        <button class="key extra-wide" data-key="Shift">Shift</button>
      </div>

      <div class="row">
        <button class="key" data-key="Control">Ctrl</button>
        <button class="key" data-key="Alt">Alt</button>
        <button class="key space" data-value=" ">Space</button>
        <button class="key" data-key="Alt">Alt</button>
        <button class="key" data-key="Control">Ctrl</button>
        <button class="key" data-key="ArrowLeft">←</button>
        <button class="key" data-key="ArrowUp">↑</button>
        <button class="key" data-key="ArrowDown">↓</button>
        <button class="key" data-key="ArrowRight">→</button>
      </div>

    </div>

    <div class="controls">
      <button class="control" id="clear">Clear</button>
      <button class="control" id="copy">Copy Text</button>

      <label class="rgb">
        RGB
        <input type="color" id="rgbColor" value="#7c3aed">
      </label>
    </div>

    <div class="status">
      Click a key or use your physical keyboard
    </div>

  </div>
</div>

<script>
const editor = document.getElementById("editor");
const keys = document.querySelectorAll(".key");

let caps = false;
let shift = false;

function insertText(text) {
  const start = editor.selectionStart;
  const end = editor.selectionEnd;

  editor.value =
    editor.value.substring(0, start) +
    text +
    editor.value.substring(end);

  editor.selectionStart = editor.selectionEnd = start + text.length;
  editor.focus();
}

function pressKey(key) {

  if (key === "Backspace") {
    const start = editor.selectionStart;
    const end = editor.selectionEnd;

    if (start !== end) {
      editor.setRangeText("", start, end, "start");
    } else if (start > 0) {
      editor.setRangeText("", start - 1, start, "start");
    }

    return;
  }

  if (key === "Enter") {
    insertText("\n");
    return;
  }

  if (key === "Tab") {
    insertText("\t");
    return;
  }

  if (key === "CapsLock") {
    caps = !caps;
    return;
  }

  if (key === "Shift") {
    shift = !shift;
    return;
  }

  if (key === " ") {
    insertText(" ");
    return;
  }

  if (key.length === 1) {
    let char = key;

    if (/[a-z]/i.test(char)) {
      if (caps !== shift) {
        char = char.toUpperCase();
      } else {
        char = char.toLowerCase();
      }
    }

    insertText(char);
  }
}

keys.forEach(button => {

  button.addEventListener("click", () => {

    const value = button.dataset.value;
    const key = button.dataset.key;

    if (value !== undefined) {
      pressKey(value);
    } else if (key) {
      pressKey(key);
    }

    button.classList.add("active");

    setTimeout(() => {
      button.classList.remove("active");
    }, 100);
  });

});

document.addEventListener("keydown", event => {

  const physicalKey = event.key;

  if (
    ["Tab", "Backspace", "Enter", "ArrowLeft",
     "ArrowRight", "ArrowUp", "ArrowDown"].includes(physicalKey)
  ) {
    event.preventDefault();
  }

  if (physicalKey === "CapsLock") {
    caps = !caps;
  }

  if (physicalKey === "Shift") {
    shift = true;
  }

  if (physicalKey === "Backspace") {
    pressKey("Backspace");
  }

  else if (physicalKey === "Enter") {
    pressKey("Enter");
  }

  else if (physicalKey === "Tab") {
    pressKey("Tab");
  }

  else if (physicalKey.length === 1) {
    insertText(physicalKey);
  }

  const matching = [...keys].find(button => {
    return button.dataset.key === physicalKey;
  });

  if (matching) {
    matching.classList.add("active");
  }
});

document.addEventListener("keyup", event => {

  if (event.key === "Shift") {
    shift = false;
  }

  const matching = [...keys].find(button => {
    return button.dataset.key === event.key;
  });

  if (matching) {
    matching.classList.remove("active");
  }
});

document.getElementById("clear").addEventListener("click", () => {
  editor.value = "";
  editor.focus();
});

document.getElementById("copy").addEventListener("click", async () => {

  await navigator.clipboard.writeText(editor.value);

  const button = document.getElementById("copy");
  const oldText = button.textContent;

  button.textContent = "Copied ✓";

  setTimeout(() => {
    button.textContent = oldText;
  }, 1200);
});

document.getElementById("rgbColor").addEventListener("input", event => {

  const color = event.target.value;

  document.documentElement.style.setProperty(
    "--rgb-color",
    color
  );

  document.querySelectorAll(".key").forEach(key => {
    key.style.setProperty("--key-color", color);
  });
});
</script>

</body>
</html>

Leave a Reply

Your email address will not be published. Required fields are marked *