Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@
## 2026-06-10 - Add inline form helpers and client-side validation
**Learning:** Combining aria-describedby for helper text and aria-hidden on visual required indicators improves screen reader clarity while providing necessary visual cues to sighted users.
**Action:** Always pair visible required markers with aria-hidden, relying on the native required attribute for semantics, and link helper text with aria-describedby.
## 2024-05-24 - Dynamic Human-Readable File Size Preview
**Learning:** Users often struggle to conceptualize large numbers in bytes (e.g., 2000000000), leading to magnitude errors. Providing a live, ARIA-announced preview in familiar units (MB, GB) right next to the input drastically improves confidence and prevents submission mistakes.
**Action:** Always pair raw byte inputs with a dynamic, human-readable preview using an `aria-live` region.
15 changes: 13 additions & 2 deletions saas_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,30 @@
<body>
<div class="box">
<h2>Shrink Media File</h2>
<form action="/shrink" method="post" enctype="multipart/form-data" onsubmit="const btn = document.getElementById('submit-btn'); setTimeout(() => { btn.disabled = true; btn.innerText = 'Processing...'; }, 10);">
<form action="/shrink" method="post" enctype="multipart/form-data" id="shrink-form">
<p>
<label for="file">Media File: <span class="required-star" aria-hidden="true">*</span></label><br>
<input type="file" id="file" name="file" accept="audio/*,video/*" aria-describedby="file_help" required>
<br><span id="file_help" class="help-text">Select an audio or video file to shrink.</span>
</p>
<p>
<label for="target_bytes">Target Bytes: <span class="required-star" aria-hidden="true">*</span></label><br>
<input type="number" id="target_bytes" name="target_bytes" value="2000000000" min="1" aria-describedby="target_bytes_help" required>
<input type="number" id="target_bytes" name="target_bytes" value="2000000000" min="1" aria-describedby="target_bytes_help target_bytes_preview" required oninput="const val = parseInt(this.value, 10); const preview = document.getElementById('target_bytes_preview'); if (isNaN(val) || val <= 0) { preview.innerText = ''; } else if (val < 1000) { preview.innerText = val + ' B'; } else if (val < 1000000) { preview.innerText = (val / 1000).toFixed(2) + ' KB'; } else if (val < 1000000000) { preview.innerText = (val / 1000000).toFixed(2) + ' MB'; } else { preview.innerText = (val / 1000000000).toFixed(2) + ' GB'; }">
<br><span id="target_bytes_help" class="help-text">Maximum allowed file size in bytes (e.g., 2000000000 for ~2GB)</span>
<br><span id="target_bytes_preview" class="help-text" aria-live="polite" style="font-weight: bold; color: #28a745;">2.00 GB</span>
</p>
<button type="submit" id="submit-btn">Upload and Shrink</button>
</form>
<script>
document.getElementById('shrink-form').addEventListener('submit', function() {
const btn = document.getElementById('submit-btn');
setTimeout(() => {
btn.disabled = true;
btn.innerText = 'Processing...';
btn.setAttribute('aria-busy', 'true');
}, 10);
});
</script>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
</div>
</body>
</html>
Expand Down