Skip to content

Commit 357cc76

Browse files
Improve exercise selection input (#85)
- add a helper-documented exercise input paired with a datalist dropdown - populate both autocomplete options and a browseable select list from exercises - keep the manual browse select in sync with the main exercise input for record actions ------ [Codex Task](https://chatgpt.com/codex/tasks/task_e_693e8b9308288325bc09d22fd6d9b4e3)
1 parent 79ed95d commit 357cc76

1 file changed

Lines changed: 67 additions & 4 deletions

File tree

workout-exercise-record.html

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,43 @@
7979
width: 100%;
8080
}
8181

82+
.exercise-picker {
83+
display: grid;
84+
gap: 0.25rem;
85+
align-self: start;
86+
width: min(360px, 100%);
87+
}
88+
89+
.exercise-browser {
90+
border: 1px solid var(--border);
91+
border-radius: 8px;
92+
padding: 0.25rem 0.5rem;
93+
background: var(--surface-2);
94+
}
95+
96+
.exercise-browser summary {
97+
cursor: pointer;
98+
font-weight: 600;
99+
padding: 0.25rem 0;
100+
}
101+
102+
.exercise-browser select {
103+
width: 100%;
104+
margin-top: 0.25rem;
105+
}
106+
107+
.visually-hidden {
108+
position: absolute;
109+
width: 1px;
110+
height: 1px;
111+
padding: 0;
112+
margin: -1px;
113+
overflow: hidden;
114+
clip: rect(0, 0, 0, 0);
115+
white-space: nowrap;
116+
border: 0;
117+
}
118+
82119
.record-actions {
83120
display: flex;
84121
gap: 0.5rem;
@@ -120,10 +157,16 @@ <h1>Workout Exercise Records</h1>
120157
<section class="card">
121158
<h2>Records</h2>
122159
<div class="record-controls">
123-
<div style="display: grid; gap: 0.25rem; align-self: start; width: min(320px, 100%);">
160+
<div class="exercise-picker">
124161
<label for="exercise-select" class="status-text">Exercise</label>
125-
<input id="exercise-select" list="exercise-options" placeholder="Start typing to search" />
162+
<input id="exercise-select" list="exercise-options" placeholder="Start typing or pick from the list" aria-describedby="exercise-help" />
163+
<p id="exercise-help" class="status-text">Start typing to search or open the dropdown to pick an exercise.</p>
126164
<datalist id="exercise-options"></datalist>
165+
<details class="exercise-browser">
166+
<summary>Browse exercise list</summary>
167+
<label class="visually-hidden" for="exercise-browse-select">Browse exercises</label>
168+
<select id="exercise-browse-select" size="8"></select>
169+
</details>
127170
</div>
128171
<div class="record-actions">
129172
<button id="get-records">Get records</button>
@@ -168,6 +211,7 @@ <h2 style="margin: 0;">Workout tools</h2>
168211
<script>
169212
const exerciseSelect = document.getElementById('exercise-select');
170213
const exerciseOptions = document.getElementById('exercise-options');
214+
const exerciseBrowseSelect = document.getElementById('exercise-browse-select');
171215
const loadStatus = document.getElementById('load-status');
172216
const recordRows = document.getElementById('record-rows');
173217
const recordStatus = document.getElementById('record-status');
@@ -187,16 +231,24 @@ <h2 style="margin: 0;">Workout tools</h2>
187231

188232
function populateExerciseOptions(list) {
189233
exerciseOptions.innerHTML = '';
234+
exerciseBrowseSelect.innerHTML = '';
190235
const sorted = [...list].sort((a, b) =>
191236
a.name.localeCompare(b.name, undefined, { sensitivity: 'base' })
192237
);
193238

194239
sorted.forEach((ex) => {
240+
const displayName = ex.display_name || formatExerciseName(ex.name);
195241
const option = document.createElement('option');
196-
option.value = formatExerciseName(ex.name);
242+
option.value = displayName;
197243
option.dataset.name = ex.name;
198-
option.dataset.displayName = ex.display_name || formatExerciseName(ex.name);
244+
option.dataset.displayName = displayName;
199245
exerciseOptions.appendChild(option);
246+
247+
const selectOption = document.createElement('option');
248+
selectOption.value = displayName;
249+
selectOption.textContent = displayName;
250+
selectOption.dataset.name = ex.name;
251+
exerciseBrowseSelect.appendChild(selectOption);
200252
});
201253
}
202254

@@ -242,6 +294,7 @@ <h2 style="margin: 0;">Workout tools</h2>
242294
async function loadExercises() {
243295
loadStatus.textContent = 'Loading exercises...';
244296
exerciseSelect.value = '';
297+
exerciseBrowseSelect.selectedIndex = -1;
245298
try {
246299
const data = await apiFetch('/exercises');
247300
if (!data.exercises.length) {
@@ -326,6 +379,16 @@ <h2 style="margin: 0;">Workout tools</h2>
326379
recordRows.innerHTML = '';
327380
});
328381

382+
exerciseBrowseSelect.addEventListener('change', (event) => {
383+
const selectedOption = event.target.selectedOptions[0];
384+
if (!selectedOption) return;
385+
const value = selectedOption.value || selectedOption.textContent;
386+
exerciseSelect.value = value;
387+
exerciseSelect.dispatchEvent(new Event('input', { bubbles: true }));
388+
const details = exerciseBrowseSelect.closest('details');
389+
if (details) details.open = false;
390+
});
391+
329392
document.getElementById('record-form').addEventListener('submit', async (event) => {
330393
event.preventDefault();
331394
const selected = getSelectedExercise();

0 commit comments

Comments
 (0)