update sounds ang transtions
Some checks failed
Test / test (push) Has been cancelled

This commit is contained in:
2026-06-22 17:16:36 +07:00
parent d70a4e45af
commit 523f98b74c
28 changed files with 2449 additions and 138 deletions

View File

@@ -864,53 +864,209 @@
</div>
<div class="page" id="pageSounds" data-page-content="sounds" hidden>
<div class="soundsPage">
<section class="card">
<div class="cardHeader">
<div>
<div class="cardTitle" data-i18n="sounds.title">Sounds</div>
<div class="cardSub" data-i18n="sounds.subtitle">Setup → Sounds — upload and manage robot sounds for sound zones.</div>
</div>
<button id="soundCreateBtn" type="button" class="btn primary" data-i18n="sounds.create">Create sound</button>
<div id="soundsListView" class="mapsMirPage">
<header class="mapsMirHeader">
<div class="mapsMirHeaderText">
<h1 class="mapsMirTitle" data-i18n="sounds.title">Sounds</h1>
<p class="mapsMirSubtitle">
<span data-i18n="sounds.subtitle">Create and edit sounds.</span>
<button type="button" class="mapsMirHelpBtn" id="soundsHelpBtn" data-i18n-title="sounds.helpTitle" aria-label="Help">
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="7" fill="none" stroke="currentColor" stroke-width="1.5"/><text x="8" y="11.5" text-anchor="middle" font-size="10" font-weight="700" fill="currentColor">?</text></svg>
</button>
</p>
</div>
<div class="cardBody">
<div id="soundListEmpty" class="mutedNote" hidden data-i18n="sounds.empty">No sounds yet. Create one to use in sound zones.</div>
<div id="soundList" class="missionList"></div>
<div class="mapsMirHeaderActions">
<button type="button" class="mapsMirBtn mapsMirBtn--green" id="soundCreateBtn">
<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M7 1v12M1 7h12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
<span data-i18n="sounds.create">Create sound</span>
</button>
<button type="button" class="mapsMirBtn mapsMirBtn--outline" id="soundsClearFiltersBtn">
<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="5.5" fill="none" stroke="currentColor" stroke-width="1.3"/><path d="M4.5 4.5l5 5" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>
<span data-i18n="sounds.clearFilters">Clear filters</span>
</button>
</div>
</section>
</header>
<div class="mapsMirFilterBar">
<label class="mapsMirFilterLabel" for="soundsFilterInput" data-i18n="sounds.filterLabel">Filter:</label>
<input type="search" id="soundsFilterInput" class="mapsMirFilterInput" data-i18n-placeholder="sounds.filterPlaceholder" placeholder="Filter by name..." autocomplete="off" />
<span id="soundsFilterCount" class="mapsMirFilterCount">0 item(s) found</span>
<div class="mapsMirPager">
<button type="button" class="mapsMirPageBtn" id="soundsPageFirst" aria-label="First page">&laquo;</button>
<button type="button" class="mapsMirPageBtn" id="soundsPagePrev" aria-label="Previous page">&lsaquo;</button>
<span id="soundsPageLabel" class="mapsMirPageLabel">Page 1 of 1</span>
<button type="button" class="mapsMirPageBtn" id="soundsPageNext" aria-label="Next page">&rsaquo;</button>
<button type="button" class="mapsMirPageBtn" id="soundsPageLast" aria-label="Last page">&raquo;</button>
</div>
</div>
<div class="soundsMirListWrap">
<div id="soundList" class="soundsMirList" role="list"></div>
<div id="soundListEmpty" class="mapsMirEmpty" hidden data-i18n="sounds.empty">No sounds yet.</div>
</div>
</div>
<dialog id="soundEditDialog" class="mapsMirDialog">
<form id="soundEditForm" method="dialog">
<h2 class="mapsMirDialogTitle" id="soundEditTitle" data-i18n="sounds.createTitle">Create sound</h2>
<p id="soundEditSystemBadge" class="soundSystemBadge" hidden data-i18n="sounds.systemBadge">System sound</p>
<label class="mapsMirField">
<span class="mapsMirFieldLabel" data-i18n="sounds.name">Name</span>
<input type="text" id="soundEditName" autocomplete="off" required />
</label>
<label class="mapsMirField">
<span class="mapsMirFieldLabel" data-i18n="sounds.description">Description</span>
<span class="mapsMirFieldLabel" data-i18n="sounds.note">Note</span>
<textarea id="soundEditDescription" rows="2"></textarea>
</label>
<label class="mapsMirField">
<span class="mapsMirFieldLabel" data-i18n="sounds.volume">Volume (0100)</span>
<div class="soundVolumeRow">
<input type="range" id="soundEditVolume" min="0" max="100" step="1" value="100" />
<output id="soundEditVolumeOut" for="soundEditVolume">100</output>
</div>
<span class="mapsMirFieldHint" data-i18n="sounds.volumeHint">100% is approximately 80 dB. Verify volume by playing on the robot.</span>
</label>
<label class="mapsMirField mapsMirField--checkbox">
<input type="checkbox" id="soundEditEnabled" checked />
<span data-i18n="sounds.enabled">Enabled</span>
</label>
<div class="mapsMirField">
<div class="mapsMirField" id="soundEditFileSection">
<span class="mapsMirFieldLabel" data-i18n="sounds.file">Audio file</span>
<p id="soundEditFileMeta" class="mutedNote"></p>
<div class="mapsMirDialogFooter mapsMirDialogFooter--inline">
<div class="mapsMirDialogFooter mapsMirDialogFooter--inline soundEditAudioActions">
<button type="button" class="mapsMirBtn mapsMirBtn--outline soundListenBtn" id="soundEditListenBtn" disabled title="Listen">
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path fill="currentColor" d="M8 2a4 4 0 0 0-4 4v3a4 4 0 0 0 8 0V6a4 4 0 0 0-4-4zm0 12a5 5 0 0 0 5-5H3a5 5 0 0 0 5 5z"/></svg>
<span data-i18n="sounds.listen">Listen</span>
</button>
<button type="button" class="mapsMirBtn mapsMirBtn--outline" id="soundEditPlayRobotBtn" disabled data-i18n="sounds.playOnRobot">Play on robot</button>
<button type="button" class="mapsMirBtn mapsMirBtn--outline" id="soundEditUploadBtn" data-i18n="sounds.upload">Upload file…</button>
<button type="button" class="mapsMirBtn mapsMirBtn--outline" id="soundEditPlayBtn" disabled data-i18n="sounds.play">Play</button>
</div>
<input type="file" id="soundEditUploadInput" accept="audio/*,.wav,.mp3,.ogg" hidden />
</div>
<div class="mapsMirDialogFooter">
<button type="button" class="mapsMirBtn mapsMirBtn--outline" id="soundEditCancelBtn" data-i18n="common.cancel">Cancel</button>
<button type="button" class="mapsMirBtn mapsMirBtn--danger" id="soundEditDeleteBtn" hidden data-i18n="common.delete">Delete</button>
<button type="submit" class="mapsMirBtn mapsMirBtn--primary" data-i18n="common.save">Save</button>
<button type="submit" class="mapsMirBtn mapsMirBtn--green" data-i18n="sounds.saveChanges">Save changes</button>
</div>
</form>
</dialog>
<dialog id="soundDeleteConfirmDialog" class="mapsMirDialog">
<div class="mapsMirDialogPanel">
<h2 class="mapsMirDialogTitle" data-i18n="sounds.deleteConfirmTitle">Delete sound?</h2>
<p id="soundDeleteConfirmText" class="mapsMirDialogText"></p>
<div class="mapsMirDialogFooter">
<button type="button" class="mapsMirBtn mapsMirBtn--outline" id="soundDeleteCancelBtn" data-i18n="common.no">No</button>
<button type="button" class="mapsMirBtn mapsMirBtn--danger" id="soundDeleteYesBtn" data-i18n="common.yes">Yes</button>
</div>
</div>
</dialog>
</div>
<div class="page" id="pageTransitions" data-page-content="transitions" hidden>
<div id="transitionsListView" class="mapsMirPage">
<header class="mapsMirHeader">
<div class="mapsMirHeaderText">
<h1 class="mapsMirTitle" data-i18n="transitions.title">Transitions</h1>
<p class="mapsMirSubtitle">
<span data-i18n="transitions.subtitle">Create and edit transitions.</span>
<button type="button" class="mapsMirHelpBtn" id="transitionsHelpBtn" data-i18n-title="transitions.helpTitle" aria-label="Help">
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="7" fill="none" stroke="currentColor" stroke-width="1.5"/><text x="8" y="11.5" text-anchor="middle" font-size="10" font-weight="700" fill="currentColor">?</text></svg>
</button>
</p>
</div>
<div class="mapsMirHeaderActions">
<button type="button" class="mapsMirBtn mapsMirBtn--green" id="transitionCreateBtn">
<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M7 1v12M1 7h12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
<span data-i18n="transitions.create">Create transition</span>
</button>
<button type="button" class="mapsMirBtn mapsMirBtn--outline" id="transitionsClearFiltersBtn">
<svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="5.5" fill="none" stroke="currentColor" stroke-width="1.3"/><path d="M4.5 4.5l5 5" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>
<span data-i18n="transitions.clearFilters">Clear filters</span>
</button>
</div>
</header>
<div class="mapsMirFilterBar">
<label class="mapsMirFilterLabel" for="transitionsFilterInput" data-i18n="transitions.filterLabel">Filter:</label>
<input type="search" id="transitionsFilterInput" class="mapsMirFilterInput" data-i18n-placeholder="transitions.filterPlaceholder" placeholder="Filter by position or mission..." autocomplete="off" />
<span id="transitionsFilterCount" class="mapsMirFilterCount">0 item(s) found</span>
<div class="mapsMirPager">
<button type="button" class="mapsMirPageBtn" id="transitionsPageFirst" aria-label="First page">&laquo;</button>
<button type="button" class="mapsMirPageBtn" id="transitionsPagePrev" aria-label="Previous page">&lsaquo;</button>
<span id="transitionsPageLabel" class="mapsMirPageLabel">Page 1 of 1</span>
<button type="button" class="mapsMirPageBtn" id="transitionsPageNext" aria-label="Next page">&rsaquo;</button>
<button type="button" class="mapsMirPageBtn" id="transitionsPageLast" aria-label="Last page">&raquo;</button>
</div>
</div>
<div class="mapsMirTableWrap">
<table class="mapsMirTable mapsMirTable--transitions" id="transitionsTable">
<thead>
<tr>
<th class="transMirThIcon" aria-hidden="true"></th>
<th data-i18n="transitions.colStart">Start</th>
<th data-i18n="transitions.colGoal">Goal</th>
<th data-i18n="transitions.colMission">Mission</th>
<th data-i18n="transitions.colCreatedBy">Created by</th>
<th class="mapsMirThFunctions" data-i18n="transitions.colFunctions">Functions</th>
</tr>
</thead>
<tbody id="transitionList"></tbody>
</table>
<div id="transitionListEmpty" class="mapsMirEmpty" hidden data-i18n="transitions.empty">No transitions yet.</div>
</div>
</div>
<dialog id="transitionEditDialog" class="mapsMirDialog">
<form id="transitionEditForm" method="dialog">
<h2 class="mapsMirDialogTitle" id="transitionEditTitle" data-i18n="transitions.createTitle">Create transition</h2>
<label class="mapsMirField">
<span class="mapsMirFieldLabel" data-i18n="transitions.site">Site</span>
<select id="transitionEditSite" required></select>
</label>
<div class="mapsMirFieldRow">
<label class="mapsMirField">
<span class="mapsMirFieldLabel" data-i18n="transitions.fromMap">From map</span>
<select id="transitionEditFromMap" required></select>
</label>
<label class="mapsMirField">
<span class="mapsMirFieldLabel" data-i18n="transitions.toMap">To map</span>
<select id="transitionEditToMap" required></select>
</label>
</div>
<div class="mapsMirFieldRow">
<label class="mapsMirField">
<span class="mapsMirFieldLabel" data-i18n="transitions.startPosition">Start position</span>
<select id="transitionEditStartPos" required></select>
</label>
<label class="mapsMirField">
<span class="mapsMirFieldLabel" data-i18n="transitions.goalPosition">Goal position</span>
<select id="transitionEditGoalPos" required></select>
</label>
</div>
<label class="mapsMirField">
<span class="mapsMirFieldLabel" data-i18n="transitions.mission">Mission</span>
<select id="transitionEditMission" required></select>
</label>
<div class="mapsMirDialogFooter">
<button type="button" class="mapsMirBtn mapsMirBtn--outline" id="transitionEditCancelBtn" data-i18n="common.cancel">Cancel</button>
<button type="button" class="mapsMirBtn mapsMirBtn--danger" id="transitionEditDeleteBtn" hidden data-i18n="common.delete">Delete</button>
<button type="submit" class="mapsMirBtn mapsMirBtn--green" data-i18n="common.save">Save</button>
</div>
</form>
</dialog>
<dialog id="transitionDeleteConfirmDialog" class="mapsMirDialog">
<div class="mapsMirDialogPanel">
<h2 class="mapsMirDialogTitle" data-i18n="transitions.deleteTitle">Delete transition?</h2>
<p id="transitionDeleteConfirmText" class="mapsMirDialogText"></p>
<div class="mapsMirDialogFooter">
<button type="button" class="mapsMirBtn mapsMirBtn--outline" id="transitionDeleteCancelBtn" data-i18n="common.no">No</button>
<button type="button" class="mapsMirBtn mapsMirBtn--danger" id="transitionDeleteYesBtn" data-i18n="common.yes">Yes</button>
</div>
</div>
</dialog>
</div>
<div class="page" id="pageMaps" data-page-content="maps" hidden>
@@ -2069,6 +2225,7 @@ GET /api/v2.0.0/status</pre>
<script src="/i18n.js"></script>
<script src="/auth.js"></script>
<script src="/nav.js"></script>
<script src="/sounds.js"></script>
<script src="/missions.js"></script>
<script src="/map-geo.js"></script>
<script src="/map-occupancy-canvas.js"></script>
@@ -2080,6 +2237,7 @@ GET /api/v2.0.0/status</pre>
<script src="/map-yaml.js"></script>
<script src="/maps.js"></script>
<script src="/sounds.js"></script>
<script src="/transitions.js"></script>
<script src="/map-editor.js"></script>
<script src="/topbar.js"></script>
<script src="/dashboard.js"></script>