Multi-device support, dynamic grid adaptation, keyboard action

- Multi-device: OpenAllDecks(), GET /api/decks, per-deck PageManagers
- Dynamic grid: frontend adapts to connected device layout
- Keyboard action: new action type for sending key combos via wtype/xdotool
- Key recorder UI: click-based modifier toggles + single key capture
- Config: remove hardcoded maxKey validation
- Screensaver and auto-switch sync across all decks
This commit is contained in:
Maksim Totmin
2026-06-16 22:51:39 +07:00
parent 4c98a9d670
commit dfe6544686
8 changed files with 214 additions and 51 deletions
+22 -1
View File
@@ -10,6 +10,8 @@ document.addEventListener('alpine:init', () => {
toast: null,
displayOutputs: {},
isCapturingKey: false,
decks: [],
activeDeckSerial: '',
// ── Edit state ──
editing: null,
@@ -25,9 +27,22 @@ document.addEventListener('alpine:init', () => {
// ── Init ──
async init() {
await this.loadConfig()
await this.loadDecks()
setInterval(() => this.pollDisplayOutputs(), 3000)
},
async loadDecks() {
try {
const res = await fetch('/api/decks')
if (res.ok) {
this.decks = await res.json()
if (this.decks.length > 0 && !this.activeDeckSerial) {
this.activeDeckSerial = this.decks[0].serial
}
}
} catch (_) {}
},
async pollDisplayOutputs() {
if (this.view !== 'grid') return
try {
@@ -69,12 +84,18 @@ document.addEventListener('alpine:init', () => {
return this.pages.map(p => p.name)
},
get activeDeck() {
return this.decks.find(d => d.serial === this.activeDeckSerial)
|| { keys_x: 5, keys_y: 3, num_keys: 15 }
},
// ── Grid ──
get gridKeys() {
const page = this.currentPage
if (!page) return []
const keys = []
for (let i = 0; i < 15; i++) {
const n = this.activeDeck.num_keys
for (let i = 0; i < n; i++) {
const kc = page.keys.find(k => k.index === i)
keys.push({
index: i,