Compare commits
9 Commits
d0251550dd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 76c823250c | |||
| ee7e8ef33c | |||
| 61adf7de16 | |||
| 23cf41eea4 | |||
| edf697744b | |||
| 0907ae5385 | |||
| aaced3ccf5 | |||
| bce365f4fc | |||
| 1efdb9fb5c |
@@ -12,6 +12,6 @@ COPY . .
|
|||||||
|
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
EXPOSE 8083
|
EXPOSE 8084
|
||||||
|
|
||||||
CMD [ "npm", "run", "preview" ]
|
CMD [ "npm", "run", "preview" ]
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/matrix-mod-logo.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Matrix 1000 Patch Selector</title>
|
<title>Matrix 1000 Patch Selector</title>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
1858
package-lock.json
generated
1858
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
29
package.json
29
package.json
@@ -6,24 +6,25 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
"lint": "eslint .",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^18.3.1",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^18.3.1"
|
"react-dom": "^19.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.3.3",
|
"@eslint/js": "^9.20.0",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react": "^19.0.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.15.0",
|
"@types/react-dom": "^19.0.3",
|
||||||
"@typescript-eslint/parser": "^7.15.0",
|
"@vitejs/plugin-react-swc": "^3.8.0",
|
||||||
"@vitejs/plugin-react-swc": "^3.5.0",
|
"eslint": "^9.20.1",
|
||||||
"eslint": "^8.57.0",
|
"eslint-plugin-react-hooks": "^5.1.0",
|
||||||
"eslint-plugin-react-hooks": "^4.6.2",
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"eslint-plugin-react-refresh": "^0.4.7",
|
"globals": "^15.15.0",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "~5.7.3",
|
||||||
"vite": "^5.3.4",
|
"typescript-eslint": "^8.24.0",
|
||||||
"webmidi": "^3.1.9"
|
"vite": "^6.1.0",
|
||||||
|
"webmidi": "^3.1.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
public/matrix-mod-logo.svg
Normal file
14
public/matrix-mod-logo.svg
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 612 792">
|
||||||
|
<!-- Generator: Adobe Illustrator 29.2.1, SVG Export Plug-In . SVG Version: 2.1.0 Build 116) -->
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.st0 {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path d="M241.1,512.1c0,16.9-13.7,30.5-30.5,30.5s-30.5-13.7-30.5-30.5,13.7-30.5,30.5-30.5,30.5,13.7,30.5,30.5ZM210.5,484.5c-8.9,0-10.3,12.3-10.3,27.6s.6,27.6,10.3,27.6,10.3-12.3,10.3-27.6-1.4-27.6-10.3-27.6Z"/>
|
||||||
|
<polygon points="232.2 482.5 235.5 485.8 230.1 538 226.6 541.9 242 541.9 239.2 537.1 242.9 503.4 255.9 534.4 266.2 542.4 267.8 542.4 280.5 503.4 284.5 539 282.4 541.9 303.5 541.9 300.9 536.8 295.8 486.4 297.9 482.5 278.4 482.5 266 517.8 252.7 482.5 232.2 482.5"/>
|
||||||
|
<rect class="st0" x="178" y="447.9" width="128" height="128"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 864 B |
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
49
src/App.css
49
src/App.css
@@ -1,63 +1,28 @@
|
|||||||
#root {
|
#root {
|
||||||
max-width: 1280px;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 2rem;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
|
||||||
height: 6em;
|
|
||||||
padding: 1.5em;
|
|
||||||
will-change: filter;
|
|
||||||
transition: filter 300ms;
|
|
||||||
}
|
|
||||||
.logo:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #646cffaa);
|
|
||||||
}
|
|
||||||
.logo.react:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes logo-spin {
|
|
||||||
from {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
a:nth-of-type(2) .logo {
|
|
||||||
animation: logo-spin infinite 20s linear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
padding: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.read-the-docs {
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selections-container {
|
.selections-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.option-box {
|
.option-box {
|
||||||
width: 4vh;
|
width: 4.2cqh;
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected-option {
|
.selected-option {
|
||||||
background-color: black;
|
background-color: lightslategrey;
|
||||||
font-size: larger;
|
font-weight: 800;
|
||||||
|
font-size: 2cqh;
|
||||||
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unselected {
|
.unselected {
|
||||||
font-size: medium;
|
font-weight: 600;
|
||||||
|
font-size: 2cqh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.midi-settings-container {
|
.midi-settings-container {
|
||||||
|
|||||||
16
src/App.tsx
16
src/App.tsx
@@ -5,11 +5,14 @@ import PatchSquare from "./PatchSquare.tsx";
|
|||||||
import {WebMidi, Output} from "webmidi";
|
import {WebMidi, Output} from "webmidi";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [bankNumber, setBankNumber] = useState(0)
|
let initBankNumber = parseInt(localStorage.getItem("bank-number")??"0")
|
||||||
const [patchNumber, setPatchNumber] = useState(0)
|
let initPatchNumber = parseInt(localStorage.getItem("patch-number")??"0")
|
||||||
|
let initMidiChannel = parseInt(localStorage.getItem("midi-channel")??"1")
|
||||||
|
const [bankNumber, setBankNumber] = useState(initBankNumber)
|
||||||
|
const [patchNumber, setPatchNumber] = useState(initPatchNumber)
|
||||||
const [midiDeviceMap, setMidiDeviceMap] = useState<Map<string, Output>>(new Map())
|
const [midiDeviceMap, setMidiDeviceMap] = useState<Map<string, Output>>(new Map())
|
||||||
const [selectedMidiDevice, setSelectedMidiDevice] = useState<string>()
|
const [selectedMidiDevice, setSelectedMidiDevice] = useState<string>()
|
||||||
const [selectedMidiChannel, setSelectedMidiChannel] = useState<number>(1)
|
const [selectedMidiChannel, setSelectedMidiChannel] = useState<number>(initMidiChannel)
|
||||||
|
|
||||||
function connect() {
|
function connect() {
|
||||||
WebMidi.enable()
|
WebMidi.enable()
|
||||||
@@ -47,10 +50,12 @@ function App() {
|
|||||||
|
|
||||||
function handleBankSelect(selection: number) {
|
function handleBankSelect(selection: number) {
|
||||||
setBankNumber(selection)
|
setBankNumber(selection)
|
||||||
|
localStorage.setItem("bank-number", selection.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePatchSelect(selection: number) {
|
function handlePatchSelect(selection: number) {
|
||||||
setPatchNumber(selection)
|
setPatchNumber(selection)
|
||||||
|
localStorage.setItem("patch-number", selection.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendPatchNumber() {
|
function sendPatchNumber() {
|
||||||
@@ -112,6 +117,7 @@ function App() {
|
|||||||
|
|
||||||
function handleMidiChannelSelect(e: ChangeEvent<HTMLSelectElement>) {
|
function handleMidiChannelSelect(e: ChangeEvent<HTMLSelectElement>) {
|
||||||
setSelectedMidiChannel(parseInt(e.target.value))
|
setSelectedMidiChannel(parseInt(e.target.value))
|
||||||
|
localStorage.setItem("midi-channel", e.target.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -123,7 +129,9 @@ function App() {
|
|||||||
<select onChange={handleMidiDeviceSelect}>{midiDeviceOptions()}</select>
|
<select onChange={handleMidiDeviceSelect}>{midiDeviceOptions()}</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<select onChange={handleMidiChannelSelect}>{midiChannelOptions()}</select>
|
<select value={selectedMidiChannel} onChange={handleMidiChannelSelect}>
|
||||||
|
{midiChannelOptions()}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
|
||||||
color-scheme: light dark;
|
color-scheme: light dark;
|
||||||
color: rgba(255, 255, 255, 0.87);
|
color: rgba(255, 255, 255, 0.6);
|
||||||
background-color: #242424;
|
background-color: #000000;
|
||||||
|
|
||||||
font-synthesis: none;
|
font-synthesis: none;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
|
|||||||
@@ -8,11 +8,13 @@ export default defineConfig({
|
|||||||
preview: {
|
preview: {
|
||||||
port: 8084,
|
port: 8084,
|
||||||
strictPort: true,
|
strictPort: true,
|
||||||
|
host: '0.0.0.0',
|
||||||
|
allowedHosts: ['matrix.halfbinary.net']
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
port: 8084,
|
port: 8084,
|
||||||
strictPort: true,
|
strictPort: true,
|
||||||
host: true,
|
host: true,
|
||||||
//origin: "http://0.0.0.0:8084",
|
//origin: "http://0.0.0.0:8084",
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user