From 05d5d4509905f04947acd318c0e2879b65b427ad Mon Sep 17 00:00:00 2001 From: TheoryOfNekomata Date: Tue, 9 Apr 2024 22:56:26 +0800 Subject: [PATCH] Update layout Add indicators, hide controls on mouseout, and put pedal board in bottom. --- docs/screenshots/screenshot-00.png | Bin 26391 -> 17197 bytes package.json | 2 + pnpm-lock.yaml | 296 +++++++++++++++++++++++++++++ postcss.config.js | 6 + src/main/index.ts | 15 +- src/renderer/src/App.tsx | 192 +++++++++++++------ src/renderer/src/assets/main.css | 73 +------ tailwind.config.js | 8 + 8 files changed, 457 insertions(+), 135 deletions(-) create mode 100644 postcss.config.js create mode 100644 tailwind.config.js diff --git a/docs/screenshots/screenshot-00.png b/docs/screenshots/screenshot-00.png index 7d8f680b7651a88a7c506c827a92d776456350b7..3a4dc3feb8481415351ad807a6c82114b105f333 100644 GIT binary patch literal 17197 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 A82|tP diff --git a/package.json b/package.json index aed400d..c64c1c9 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@types/react": "^18.2.48", "@types/react-dom": "^18.2.18", "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.4.19", "electron": "^28.2.0", "electron-builder": "^24.9.1", "electron-vite": "^2.0.0", @@ -42,6 +43,7 @@ "prettier": "^3.2.4", "react": "^18.2.0", "react-dom": "^18.2.0", + "tailwindcss": "^3.4.3", "typescript": "^5.3.3", "vite": "^5.0.12" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2747929..322a9fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,6 +40,9 @@ devDependencies: '@vitejs/plugin-react': specifier: ^4.2.1 version: 4.2.1(vite@5.2.8) + autoprefixer: + specifier: ^10.4.19 + version: 10.4.19(postcss@8.4.38) electron: specifier: ^28.2.0 version: 28.2.10 @@ -64,6 +67,9 @@ devDependencies: react-dom: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) + tailwindcss: + specifier: ^3.4.3 + version: 3.4.3 typescript: specifier: ^5.3.3 version: 5.4.4 @@ -82,6 +88,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /@alloc/quick-lru@5.2.0: + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + dev: true + /@ampproject/remapping@2.3.0: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -1507,6 +1518,18 @@ packages: engines: {node: '>=12'} dev: true + /any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + dev: true + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + /app-builder-bin@4.0.0: resolution: {integrity: sha512-xwdG0FJPQMe0M0UA4Tz0zEB8rBJTRA5a476ZawAqiBkMv16GRK5xpXThOjMaEOFnZ6zabejjG4J3da0SXG63KA==} dev: true @@ -1596,6 +1619,10 @@ packages: zip-stream: 4.1.1 dev: true + /arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: true + /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -1721,6 +1748,22 @@ packages: engines: {node: '>= 4.0.0'} dev: true + /autoprefixer@10.4.19(postcss@8.4.38): + resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.23.0 + caniuse-lite: 1.0.30001607 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.0.0 + postcss: 8.4.38 + postcss-value-parser: 4.2.0 + dev: true + /available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -1737,6 +1780,11 @@ packages: requiresBuild: true dev: true + /binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + dev: true + /bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} dependencies: @@ -1890,6 +1938,11 @@ packages: engines: {node: '>=6'} dev: true + /camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + dev: true + /caniuse-lite@1.0.30001607: resolution: {integrity: sha512-WcvhVRjXLKFB/kmOFVwELtMxyhq3iM/MvmXcyCe2PNf166c39mptscOc/45TTS96n2gpNV2z7+NakArTWZCQ3w==} dev: true @@ -1911,6 +1964,21 @@ packages: supports-color: 7.2.0 dev: true + /chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -1977,6 +2045,11 @@ packages: delayed-stream: 1.0.0 dev: true + /commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + dev: true + /commander@5.1.0: resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} engines: {node: '>= 6'} @@ -2053,6 +2126,12 @@ packages: which: 2.0.2 dev: true + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + dev: true + /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} dev: true @@ -2135,6 +2214,10 @@ packages: requiresBuild: true optional: true + /didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dev: true + /dir-compare@3.3.0: resolution: {integrity: sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg==} dependencies: @@ -2149,6 +2232,10 @@ packages: path-type: 4.0.0 dev: true + /dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dev: true + /dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3): resolution: {integrity: sha512-rcJUkMfnJpfCboZoOOPf4L29TRtEieHNOeAbYPWPxlaBw/Z1RKrRA86dOI9rwaI4tQSc/RD82zTNHprfUHXsoQ==} dependencies: @@ -2805,6 +2892,10 @@ packages: mime-types: 2.1.35 dev: true + /fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + dev: true + /fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} dev: true @@ -3174,6 +3265,13 @@ packages: has-bigints: 1.0.2 dev: true + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.3.0 + dev: true + /is-boolean-object@1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} @@ -3383,6 +3481,11 @@ packages: minimatch: 3.1.2 dev: true + /jiti@1.21.0: + resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} + hasBin: true + dev: true + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3465,6 +3568,20 @@ packages: type-check: 0.4.0 dev: true + /lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + dev: true + + /lilconfig@3.1.1: + resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==} + engines: {node: '>=14'} + dev: true + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true + /locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -3674,6 +3791,14 @@ packages: /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + /mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: true + /nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -3699,6 +3824,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + dev: true + /normalize-url@6.1.0: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} @@ -3708,6 +3838,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + dev: true + /object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} dev: true @@ -3854,6 +3989,16 @@ packages: engines: {node: '>=8.6'} dev: true + /pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + dev: true + + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + dev: true + /plist@3.1.0: resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} engines: {node: '>=10.4.0'} @@ -3868,6 +4013,67 @@ packages: engines: {node: '>= 0.4'} dev: true + /postcss-import@15.1.0(postcss@8.4.38): + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + postcss: 8.4.38 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + dev: true + + /postcss-js@4.0.1(postcss@8.4.38): + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.38 + dev: true + + /postcss-load-config@4.0.2(postcss@8.4.38): + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 3.1.1 + postcss: 8.4.38 + yaml: 2.4.1 + dev: true + + /postcss-nested@6.0.1(postcss@8.4.38): + resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + dependencies: + postcss: 8.4.38 + postcss-selector-parser: 6.0.16 + dev: true + + /postcss-selector-parser@6.0.16: + resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + + /postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + dev: true + /postcss@8.4.38: resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} engines: {node: ^10 || ^12 || >=14} @@ -3963,6 +4169,12 @@ packages: dependencies: loose-envify: 1.4.0 + /read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + dependencies: + pify: 2.3.0 + dev: true + /read-config-file@6.3.2: resolution: {integrity: sha512-M80lpCjnE6Wt6zb98DoW8WHR09nzMSpu8XHtPkiTHrJ5Az9CybfeQhTJ8D7saeBHpGhLPIVyA8lcL6ZmdKwY6Q==} engines: {node: '>=12.0.0'} @@ -4002,6 +4214,13 @@ packages: minimatch: 5.1.6 dev: true + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + /reflect.getprototypeof@1.0.6: resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} engines: {node: '>= 0.4'} @@ -4038,6 +4257,15 @@ packages: engines: {node: '>=4'} dev: true + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + /resolve@2.0.0-next.5: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true @@ -4383,6 +4611,20 @@ packages: engines: {node: '>=8'} dev: true + /sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + commander: 4.1.1 + glob: 10.3.12 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + dev: true + /sumchecker@3.0.1: resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} engines: {node: '>= 8.0'} @@ -4418,6 +4660,37 @@ packages: tslib: 2.6.2 dev: true + /tailwindcss@3.4.3: + resolution: {integrity: sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.0 + lilconfig: 2.1.0 + micromatch: 4.0.5 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.0 + postcss: 8.4.38 + postcss-import: 15.1.0(postcss@8.4.38) + postcss-js: 4.0.1(postcss@8.4.38) + postcss-load-config: 4.0.2(postcss@8.4.38) + postcss-nested: 6.0.1(postcss@8.4.38) + postcss-selector-parser: 6.0.16 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + dev: true + /tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} @@ -4452,6 +4725,19 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + dev: true + + /thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + dev: true + /tiny-typed-emitter@2.1.0: resolution: {integrity: sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==} dev: false @@ -4494,6 +4780,10 @@ packages: typescript: 5.4.4 dev: true + /ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + dev: true + /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} dev: true @@ -4754,6 +5044,12 @@ packages: /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + /yaml@2.4.1: + resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} + engines: {node: '>= 14'} + hasBin: true + dev: true + /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/src/main/index.ts b/src/main/index.ts index a796434..00e7607 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,6 +1,6 @@ import { app, shell, BrowserWindow, ipcMain } from 'electron' import { join } from 'path' -import { readFile, stat, writeFile } from "fs/promises"; +import { readFile, stat, writeFile } from 'fs/promises' import { electronApp, optimizer, is } from '@electron-toolkit/utils' import icon from '../../resources/icon.png?asset' @@ -18,7 +18,6 @@ const defaultConfig: Config = { const configPath = './config.json' const naturalKeyWidth = 20 -const pedalBoardWidth = 239 const height = 175 const getNaturalKeys = (range: string): number => { @@ -47,7 +46,7 @@ const getNaturalKeys = (range: string): number => { function createWindow(config: Config): void { // Create the browser window. const naturalKeys = getNaturalKeys(config.range) - const width = naturalKeys * naturalKeyWidth + pedalBoardWidth + const width = naturalKeys * naturalKeyWidth + Number(config.scaleFactor) const mainWindow = new BrowserWindow({ width, height, @@ -127,9 +126,17 @@ app.whenReady().then(async () => { await writeFile(configPath, JSON.stringify(effectiveConfig)) }) - ipcMain.on('scalefactorchange', async (_event, value) => { + ipcMain.on('scalefactorchange', async (event, value) => { effectiveConfig.scaleFactor = value await writeFile(configPath, JSON.stringify(effectiveConfig)) + await writeFile(configPath, JSON.stringify(effectiveConfig)) + const webContents = event.sender + const win = BrowserWindow.fromWebContents(webContents) + if (!win) { + return + } + win.close() + createWindow(effectiveConfig) }) ipcMain.on('rangechange', async (event, value) => { diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 6a454f9..0a52877 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -18,6 +18,7 @@ const RANGES = { 'E1-E7': '28|100', 'E1-G7': '28|103', 'A0-C8': '21|108', + 'C0-B9': '12|119', 'Full MIDI': '0|127' } @@ -31,6 +32,25 @@ const App: React.FC = () => { const [scaleFactor, setScaleFactor] = React.useState(() => Number(new URLSearchParams(window.location.search).get('scaleFactor') || 1) ) + const [currentDeviceActive, setCurrentDeviceActive] = React.useState([ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ]) + const currentDeviceActiveTimeoutRef = React.useRef() const [devicesLoadedTimestamp, setDevicesLoadedTimestamp] = React.useState() const [midiAccess, setMidiAccess] = React.useState() @@ -116,11 +136,29 @@ const App: React.FC = () => { return } + const addActivity = (channel: number) => { + setCurrentDeviceActive((oldCurrentDeviceActive) => + oldCurrentDeviceActive.map((state, i) => (i === channel ? true : state)) + ) + window.clearTimeout(currentDeviceActiveTimeoutRef.current) + currentDeviceActiveTimeoutRef.current = window.setTimeout(() => { + setCurrentDeviceActive((oldCurrentDeviceActive) => + oldCurrentDeviceActive.map((state, i) => (i === channel ? false : state)) + ) + }, 100) + } + const midiEvent = e as MidiMessageEvent const [messageType, param1, param2] = midiEvent.data + const channel = messageType & 0b00001111 + addActivity(channel) switch (messageType & 0b11110000) { case 0b10110000: { + if (channel === 9) { + return + } + const controlNumber = param1 const value = param2 @@ -140,7 +178,6 @@ const App: React.FC = () => { return } case 0b10010000: { - const channel = messageType & 0b00001111 const keyNumber = param1 const velocity = param2 @@ -161,7 +198,6 @@ const App: React.FC = () => { return } case 0b10000000: { - const channel = messageType & 0b00001111 const keyNumber = param1 setKeyChannels((oldKeyChannels) => { @@ -187,65 +223,14 @@ const App: React.FC = () => { typeof midiAccess?.inputs !== 'undefined' ? Array.from(midiAccess.inputs) : undefined return ( -
-
-
- -
-
- -
-
-
- -
-
- -
-
-
-
-
+
+
+
{ }} />
-
+
+
+
+ +
+
key === queryDeviceKey)?.[1]?.state === 'connected' + ? 1 + : 0.25 + }} + /> + {currentDeviceActive.map((a, i) => ( +
+ ))} +
+
+
{
+
+
+ +
+
+
+ +
+
+ +
+
+
) diff --git a/src/renderer/src/assets/main.css b/src/renderer/src/assets/main.css index 500e534..8f85992 100644 --- a/src/renderer/src/assets/main.css +++ b/src/renderer/src/assets/main.css @@ -1,3 +1,6 @@ +@tailwind base; +@tailwind utilities; + :root { height: 100%; width: 100%; @@ -9,77 +12,9 @@ body { height: 100%; width: 100%; margin: 0; - font-family: sans-serif; + font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } #root { display: contents; } - -.flex { - display: flex; -} - -.flex-col { - flex-direction: column; -} - -.items-stretch { - align-items: stretch; -} - -.justify-center { - justify-content: center; -} - -.h-full { - height: 100%; -} - -.flex-shrink-0 { - flex-shrink: 0; -} - -.items-center { - align-items: center; -} - -.w-full { - width: 100%; -} - -.gap-8 { - gap: 2rem; -} - -.flex-auto { - flex: auto; -} - -.bg-black { - background-color: black; -} - -select { - color: inherit; - font: inherit; - border: 0; -} - -.h-12 { - height: 3rem; -} - -.px-4 { - padding-left: 1rem; - padding-right: 1rem; -} - -.px-8 { - padding-left: 2rem; - padding-right: 2rem; -} - -.gap-4 { - gap: 1rem; -} diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..cc8edc3 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ['./src/renderer/**/*.tsx'], + theme: { + extend: {} + }, + plugins: [] +}