From 8aff61967d63baece26486160c9c63ea9e0ef6df Mon Sep 17 00:00:00 2001
From: Paolo Brasolin <paolo.brasolin@eurac.edu>
Date: Wed, 23 Mar 2022 10:34:11 +0100
Subject: [PATCH] feat: #fe whip up minimal working keyboard

---
 frontend/package-lock.json               | 192 ++++++++++++++++++++++-
 frontend/package.json                    |   4 +-
 frontend/src/css/keyboard.scss           | 109 +++++++++++++
 frontend/src/css/{main.css => main.scss} |   2 +
 frontend/src/index.html                  |   3 +-
 frontend/src/js/main.ts                  |  24 +++
 6 files changed, 331 insertions(+), 3 deletions(-)
 create mode 100644 frontend/src/css/keyboard.scss
 rename frontend/src/css/{main.css => main.scss} (69%)

diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 041b653..ddb9185 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -12,7 +12,8 @@
         "axios": "^0.26.0",
         "damerau-levenshtein": "^1.0.8",
         "newton-raphson-method": "^1.0.2",
-        "phaser": "^3.55.2"
+        "phaser": "^3.55.2",
+        "simple-keyboard": "^3.4.68"
       },
       "devDependencies": {
         "@types/jest": "^27.0.3",
@@ -27,6 +28,7 @@
         "parcel-bundler": "^1.12.4",
         "parcel-plugin-static-files-copy": "^2.6.0",
         "prettier": "^2.5.1",
+        "sass": "^1.49.9",
         "ts-jest": "^27.0.7",
         "ts-node": "^10.5.0",
         "typescript": "^4.5.2"
@@ -7246,6 +7248,12 @@
         "node": ">= 4"
       }
     },
+    "node_modules/immutable": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz",
+      "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==",
+      "dev": true
+    },
     "node_modules/import-fresh": {
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -12391,6 +12399,95 @@
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
       "dev": true
     },
+    "node_modules/sass": {
+      "version": "1.49.9",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.9.tgz",
+      "integrity": "sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==",
+      "dev": true,
+      "dependencies": {
+        "chokidar": ">=3.0.0 <4.0.0",
+        "immutable": "^4.0.0",
+        "source-map-js": ">=0.6.2 <2.0.0"
+      },
+      "bin": {
+        "sass": "sass.js"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/sass/node_modules/binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/sass/node_modules/chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/sass/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/sass/node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dev": true,
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/sass/node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dev": true,
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
     "node_modules/sax": {
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
@@ -12595,6 +12692,11 @@
       "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
       "dev": true
     },
+    "node_modules/simple-keyboard": {
+      "version": "3.4.68",
+      "resolved": "https://registry.npmjs.org/simple-keyboard/-/simple-keyboard-3.4.68.tgz",
+      "integrity": "sha512-k/8Q2ya0cjgsh89LKmitoLZ5OuKxLcOM+KBypY50POPZr5ZwY0FO/zgSo4e0FwW+nKbkycccKwuU4TiY6DlIiA=="
+    },
     "node_modules/simple-swizzle": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
@@ -12774,6 +12876,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/source-map-js": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+      "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/source-map-resolve": {
       "version": "0.5.3",
       "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
@@ -20436,6 +20547,12 @@
       "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
       "dev": true
     },
+    "immutable": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz",
+      "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==",
+      "dev": true
+    },
     "import-fresh": {
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -24525,6 +24642,68 @@
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
       "dev": true
     },
+    "sass": {
+      "version": "1.49.9",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.9.tgz",
+      "integrity": "sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==",
+      "dev": true,
+      "requires": {
+        "chokidar": ">=3.0.0 <4.0.0",
+        "immutable": "^4.0.0",
+        "source-map-js": ">=0.6.2 <2.0.0"
+      },
+      "dependencies": {
+        "binary-extensions": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+          "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+          "dev": true
+        },
+        "chokidar": {
+          "version": "3.5.3",
+          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+          "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+          "dev": true,
+          "requires": {
+            "anymatch": "~3.1.2",
+            "braces": "~3.0.2",
+            "fsevents": "~2.3.2",
+            "glob-parent": "~5.1.2",
+            "is-binary-path": "~2.1.0",
+            "is-glob": "~4.0.1",
+            "normalize-path": "~3.0.0",
+            "readdirp": "~3.6.0"
+          }
+        },
+        "glob-parent": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+          "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+          "dev": true,
+          "requires": {
+            "is-glob": "^4.0.1"
+          }
+        },
+        "is-binary-path": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+          "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+          "dev": true,
+          "requires": {
+            "binary-extensions": "^2.0.0"
+          }
+        },
+        "readdirp": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+          "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+          "dev": true,
+          "requires": {
+            "picomatch": "^2.2.1"
+          }
+        }
+      }
+    },
     "sax": {
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
@@ -24699,6 +24878,11 @@
       "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
       "dev": true
     },
+    "simple-keyboard": {
+      "version": "3.4.68",
+      "resolved": "https://registry.npmjs.org/simple-keyboard/-/simple-keyboard-3.4.68.tgz",
+      "integrity": "sha512-k/8Q2ya0cjgsh89LKmitoLZ5OuKxLcOM+KBypY50POPZr5ZwY0FO/zgSo4e0FwW+nKbkycccKwuU4TiY6DlIiA=="
+    },
     "simple-swizzle": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
@@ -24850,6 +25034,12 @@
       "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
       "dev": true
     },
