aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNick Coutsos <[email protected]>2022-04-28 23:52:20 -0400
committerNick Coutsos <[email protected]>2022-04-28 23:52:20 -0400
commit94efab0e1ac5cb65a85f47b376b111cf00989052 (patch)
treeef2cf0e76db3f0ff5108fb603cf3f87644e65806
parent7f6b1db5f9cc50eb3b30bfea95fe677641340723 (diff)
parent260f0c6f3dc841cbe5fbf290d2b802e8acdb20b6 (diff)
downloadkeymap-editor-94efab0e1ac5cb65a85f47b376b111cf00989052.tar.gz
keymap-editor-94efab0e1ac5cb65a85f47b376b111cf00989052.zip
Merge branch 'main' into react-app
-rw-r--r--README.md3
-rw-r--r--api/config.js26
-rw-r--r--api/index.js9
-rw-r--r--api/routes/application.js6
-rw-r--r--api/services/github/auth.js15
-rw-r--r--api/services/zmk/layout.js1
-rw-r--r--application/README.md57
-rw-r--r--application/components/key-value.vue2
-rw-r--r--application/components/key.vue6
-rw-r--r--application/components/keyboard-picker.vue2
-rw-r--r--application/data/keymap.json231
-rw-r--r--application/data/layers.json56
-rw-r--r--application/data/layout.json62
-rw-r--r--application/keycodes.js4
-rw-r--r--editor-screenshot.pngbin292465 -> 169899 bytes
-rw-r--r--index.js7
-rw-r--r--package-lock.json46
-rw-r--r--package.json3
18 files changed, 146 insertions, 390 deletions
diff --git a/README.md b/README.md
index ae3b1d6..20a3f39 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,9 @@ A browser app (plus NodeJS server) to edit ZMK keymaps. This is still in its
infancy and doesn't yet support parsing existing ZMK keymaps which limits some
kinds of functionality (mainly those involving custom/configured behaviours).
+**Try it live!** Go to the [keymap-editor] and try it out with the built-in
+[zmk-config-corne-demo] before setting up your own repo.
+
![Screenshot](editor-screenshot.png)
## Features
diff --git a/api/config.js b/api/config.js
new file mode 100644
index 0000000..ff9644f
--- /dev/null
+++ b/api/config.js
@@ -0,0 +1,26 @@
+const process = require('process')
+require('dotenv/config')
+
+const PORT = process.env.PORT || 8080
+const ENABLE_DEV_SERVER = process.env.ENABLE_DEV_SERVER
+const ENABLE_GITHUB = process.env.ENABLE_GITHUB
+const GITHUB_APP_NAME = process.env.GITHUB_APP_NAME
+const GITHUB_APP_PRIVATE_KEY = process.env.GITHUB_APP_PRIVATE_KEY
+const GITHUB_APP_ID = process.env.GITHUB_APP_ID
+const GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID
+const GITHUB_CLIENT_SECRET = process.env.GITHUB_CLIENT_SECRET
+const GITHUB_OAUTH_CALLBACK_URL = process.env.GITHUB_OAUTH_CALLBACK_URL
+const APP_BASE_URL = process.env.APP_BASE_URL
+
+module.exports = {
+ PORT,
+ ENABLE_DEV_SERVER,
+ ENABLE_GITHUB,
+ GITHUB_APP_NAME,
+ GITHUB_APP_PRIVATE_KEY,
+ GITHUB_APP_ID,
+ GITHUB_CLIENT_ID,
+ GITHUB_CLIENT_SECRET,
+ GITHUB_OAUTH_CALLBACK_URL,
+ APP_BASE_URL
+}
diff --git a/api/index.js b/api/index.js
index d45471c..9c7e63c 100644
--- a/api/index.js
+++ b/api/index.js
@@ -1,9 +1,9 @@
-require('dotenv/config')
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const morgan = require('morgan')
+const config = require('./config')
const applicationInit = require('./routes/application')
const keyboards = require('./routes/keyboards')
@@ -14,14 +14,15 @@ app.use(cors({
origin: 'https://nickcoutsos.github.io'
}))
-if (process.env.ENABLE_DEV_SERVER) {
+if (config.ENABLE_DEV_SERVER) {
applicationInit(app)
}
app.use(morgan('dev'))
-app.use(keyboards)
-app.use('/github', require('./routes/github'))
app.get('/health', (req, res) => res.sendStatus(200))
+app.use(keyboards)
+config.ENABLE_GITHUB && app.use('/github', require('./routes/github'))
+
module.exports = app
diff --git a/api/routes/application.js b/api/routes/application.js
index 3ecac87..add60be 100644
--- a/api/routes/application.js
+++ b/api/routes/application.js
@@ -3,6 +3,8 @@ const path = require('path')
const express = require('express')
const expressWs = require('express-ws')
+const config = require('../config')
+
const appDir = path.join(__dirname, '..', '..', 'application')
function init (app) {
@@ -12,8 +14,8 @@ function init (app) {
cwd: appDir,
env: Object.assign({}, process.env, {
ENABLE_LOCAL: true,
- ENABLE_GITHUB: true,
- GITHUB_APP_NAME: process.env.GITHUB_APP_NAME,
+ ENABLE_GITHUB: config.ENABLE_GITHUB,
+ GITHUB_APP_NAME: config.GITHUB_APP_NAME,
API_BASE_URL: 'http://localhost:8080',
APP_BASE_URL: 'http://localhost:8080/application'
})
diff --git a/api/services/github/auth.js b/api/services/github/auth.js
index 175e5f7..fcb3ec4 100644
--- a/api/services/github/auth.js
+++ b/api/services/github/auth.js
@@ -3,12 +3,13 @@ const path = require('path')
const jwt = require('jsonwebtoken')
const api = require('./api')
+const config = require('../../config')
const pemPath = path.join(__dirname, '..', '..', '..', 'private-key.pem')
-const privateKey = process.env.GITHUB_APP_PRIVATE_KEY || fs.readFileSync(pemPath)
+const privateKey = config.GITHUB_APP_PRIVATE_KEY || fs.readFileSync(pemPath)
function createAppToken () {
- return jwt.sign({ iss: process.env.GITHUB_APP_ID }, privateKey, {
+ return jwt.sign({ iss: config.GITHUB_APP_ID }, privateKey, {
algorithm: 'RS256',
expiresIn: '10m'
})
@@ -24,8 +25,8 @@ function createOauthFlowUrl () {
const redirectUrl = new URL('https://github.com/login/oauth/authorize')
redirectUrl.search = new URLSearchParams({
- client_id: process.env.GITHUB_CLIENT_ID,
- redirect_uri: process.env.GITHUB_OAUTH_CALLBACK_URL,
+ client_id: config.GITHUB_CLIENT_ID,
+ redirect_uri: config.GITHUB_OAUTH_CALLBACK_URL,
state: 'foo'
}).toString()
@@ -33,7 +34,7 @@ function createOauthFlowUrl () {
}
function createOauthReturnUrl (token) {
- const url = new URL(process.env.APP_BASE_URL)
+ const url = new URL(config.APP_BASE_URL)
url.search = new URLSearchParams({ token }).toString()
return url.toString()
}
@@ -46,8 +47,8 @@ function getOauthToken (code) {
Accept: 'application/json'
},
data: {
- client_id: process.env.GITHUB_CLIENT_ID,
- client_secret: process.env.GITHUB_CLIENT_SECRET,
+ client_id: config.GITHUB_CLIENT_ID,
+ client_secret: config.GITHUB_CLIENT_SECRET,
code
}
})
diff --git a/api/services/zmk/layout.js b/api/services/zmk/layout.js
index c914177..17bd7e4 100644
--- a/api/services/zmk/layout.js
+++ b/api/services/zmk/layout.js
@@ -36,7 +36,6 @@ function renderTable (layout, layer, opts={}) {
(row[i] || []).length
+ columnSeparator.length
+ (useQuotes ? 2 : 0) // wrapping with quotes adds 2 characters
- + (i === 6 ? 10 : 0) // sloppily add a little space between halves (right half starts at column 6)
))
))
diff --git a/application/README.md b/application/README.md
new file mode 100644
index 0000000..6b967e1
--- /dev/null
+++ b/application/README.md
@@ -0,0 +1,57 @@
+# Keymap Editor - Web Application
+
+This is a single page application currently written in Vue (but I'm starting to
+experiment with porting it to React) to integrate with the Keymap Editor API.
+
+It handles keyboard selection and rendering of parsed keymap data into a visual
+editor. This application is _aware_ of some of the particulars of ZMK, but it
+receives key bindings already parsed into a tree of values and parameters.
+
+## Building
+
+The easiest way to use this is the [hosted version](https://nickcoutsos.github.io/keymap-editor).
+The second easiest is locally, served up via the API itself (in the repo root,
+run `npm run dev` and open `http://localhost:8080` in your browser).
+
+If you must deploy this app to the web then you'll need to take care of building
+it. This requires some configuration, as seen in the [config module](./config.js).
+
+All configuration is provided via environment variables.
+
+Variable | Description
+------------------|-------------
+`API_BASE_URL` | Fully qualified publicly accessible URL of the backend API.
+`APP_BASE_URL` | Fully qualified publicly accessible URL of _this_ app.
+`GITHUB_APP_NAME` | The app name (slug?) of the GitHub app integration (only required if using with GitHub).
+`ENABLE_GITHUB` | Whether to enable fetching keyboard data from GitHub. Default is false, values `"1"`, `"on"`, `"yes"`, `"true"` are interpreted as `true`.
+`ENABLE_LOCAL` | Whether to enable fetching keyboard data from locally. Default is false, values `"1"`, `"on"`, `"yes"`, `"true"` are interpreted as `true`.
+
+_Note: choosing to use the GitHub integration in your own environment isn't a
+matter of flipping a switch, you will need to set up your own app in GitHub and
+configure your API accordingly._
+
+With these set you can run the npm build script, e.g.
+
+```bash
+export API_BASE_URL=...
+export APP_BASE_URL=...
+export GITHUB_APP_NAME=...
+export ENABLE_GITHUB=...
+export ENABLE_LOCAL=...
+npm run build
+```
+
+_(make sure you're in this directory, not the repository root!)_
+
+This will have webpack produce bundles in the `dist/` directory which you can
+deploy however you like.
+
+### Deploying to GitHub Pages
+
+On your GitHub repository's settings page, select _Pages_ in the sidebar. Pick a
+branch you want to serve the app from (I use `pages`) and choose the `/ (root)`
+directory. Check out that branch (I have another working repository locally for
+this) locally, or make a new orphaned branch if such a branch doesn't exist, and
+copy the contents of `dist/` to it. Commit and push to the GitHub remote.
+
+If you're not familiar with this it's worth reading up on the [GitHub Pages docs](https://docs.github.com/en/pages). \ No newline at end of file
diff --git a/application/components/key-value.vue b/application/components/key-value.vue
index 776a37b..1bc6b10 100644
--- a/application/components/key-value.vue
+++ b/application/components/key-value.vue
@@ -5,7 +5,7 @@
@click.stop="onSelect({ target: $event.target, codeIndex: index, code: value, param })"
>
<template v-if="source">
- <span v-if="source.faIcon" class="['fa', `fa-${source.faIcon}" />
+ <span v-if="source.faIcon" :class="['fa', `fa-${source.faIcon}`]" />
<template v-else>{{source.symbol || source.code}}</template>
</template>
<template v-else>⦸</template>
diff --git a/application/components/key.vue b/application/components/key.vue
index dcc6972..1c135bb 100644
--- a/application/components/key.vue
+++ b/application/components/key.vue
@@ -140,15 +140,17 @@ export default {
},
isSimple() {
const [first] = this.normalized.params
+ const icon = get(first, 'source.faIcon')
const symbol = get(first, 'source.symbol', get(first, 'source.code', ''))
- const shortSymbol = symbol.length === 1
+ const shortSymbol = !!icon || symbol.length === 1
const singleParam = this.normalized.params.length === 1
return singleParam && shortSymbol
},
isComplex() {
const [first] = this.normalized.params
+ const icon = get(first, 'source.faIcon')
const symbol = get(first, 'source.symbol', get(first, 'value', ''))
- const isLongSymbol = symbol.length > 4
+ const isLongSymbol = !icon && symbol.length > 4
const isMultiParam = this.behaviourParams.length > 1
const isNestedParam = get(first, 'params', []).length > 0
diff --git a/application/components/keyboard-picker.vue b/application/components/keyboard-picker.vue
index c3b6383..dec3e37 100644
--- a/application/components/keyboard-picker.vue
+++ b/application/components/keyboard-picker.vue
@@ -41,7 +41,7 @@ export default {
sourceChoices,
source: onlySource || (
sourceChoices.find(source => source.id === selectedSource)
- ? selectedSource.id
+ ? selectedSource
: null
)
}
diff --git a/application/data/keymap.json b/application/data/keymap.json
deleted file mode 100644
index c8678a6..0000000
--- a/application/data/keymap.json
+++ /dev/null
@@ -1,231 +0,0 @@
-{
- "keyboard": "handwired/dactyl_reduced",
- "keymap": "default",
- "layout": "LAYOUT",
- "layers": [
- [
- "KC_TAB",
- "KC_Q",
- "KC_W",
- "KC_E",
- "KC_R",
- "KC_T",
- "KC_Y",
- "KC_U",
- "KC_I",
- "KC_O",
- "KC_P",
- "KC_BSLS",
- "KC_CAPS",
- "KC_A",
- "KC_S",
- "KC_D",
- "KC_F",
- "KC_G",
- "KC_H",
- "KC_J",
- "KC_K",
- "KC_L",
- "LT(2,KC_SCLN)",
- "KC_QUOT",
- "KC_LSPO",
- "KC_Z",
- "KC_X",
- "KC_C",
- "KC_V",
- "KC_B",
- "KC_N",
- "KC_M",
- "KC_COMM",
- "KC_DOT",
- "KC_SLSH",
- "KC_RSPC",
- "KC_LCTL",
- "KC_LEFT",
- "KC_RGHT",
- "KC_DOWN",
- "KC_UP",
- "KC_LBRC",
- "KC_LCTL",
- "KC_BSPC",
- "KC_RALT",
- "KC_ESC",
- "KC_LALT",
- "KC_LGUI",
- "MO(1)",
- "KC_PGUP",
- "KC_ENT",
- "KC_SPC",
- "MO(2)",
- "KC_PGDN"
- ],
- [
- "KC_TRNS",
- "KC_TRNS",
- "KC_GRAVE",
- "KC_MINS",
- "KC_EQL",
- "KC_TRNS",
- "KC_LBRC",
- "KC_7",
- "KC_8",
- "KC_9",
- "KC_RBRC",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_KP_PLUS",
- "KC_4",
- "KC_5",
- "KC_6",
- "KC_KP_ASTERISK",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_KP_MINUS",
- "KC_1",
- "KC_2",
- "KC_3",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_0",
- "KC_DOT",
- "KC_TRNS",
- "KC_TRNS",
- "KC_LCMD",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_LSHIFT",
- "KC_TRNS"
- ],
- [
- "RESET",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "LCMD(KC_LBRC)",
- "LCMD(LSFT(KC_LBRC))",
- "LCMD(LSFT(KC_RBRC))",
- "LCMD(KC_RBRC)",
- "KC_TRNS",
- "KC_TRNS",
- "RGB_MODE_FORWARD",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_F8",
- "KC_F9",
- "KC_F7",
- "LCMD(LALT(KC_GRAVE))",
- "KC_TRNS",
- "KC_TRNS",
- "RGB_HUI",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC__VOLDOWN",
- "KC__VOLUP",
- "KC__MUTE",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS"
- ],
- [
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_F7",
- "KC_F8",
- "KC_F9",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_F4",
- "KC_F5",
- "KC_F6",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_F1",
- "KC_F2",
- "KC_F3",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS",
- "KC_TRNS"
- ]
- ]
-} \ No newline at end of file
diff --git a/application/data/layers.json b/application/data/layers.json
deleted file mode 100644
index 3edf07b..0000000
--- a/application/data/layers.json
+++ /dev/null
@@ -1,56 +0,0 @@
-[
- { "code": "KC_TAB" },
- { "code": "KC_Q" },
- { "code": "KC_W" },
- { "code": "KC_E" },
- { "code": "KC_R" },
- { "code": "KC_T" },
- { "code": "KC_Y" },
- { "code": "KC_U" },
- { "code": "KC_I" },
- { "code": "KC_O" },
- { "code": "KC_P" },
- { "code": "KC_BSLS" },
- { "code": "KC_CAPS" },
- { "code": "KC_A" },
- { "code": "KC_S" },
- { "code": "KC_D" },
- { "code": "KC_F" },
- { "code": "KC_G" },
- { "code": "KC_H" },
- { "code": "KC_J" },
- { "code": "KC_K" },
- { "code": "KC_L" },
- { "code": "LT(2, KC_SCLN)" },
- { "code": "KC_QUOT" },
- { "code": "KC_LSPO" },
- { "code": "KC_Z" },
- { "code": "KC_X" },
- { "code": "KC_C" },
- { "code": "KC_V" },
- { "code": "KC_B" },
- { "code": "KC_N" },
- { "code": "KC_M" },
- { "code": "KC_COMM" },
- { "code": "KC_DOT" },
- { "code": "KC_SLSH" },
- { "code": "KC_RSPC" },
- { "code": "KC_LCTL" },
- { "code": "KC_LEFT" },
- { "code": "KC_RGHT" },
- { "code": "KC_DOWN" },
- { "code": "KC_UP" },
- { "code": "KC_LBRC" },
- { "code": "KC_LCTL" },
- { "code": "KC_BSPC" },
- { "code": "KC_RALT" },
- { "code": "KC_ESC" },
- { "code": "KC_LALT" },
- { "code": "KC_LGUI" },
- { "code": "MO(1)" },
- { "code": "KC_PGUP" },
- { "code": "KC_ENT" },
- { "code": "KC_SPC" },
- { "code": "MO(2)" },
- { "code": "KC_PGDN" }
-]
diff --git a/application/data/layout.json b/application/data/layout.json
deleted file mode 100644
index 6095cd6..0000000
--- a/application/data/layout.json
+++ /dev/null
@@ -1,62 +0,0 @@
-[
- { "label": "L00", "row": 0, "col": 0, "x": 0, "y": 0.5 },
- { "label": "L01", "row": 0, "col": 1, "x": 1, "y": 0.5 },
- { "label": "L02", "row": 0, "col": 2, "x": 2, "y": 0.2 },
- { "label": "L03", "row": 0, "col": 3, "x": 3, "y": 0 },
- { "label": "L04", "row": 0, "col": 4, "x": 4, "y": 0.25 },
- { "label": "L05", "row": 0, "col": 5, "x": 5, "y": 0.25 },
- { "label": "R06", "row": 0, "col": 6, "x": 13, "y": 0.25 },
- { "label": "R07", "row": 0, "col": 7, "x": 14, "y": 0.25 },
- { "label": "R08", "row": 0, "col": 8, "x": 15, "y": 0 },
- { "label": "R09", "row": 0, "col": 9, "x": 16, "y": 0.2 },
- { "label": "R0A", "row": 0, "col": 10, "x": 17, "y": 0.5 },
- { "label": "R0B", "row": 0, "col": 11, "x": 18, "y": 0.5 },
-
- { "label": "L10", "row": 1, "col": 0, "x": 0, "y": 1.5 },
- { "label": "L11", "row": 1, "col": 1, "x": 1, "y": 1.5 },
- { "label": "L12", "row": 1, "col": 2, "x": 2, "y": 1.2 },
- { "label": "L13", "row": 1, "col": 3, "x": 3, "y": 1 },
- { "label": "L14", "row": 1, "col": 4, "x": 4, "y": 1.25 },
- { "label": "L15", "row": 1, "col": 5, "x": 5, "y": 1.25 },
- { "label": "R16", "row": 1, "col": 6, "x": 13, "y": 1.25 },
- { "label": "R17", "row": 1, "col": 7, "x": 14, "y": 1.25 },
- { "label": "R18", "row": 1, "col": 8, "x": 15, "y": 1 },
- { "label": "R19", "row": 1, "col": 9, "x": 16, "y": 1.2 },
- { "label": "R1A", "row": 1, "col": 10, "x": 17, "y": 1.5 },
- { "label": "R1B", "row": 1, "col": 11, "x": 18, "y": 1.5 },
-
- { "label": "L20", "row": 2, "col": 0, "x": 0, "y": 2.5 },
- { "label": "L21", "row": 2, "col": 1, "x": 1, "y": 2.5 },
- { "label": "L22", "row": 2, "col": 2, "x": 2, "y": 2.2 },
- { "label": "L23", "row": 2, "col": 3, "x": 3, "y": 2 },
- { "label": "L24", "row": 2, "col": 4, "x": 4, "y": 2.25 },
- { "label": "L25", "row": 2, "col": 5, "x": 5, "y": 2.25 },
- { "label": "R26", "row": 2, "col": 6, "x": 13, "y": 2.25 },
- { "label": "R27", "row": 2, "col": 7, "x": 14, "y": 2.25 },
- { "label": "R28", "row": 2, "col": 8, "x": 15, "y": 2 },
- { "label": "R29", "row": 2, "col": 9, "x": 16, "y": 2.2 },
- { "label": "R2A", "row": 2, "col": 10, "x": 17, "y": 2.5 },
- { "label": "R2B", "row": 2, "col": 11, "x": 18, "y": 2.5 },
-
- { "label": "L32", "row": 3, "col": 2, "x": 2, "y": 3.2 },
- { "label": "L33", "row": 3, "col": 3, "x": 3, "y": 3 },
- { "label": "L34", "row": 3, "col": 4, "x": 4, "y": 3.25 },
- { "label": "R37", "row": 3, "col": 7, "x": 14, "y": 3.25 },
- { "label": "R38", "row": 3, "col": 8, "x": 15, "y": 3 },
- { "label": "R39", "row": 3, "col": 9, "x": 16, "y": 3.2 },
-
- { "label": "L42", "row": 4, "col": 4, "x": 6.5, "y": 2, "r": 20, "rx": 4.5, "ry": 3 },
- { "label": "L43", "row": 4, "col": 5, "x": 7.5, "y": 2, "r": 20, "rx": 4.5, "ry": 3 },
- { "label": "R48", "row": 4, "col": 6, "x": 10.5, "y": 2, "r": -20, "rx": 14.5, "ry": 3 },
- { "label": "R49", "row": 4, "col": 7, "x": 11.5, "y": 2, "r": -20, "rx": 14.5, "ry": 3 },
-
- { "label": "L40", "row": 5, "col": 3, "x": 5.5, "y": 3, "r": 20, "rx": 4.5, "ry": 3, "h": 2 },
- { "label": "L41", "row": 5, "col": 4, "x": 6.5, "y": 3, "r": 20, "rx": 4.5, "ry": 3, "h": 2 },
- { "label": "L44", "row": 5, "col": 5, "x": 7.5, "y": 3, "r": 20, "rx": 4.5, "ry": 3 },
- { "label": "R47", "row": 5, "col": 6, "x": 10.5, "y": 3, "r": -20, "rx": 14.5, "ry": 3 },
- { "label": "R4A", "row": 5, "col": 7, "x": 11.5, "y": 3, "r": -20, "rx": 14.5, "ry": 3, "h": 2 },
- { "label": "R4B", "row": 5, "col": 8, "x": 12.5, "y": 3, "r": -20, "rx": 14.5, "ry": 3, "h": 2 },
-
- { "label": "L45", "row": 6, "col": 5, "x": 7.5, "y": 4, "r": 20, "rx": 4.5, "ry": 3 },
- { "label": "R46", "row": 6, "col": 6, "x": 10.5, "y": 4, "r": -20, "rx": 14.5, "ry": 3 }
-] \ No newline at end of file
diff --git a/application/keycodes.js b/application/keycodes.js
index 743bc76..7a65f5b 100644
--- a/application/keycodes.js
+++ b/application/keycodes.js
@@ -18,10 +18,10 @@ function normalizeZmkKeycodes (keycodes) {
const fnPattern = /^(.+?)\((code)\)$/
return keycodes.reduce((keycodes, keycode) => {
- const { description, context, symbol } = keycode
+ const { description, context, symbol, faIcon } = keycode
const aliases = keycode.names.filter(name => !name.match(fnPattern))
const fnCode = keycode.names.map(name => name.match(fnPattern)).filter(v => !!v)[0]
- const base = { aliases, description, context, symbol: symbol || shortestAlias(aliases), params: [] }
+ const base = { aliases, description, context, faIcon, symbol: symbol || shortestAlias(aliases), params: [] }
for (let code of aliases) {
keycodes.push(Object.assign({}, base, {
diff --git a/editor-screenshot.png b/editor-screenshot.png
index 5d64bbf..86113cf 100644
--- a/editor-screenshot.png
+++ b/editor-screenshot.png
Binary files differ
diff --git a/index.js b/index.js
index 772caf4..95fcd8c 100644
--- a/index.js
+++ b/index.js
@@ -1,6 +1,5 @@
-const process = require('process')
const api = require('./api')
+const config = require('./api/config')
-const PORT = process.env.PORT || 8080
-api.listen(PORT)
-console.log('listening on', PORT)
+api.listen(config.PORT)
+console.log('listening on', config.PORT)
diff --git a/package-lock.json b/package-lock.json
index 1df314c..0ad2ad6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
"axios": "^0.21.4",
"body-parser": "^1.19.0",
"cors": "^2.8.5",
+ "cross-env": "^7.0.3",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"express-ws": "^4.0.0",
@@ -448,11 +449,27 @@
"node": ">= 0.10"
}
},
+ "node_modules/cross-env": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
+ "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
+ "dependencies": {
+ "cross-spawn": "^7.0.1"
+ },
+ "bin": {
+ "cross-env": "src/bin/cross-env.js",
+ "cross-env-shell": "src/bin/cross-env-shell.js"
+ },
+ "engines": {
+ "node": ">=10.14",
+ "npm": ">=6",
+ "yarn": ">=1"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -1682,8 +1699,7 @@
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
- "dev": true
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"node_modules/js-yaml": {
"version": "4.1.0",
@@ -2154,7 +2170,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -2354,7 +2369,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
"dependencies": {
"shebang-regex": "^3.0.0"
},
@@ -2366,7 +2380,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -2603,7 +2616,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
"dependencies": {
"isexe": "^2.0.0"
},
@@ -2991,11 +3003,18 @@
"vary": "^1"
}
},
+ "cross-env": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
+ "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
+ "requires": {
+ "cross-spawn": "^7.0.1"
+ }
+ },
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
"requires": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -3899,8 +3918,7 @@
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
- "dev": true
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"js-yaml": {
"version": "4.1.0",
@@ -4274,8 +4292,7 @@
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
},
"path-parse": {
"version": "1.0.7",
@@ -4426,7 +4443,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
"requires": {
"shebang-regex": "^3.0.0"
}
@@ -4434,8 +4450,7 @@
"shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
},
"side-channel": {
"version": "1.0.4",
@@ -4609,7 +4624,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
"requires": {
"isexe": "^2.0.0"
}
diff --git a/package.json b/package.json
index e428342..2c54a91 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"scripts": {
"postinstall": "cd application && npm install",
"start": "node index.js",
- "dev": "ENABLE_DEV_SERVER=true node index.js",
+ "dev": "cross-env ENABLE_DEV_SERVER=true node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
@@ -16,6 +16,7 @@
"axios": "^0.21.4",
"body-parser": "^1.19.0",
"cors": "^2.8.5",
+ "cross-env": "^7.0.3",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"express-ws": "^4.0.0",