feat: ajout dropdowns gain par route dans matrice routing
- Dropdown gain -12dB à +6dB pour chaque route active - Interface visuelle améliorée (checkbox + gain) - Gestion gains input->group et group->output - Sauvegarde gains dans config.yaml - Design responsive mobile
This commit is contained in:
@@ -81,7 +81,7 @@ define(['./workbox-290dd570'], (function (workbox) { 'use strict';
|
|||||||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||||
}, {
|
}, {
|
||||||
"url": "index.html",
|
"url": "index.html",
|
||||||
"revision": "0.pjhah2a023"
|
"revision": "0.guj84039cv8"
|
||||||
}], {});
|
}], {});
|
||||||
workbox.cleanupOutdatedCaches();
|
workbox.cleanupOutdatedCaches();
|
||||||
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -84,15 +84,25 @@
|
|||||||
|
|
||||||
.matrix-cell {
|
.matrix-cell {
|
||||||
background: var(--color-bg);
|
background: var(--color-bg);
|
||||||
padding: var(--spacing-md);
|
padding: var(--spacing-sm);
|
||||||
min-height: 40px;
|
min-height: 60px;
|
||||||
min-width: 60px;
|
min-width: 80px;
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: var(--spacing-xs);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-checkbox {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 30px;
|
||||||
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: relative;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.matrix-cell:hover {
|
.matrix-cell:hover {
|
||||||
@@ -114,6 +124,25 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gain-select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
color: var(--color-text);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gain-select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: rgba(255, 255, 255, 0.6);
|
||||||
|
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1024px) {
|
||||||
.matrix-header-cell,
|
.matrix-header-cell,
|
||||||
.matrix-label-cell {
|
.matrix-label-cell {
|
||||||
@@ -123,10 +152,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.matrix-cell {
|
.matrix-cell {
|
||||||
min-width: 50px;
|
min-width: 70px;
|
||||||
min-height: 35px;
|
min-height: 50px;
|
||||||
padding: var(--spacing-sm);
|
padding: var(--spacing-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gain-select {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
padding: 3px 6px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
@@ -147,11 +181,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.matrix-cell {
|
.matrix-cell {
|
||||||
min-width: 40px;
|
min-width: 65px;
|
||||||
min-height: 30px;
|
min-height: 45px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkmark {
|
.checkmark {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gain-select {
|
||||||
|
font-size: 0.65rem;
|
||||||
|
padding: 2px 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,39 @@ function AudioRoutingMatrix({ groups, channelNames }) {
|
|||||||
return routing.groupToOutput[groupId]?.includes(outputId) || false;
|
return routing.groupToOutput[groupId]?.includes(outputId) || false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getGainForInputToGroup = (inputId, groupId) => {
|
||||||
|
const key = `in_${inputId}_${groupId}`;
|
||||||
|
return routing.gains?.[key] || 0.0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getGainForGroupToOutput = (groupId, outputId) => {
|
||||||
|
const key = `${groupId}_out_${outputId}`;
|
||||||
|
return routing.gains?.[key] || 0.0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setGainForInputToGroup = (inputId, groupId, gainDb) => {
|
||||||
|
setRouting(prev => {
|
||||||
|
const gains = { ...prev.gains };
|
||||||
|
const key = `in_${inputId}_${groupId}`;
|
||||||
|
gains[key] = parseFloat(gainDb);
|
||||||
|
return { ...prev, gains };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setGainForGroupToOutput = (groupId, outputId, gainDb) => {
|
||||||
|
setRouting(prev => {
|
||||||
|
const gains = { ...prev.gains };
|
||||||
|
const key = `${groupId}_out_${outputId}`;
|
||||||
|
gains[key] = parseFloat(gainDb);
|
||||||
|
return { ...prev, gains };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatGain = (gainDb) => {
|
||||||
|
if (gainDb === 0) return '0dB';
|
||||||
|
return gainDb > 0 ? `+${gainDb}dB` : `${gainDb}dB`;
|
||||||
|
};
|
||||||
|
|
||||||
const getChannelName = (type, id) => {
|
const getChannelName = (type, id) => {
|
||||||
const name = channelNames?.[type]?.[id];
|
const name = channelNames?.[type]?.[id];
|
||||||
return name || `${type === 'inputs' ? 'Input' : 'Output'} ${id}`;
|
return name || `${type === 'inputs' ? 'Input' : 'Output'} ${id}`;
|
||||||
@@ -169,15 +202,39 @@ function AudioRoutingMatrix({ groups, channelNames }) {
|
|||||||
{getChannelName('inputs', i)}
|
{getChannelName('inputs', i)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{groups.map(group => (
|
{groups.map(group => {
|
||||||
<div
|
const isRouted = isInputRoutedToGroup(String(i), group.id);
|
||||||
key={`${i}-${group.id}`}
|
const gain = getGainForInputToGroup(String(i), group.id);
|
||||||
className={`matrix-cell ${isInputRoutedToGroup(String(i), group.id) ? 'active' : ''}`}
|
|
||||||
onClick={() => toggleInputToGroup(String(i), group.id)}
|
return (
|
||||||
>
|
<div
|
||||||
{isInputRoutedToGroup(String(i), group.id) && <span className="checkmark">✓</span>}
|
key={`${i}-${group.id}`}
|
||||||
</div>
|
className={`matrix-cell ${isRouted ? 'active' : ''}`}
|
||||||
))}
|
>
|
||||||
|
<div
|
||||||
|
className="cell-checkbox"
|
||||||
|
onClick={() => toggleInputToGroup(String(i), group.id)}
|
||||||
|
>
|
||||||
|
{isRouted && <span className="checkmark">✓</span>}
|
||||||
|
</div>
|
||||||
|
{isRouted && (
|
||||||
|
<select
|
||||||
|
className="gain-select"
|
||||||
|
value={gain}
|
||||||
|
onChange={(e) => setGainForInputToGroup(String(i), group.id, e.target.value)}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<option value="-12">-12dB</option>
|
||||||
|
<option value="-6">-6dB</option>
|
||||||
|
<option value="-3">-3dB</option>
|
||||||
|
<option value="0">0dB</option>
|
||||||
|
<option value="3">+3dB</option>
|
||||||
|
<option value="6">+6dB</option>
|
||||||
|
</select>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -204,15 +261,39 @@ function AudioRoutingMatrix({ groups, channelNames }) {
|
|||||||
{group.name}
|
{group.name}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{getVisibleOutputChannels().map(i => (
|
{getVisibleOutputChannels().map(i => {
|
||||||
<div
|
const isRouted = isGroupRoutedToOutput(group.id, String(i));
|
||||||
key={`${group.id}-${i}`}
|
const gain = getGainForGroupToOutput(group.id, String(i));
|
||||||
className={`matrix-cell ${isGroupRoutedToOutput(group.id, String(i)) ? 'active' : ''}`}
|
|
||||||
onClick={() => toggleGroupToOutput(group.id, String(i))}
|
return (
|
||||||
>
|
<div
|
||||||
{isGroupRoutedToOutput(group.id, String(i)) && <span className="checkmark">✓</span>}
|
key={`${group.id}-${i}`}
|
||||||
</div>
|
className={`matrix-cell ${isRouted ? 'active' : ''}`}
|
||||||
))}
|
>
|
||||||
|
<div
|
||||||
|
className="cell-checkbox"
|
||||||
|
onClick={() => toggleGroupToOutput(group.id, String(i))}
|
||||||
|
>
|
||||||
|
{isRouted && <span className="checkmark">✓</span>}
|
||||||
|
</div>
|
||||||
|
{isRouted && (
|
||||||
|
<select
|
||||||
|
className="gain-select"
|
||||||
|
value={gain}
|
||||||
|
onChange={(e) => setGainForGroupToOutput(group.id, String(i), e.target.value)}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<option value="-12">-12dB</option>
|
||||||
|
<option value="-6">-6dB</option>
|
||||||
|
<option value="-3">-3dB</option>
|
||||||
|
<option value="0">0dB</option>
|
||||||
|
<option value="3">+3dB</option>
|
||||||
|
<option value="6">+6dB</option>
|
||||||
|
</select>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user