+    "source-map-js": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+      "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+      "dev": true
+    },
     "source-map-resolve": {
       "version": "0.5.3",
       "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index c4daf9e..29928c5 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -20,7 +20,8 @@
     "axios": "^0.26.0",
     "damerau-levenshtein": "^1.0.8",
     "newton-raphson-method": "^1.0.2",
-    "phaser": "^3.55.2"
+    "phaser": "^3.55.2",
+    "simple-keyboard": "^3.4.68"
   },
   "devDependencies": {
     "@types/jest": "^27.0.3",
@@ -35,6 +36,7 @@
     "parcel-bundler": "^1.12.4",
     "parcel-plugin-static-files-copy": "^2.6.0",
     "prettier": "^2.5.1",
+    "sass": "^1.49.9",
     "ts-jest": "^27.0.7",
     "ts-node": "^10.5.0",
     "typescript": "^4.5.2"
diff --git a/frontend/src/css/keyboard.scss b/frontend/src/css/keyboard.scss
new file mode 100644
index 0000000..c2f3def
--- /dev/null
+++ b/frontend/src/css/keyboard.scss
@@ -0,0 +1,109 @@
+$kbd-gutter: 3px;
+$key-width: 8vw;
+
+.hg-theme-default {
+  width: 100%;
+  user-select: none;
+  box-sizing: border-box;
+  overflow: hidden;
+  touch-action: manipulation;
+  // font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
+  font-family: "Courier New", Courier, monospace;
+
+  // background-color: #ececec;
+  background-color: #aaaa;
+  // padding: 5px;
+  padding: $kbd-gutter;
+  // border-radius: 5px;
+
+  font-weight: bold;
+  // font-size: 20px;
+
+  .hg-button span {
+    pointer-events: none;
+  }
+
+  button.hg-button {
+    border-width: 0;
+    outline: 0;
+    font-size: inherit;
+  }
+
+  .hg-button {
+    display: inline-block;
+    flex-grow: 1;
+    cursor: pointer;
+  }
+
+  .hg-row {
+    display: flex;
+
+    &:not(:last-child) {
+      // margin-bottom: 5px;
+      margin-bottom: $kbd-gutter;
+    }
+
+    .hg-button:not(:last-child) {
+      // margin-right: 5px;
+      margin-right: $kbd-gutter;
+    }
+
+    .hg-button-container {
+      // margin-right: 5px;
+      margin-right: $kbd-gutter;
+      display: flex;
+    }
+
+    > div:last-child {
+      margin-right: 0;
+    }
+
+    &:nth-child(2) {
+      margin-left: 0.5 * $key-width;
+    }
+  }
+
+  .hg-button {
+    // box-shadow: 0px 0px 3px -1px rgba(0, 0, 0, 0.3);
+    height: 40px;
+    border-radius: 5px;
+    box-sizing: border-box;
+    // padding: 5px;
+    background: white;
+    // border-bottom: 1px solid #b5b5b5;
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+
+    &.hg-standardBtn {
+      // width: 20px;
+      // width: $key-width;
+      max-width: 8vw; // 100/12 ~ 8.3
+    }
+
+    &.hg-activeButton {
+      background: #ff0;
+    }
+  }
+
+  // .hg-button {
+  //   &.hg-functionBtn {
+  //     &[data-skbtn="{bksp}"] {
+  //       background-color: lightcoral;
+  //     }
+  //     &[data-skbtn="{space}"] {
+  //       background-color: lightblue;
+  //     }
+  //     &[data-skbtn="{enter}"] {
+  //       background-color: lightgreen;
+  //     }
+  //   }
+  // }
+}
+
+.simple-keyboard {
+  position: absolute;
+  bottom: 0;
+}
diff --git a/frontend/src/css/main.css b/frontend/src/css/main.scss
similarity index 69%
rename from frontend/src/css/main.css
rename to frontend/src/css/main.scss
index 2ca97a6..47d4e78 100644
--- a/frontend/src/css/main.css
+++ b/frontend/src/css/main.scss
@@ -5,3 +5,5 @@ body {
   height: 100vh;
   margin: 0;
 }
+
+@import url("./keyboard.scss");
diff --git a/frontend/src/index.html b/frontend/src/index.html
index 0ceb7e1..0058f20 100644
--- a/frontend/src/index.html
+++ b/frontend/src/index.html
@@ -4,12 +4,13 @@
 <head>
   <meta charset="utf-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <link href="css/main.css" rel="stylesheet">
+  <link href="css/main.scss" rel="stylesheet">
   <script src="js/main.ts" charset="utf-8"></script>
   <title>Ötzi App</title>
 </head>
 
 <body>
+  <div class="simple-keyboard"></div>
 </body>
 
 </html>
diff --git a/frontend/src/js/main.ts b/frontend/src/js/main.ts
index 3e0695f..05cfa2b 100644
--- a/frontend/src/js/main.ts
+++ b/frontend/src/js/main.ts
@@ -22,3 +22,27 @@ const config = {
 };
 
 new Phaser.Game(config);
+
+import Keyboard from "simple-keyboard";
+
+document.addEventListener("DOMContentLoaded", () => {
+  new Keyboard({
+    theme: "hg-theme-default hg-theme-oetzi",
+    physicalKeyboardHighlight: true,
+    debug: true,
+    layout: {
+      default: [
+        "q w e r t z u i o p \u00FC {bksp}",
+        "a s d f g h j k l \u00F6 \u00E4",
+        "{space} y x c v b n m \u00DF {enter}",
+      ],
+    },
+    display: {
+      "{bksp}": "⟵", // "⌫⟵",
+      "{enter}": "↵", // "⏎↩↵⏎",
+      "{space}": "␣", // "␣",
+    },
+    // onChange: console.log,
+    // onKeyPress: console.log,
+  });
+});
-- 
GitLab