Fix scrolling UX with sticky header controls

This commit is contained in:
notV3NOM 2025-09-05 21:25:13 +05:30
parent 191680940b
commit e4ca2623cb
No known key found for this signature in database
GPG key ID: 126E8E7CA0B1531D
3 changed files with 91 additions and 53 deletions

View file

@ -74,10 +74,13 @@
body { body {
font-family: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; font-family: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
margin: 20px; margin: 0;
text-align: center; text-align: center;
background-color: var(--bg); background-color: var(--bg);
color: var(--text); color: var(--text);
height: 100vh;
display: flex;
flex-direction: column;
} }
/* Record button */ /* Record button */
@ -168,9 +171,18 @@ body {
} }
#status { #status {
margin-top: 20px; margin-top: 15px;
font-size: 16px; font-size: 16px;
color: var(--text); color: var(--text);
margin-bottom: 0;
}
.header-container {
position: sticky;
top: 0;
background-color: var(--bg);
z-index: 100;
padding: 20px;
} }
/* Settings */ /* Settings */
@ -179,7 +191,6 @@ body {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
gap: 15px; gap: 15px;
margin-top: 20px;
} }
.settings { .settings {
@ -297,9 +308,21 @@ label {
border-radius: 999px; border-radius: 999px;
} }
.transcript-container {
flex: 1;
overflow-y: auto;
padding: 20px;
scrollbar-width: none;
-ms-overflow-style: none;
}
.transcript-container::-webkit-scrollbar {
display: none;
}
/* Transcript area */ /* Transcript area */
#linesTranscript { #linesTranscript {
margin: 20px auto; margin: 0 auto;
max-width: 700px; max-width: 700px;
text-align: left; text-align: left;
font-size: 16px; font-size: 16px;
@ -407,6 +430,10 @@ label {
/* for smaller screens */ /* for smaller screens */
@media (max-width: 768px) { @media (max-width: 768px) {
.header-container {
padding: 15px;
}
.settings-container { .settings-container {
flex-direction: column; flex-direction: column;
gap: 10px; gap: 10px;
@ -430,11 +457,15 @@ label {
.theme-selector-container { .theme-selector-container {
margin-top: 10px; margin-top: 10px;
} }
.transcript-container {
padding: 15px;
}
} }
@media (max-width: 480px) { @media (max-width: 480px) {
body { .header-container {
margin: 10px; padding: 10px;
} }
.settings { .settings {
@ -457,4 +488,8 @@ label {
width: 14px; width: 14px;
height: 14px; height: 14px;
} }
.transcript-container {
padding: 10px;
}
} }

View file

@ -9,63 +9,63 @@
</head> </head>
<body> <body>
<div class="settings-container"> <div class="header-container">
<button id="recordButton"> <div class="settings-container">
<div class="shape-container"> <button id="recordButton">
<div class="shape"></div> <div class="shape-container">
</div> <div class="shape"></div>
<div class="recording-info">
<div class="wave-container">
<canvas id="waveCanvas"></canvas>
</div> </div>
<div class="timer">00:00</div> <div class="recording-info">
</div> <div class="wave-container">
</button> <canvas id="waveCanvas"></canvas>
</div>
<div class="timer">00:00</div>
</div>
</button>
<div class="settings"> <div class="settings">
<div class="field"> <div class="field">
<label for="websocketInput">Websocket URL</label> <label for="websocketInput">Websocket URL</label>
<input id="websocketInput" type="text" placeholder="ws://host:port/asr" /> <input id="websocketInput" type="text" placeholder="ws://host:port/asr" />
</div> </div>
<div class="field"> <div class="field">
<label id="microphoneSelectLabel" for="microphoneSelect">Select Microphone</label> <label id="microphoneSelectLabel" for="microphoneSelect">Select Microphone</label>
<select id="microphoneSelect"> <select id="microphoneSelect">
<option value="">Default Microphone</option> <option value="">Default Microphone</option>
</select> </select>
</div> </div>
<div class="theme-selector-container"> <div class="theme-selector-container">
<div class="segmented" role="radiogroup" aria-label="Theme selector"> <div class="segmented" role="radiogroup" aria-label="Theme selector">
<input type="radio" id="theme-system" name="theme" value="system" /> <input type="radio" id="theme-system" name="theme" value="system" />
<label for="theme-system" title="System"> <label for="theme-system" title="System">
<img src="/web/src/system_mode.svg" alt="" /> <img src="/web/src/system_mode.svg" alt="" />
<span>System</span> <span>System</span>
</label> </label>
<input type="radio" id="theme-light" name="theme" value="light" /> <input type="radio" id="theme-light" name="theme" value="light" />
<label for="theme-light" title="Light"> <label for="theme-light" title="Light">
<img src="/web/src/light_mode.svg" alt="" /> <img src="/web/src/light_mode.svg" alt="" />
<span>Light</span> <span>Light</span>
</label> </label>
<input type="radio" id="theme-dark" name="theme" value="dark" /> <input type="radio" id="theme-dark" name="theme" value="dark" />
<label for="theme-dark" title="Dark"> <label for="theme-dark" title="Dark">
<img src="/web/src/dark_mode.svg" alt="" /> <img src="/web/src/dark_mode.svg" alt="" />
<span>Dark</span> <span>Dark</span>
</label> </label>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
<p id="status"></p>
</div> </div>
<div class="transcript-container">
<div id="linesTranscript"></div>
<p id="status"></p> </div>
<div id="linesTranscript"></div>
<script src="/web/live_transcription.js"></script> <script src="/web/live_transcription.js"></script>
</body> </body>

View file

@ -373,7 +373,10 @@ function renderLinesWithBuffer(
.join(""); .join("");
linesTranscriptDiv.innerHTML = linesHtml; linesTranscriptDiv.innerHTML = linesHtml;
window.scrollTo({ top: document.body.scrollHeight, behavior: "smooth" }); const transcriptContainer = document.querySelector('.transcript-container');
if (transcriptContainer) {
transcriptContainer.scrollTo({ top: transcriptContainer.scrollHeight, behavior: "smooth" });
}
} }
function updateTimer() { function updateTimer() {