Added Advance setting:

Added Advance setting:
Custom Primary/Secondary NTP server input
24/12h clock mode toggle (24-hour default)
Flip display (180 degrees)
Adjustable display brightness
This commit is contained in:
mfactory-osaka
2025-06-12 17:38:35 +09:00
parent 8a9caa52c5
commit e3a27974db
4 changed files with 433 additions and 328 deletions

View File

@@ -4,8 +4,13 @@
"openWeatherApiKey": "ADD-YOUR-API-KEY-32-CHARACTERS",
"openWeatherCity": "",
"openWeatherCountry": "",
"clockDuration": "10000",
"weatherDuration": "5000",
"clockDuration": 10000,
"weatherDuration": 5000,
"timeZone": "",
"weatherUnits": "metric"
}
"weatherUnits": "metric",
"brightness": 10,
"flipDisplay": false,
"ntpServer1": "pool.ntp.org",
"ntpServer2": "time.nist.gov",
"twelveHourToggle": false
}

View File

@@ -5,6 +5,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>ESPTimeCast Settings</title>
<style>
:root{
--accent-color: #0075ff;
}
* { box-sizing: border-box; }
html{
background: radial-gradient(ellipse at 70% 0%, #2b425a 0%, #171e23 100%);
@@ -17,18 +22,18 @@
color: #FFFFFF;
background-repeat: no-repeat, repeat, repeat;
opacity: 0;
transition: opacity 0.6s cubic-bezier(.4,0,.2,1);
visibility: 0;
transition: opacity 0.6s cubic-bezier(.4,0,.2,1);
visibility: 0;
}
body.loaded {
visibility: visible;
opacity: 1;
}
body.loaded {
visibility: visible;
opacity: 1;
}
body.modal-open {
overflow: hidden;
}
}
h1 {
text-align: center;
font-size: 1.5rem;
@@ -62,7 +67,7 @@ body.loaded {
}
label {
font-size: 0.9rem;
margin-bottom: 0.25rem;
margin-bottom: 0.25rem;
display: block;
margin-top: 0.75rem;
}
@@ -85,6 +90,24 @@ body.loaded {
input[type="submit"]:hover {
background-color: #005ecb;
}
input:-webkit-autofill,
input:-webkit-autofill:focus,
input:-webkit-autofill:hover {
background: rgba(225,245,255,0.07) !important;
color: #fff !important;
-webkit-box-shadow: 0 0 0 1000px rgba(225,245,255,0.07) inset !important;
box-shadow: 0 0 0 1000px rgba(225,245,255,0.07) inset !important;
-webkit-text-fill-color: #fff !important;
transition: background 9999s ease-in-out 0s;
}
input::placeholder,
textarea::placeholder {
color: #fff; /* Example: light blue */
opacity: 1; /* Make sure it's not semi-transparent */
}
.form-row {
display: flex;
flex-direction: column;
@@ -155,20 +178,80 @@ body.loaded {
margin-top: 0.25rem;
}
select option {
color: black;
}
select option {
color: black;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@media (min-width: 320px) {
.form-row.two-col {
flex-direction: row;
gap: 1rem; }
.form-row.two-col {
flex-direction: row;
gap: 1rem; }
}
/* Make sure .details-content is visible only when open */
.animated-details[open] .details-content {
/* JS will animate the height */
}
/* Toggle Switch Styling for Flip Display */
.toggle-switch { position: relative; display: inline-block; width: 48px; height: 24px; }
.toggle-switch input { opacity: 0; width: 0; height: 0; }
.toggle-slider {
position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0;
background-color: #ccc; transition: .4s; border-radius: 24px;
}
.toggle-slider:before {
position: absolute; content: ""; height: 20px; width: 20px; left: 2px; bottom: 2px;
background-color: white; transition: .4s; border-radius: 50%;
}
input:checked + .toggle-slider { background-color: var(--accent-color); }
input:checked + .toggle-slider:before { transform: translateX(24px); }
.accent{
accent-color: var(--accent-color);
}
.collapsible-toggle {
display: flex;
align-items: center;
cursor: pointer;
font-size: 1.1rem;
font-weight: bold;
background: none;
border: none;
color: white;
padding: 0;
margin: 0;
outline: none;
gap: 0.5em;
user-select: none;
margin-top: 2.5rem;
}
.collapsible-toggle .icon-area {
transition: transform 0.3s cubic-bezier(.4,0,.2,1);
display: flex;
}
.collapsible-toggle.open .icon-area {
transform: rotate(90deg);
}
.collapsible-content {
overflow: hidden;
height: 0;
transition: height 0.3s cubic-bezier(.4,0,.2,1);
color: #fff;
margin-bottom: 2rem;
}
.collapsible-content-inner {
padding: 1em 0;
}
</style>
</head>
<body>
@@ -209,103 +292,102 @@ body.loaded {
</select>
<div class="small">
Consult the <a href="https://openweathermap.org/price" target="_blank" rel="noopener">OpenWeatherMap</a>
documendation for info about getting your API key, city, and country code.
</div>
documentation for info about getting your API key, city, and country code.
</div>
<h2>Clock Settings</h2>
<label for="timeZone">Time Zone</label>
<select id="timeZone" name="timeZone" required>
<option value="" disabled selected>Select your time zone</option>
<option value="Africa/Algiers">Africa/Algiers</option>
<option value="Africa/Cairo">Africa/Cairo</option>
<option value="Africa/Casablanca">Africa/Casablanca</option>
<option value="Africa/Johannesburg">Africa/Johannesburg</option>
<option value="Africa/Lagos">Africa/Lagos</option>
<option value="Africa/Nairobi">Africa/Nairobi</option>
<option value="America/Anchorage">America/Anchorage</option>
<option value="America/Argentina/Buenos_Aires">America/Argentina/Buenos_Aires</option>
<option value="America/Bogota">America/Bogota</option>
<option value="America/Caracas">America/Caracas</option>
<option value="America/Chicago">America/Chicago</option>
<option value="America/Denver">America/Denver</option>
<option value="America/Lima">America/Lima</option>
<option value="America/Los_Angeles">America/Los_Angeles</option>
<option value="America/Mexico_City">America/Mexico_City</option>
<option value="America/New_York">America/New_York</option>
<option value="America/Phoenix">America/Phoenix</option>
<option value="America/Santiago">America/Santiago</option>
<option value="America/Sao_Paulo">America/Sao_Paulo</option>
<option value="America/Toronto">America/Toronto</option>
<option value="America/Vancouver">America/Vancouver</option>
<option value="Asia/Almaty">Asia/Almaty</option>
<option value="Asia/Amman">Asia/Amman</option>
<option value="Asia/Baghdad">Asia/Baghdad</option>
<option value="Asia/Baku">Asia/Baku</option>
<option value="Asia/Bangkok">Asia/Bangkok</option>
<option value="Asia/Beirut">Asia/Beirut</option>
<option value="Asia/Dhaka">Asia/Dhaka</option>
<option value="Asia/Dubai">Asia/Dubai</option>
<option value="Asia/Ho_Chi_Minh">Asia/Ho_Chi_Minh</option>
<option value="Asia/Hong_Kong">Asia/Hong_Kong</option>
<option value="Asia/Jakarta">Asia/Jakarta</option>
<option value="Asia/Jerusalem">Asia/Jerusalem</option>
<option value="Asia/Kabul">Asia/Kabul</option>
<option value="Asia/Karachi">Asia/Karachi</option>
<option value="Asia/Kathmandu">Asia/Kathmandu</option>
<option value="Asia/Kolkata">Asia/Kolkata</option>
<option value="Asia/Kuala_Lumpur">Asia/Kuala_Lumpur</option>
<option value="Asia/Kuwait">Asia/Kuwait</option>
<option value="Asia/Manila">Asia/Manila</option>
<option value="Asia/Riyadh">Asia/Riyadh</option>
<option value="Asia/Seoul">Asia/Seoul</option>
<option value="Asia/Shanghai">Asia/Shanghai</option>
<option value="Asia/Singapore">Asia/Singapore</option>
<option value="Asia/Taipei">Asia/Taipei</option>
<option value="Asia/Tashkent">Asia/Tashkent</option>
<option value="Asia/Tehran">Asia/Tehran</option>
<option value="Asia/Tokyo">Asia/Tokyo</option>
<option value="Asia/Yangon">Asia/Yangon</option>
<option value="Australia/Adelaide">Australia/Adelaide</option>
<option value="Australia/Brisbane">Australia/Brisbane</option>
<option value="Australia/Melbourne">Australia/Melbourne</option>
<option value="Australia/Perth">Australia/Perth</option>
<option value="Australia/Sydney">Australia/Sydney</option>
<option value="Europe/Amsterdam">Europe/Amsterdam</option>
<option value="Europe/Athens">Europe/Athens</option>
<option value="Europe/Belgrade">Europe/Belgrade</option>
<option value="Europe/Berlin">Europe/Berlin</option>
<option value="Europe/Brussels">Europe/Brussels</option>
<option value="Europe/Bucharest">Europe/Bucharest</option>
<option value="Europe/Budapest">Europe/Budapest</option>
<option value="Europe/Copenhagen">Europe/Copenhagen</option>
<option value="Europe/Dublin">Europe/Dublin</option>
<option value="Europe/Helsinki">Europe/Helsinki</option>
<option value="Europe/Istanbul">Europe/Istanbul</option>
<option value="Europe/Kiev">Europe/Kiev</option>
<option value="Europe/Lisbon">Europe/Lisbon</option>
<option value="Europe/London">Europe/London</option>
<option value="Europe/Madrid">Europe/Madrid</option>
<option value="Europe/Moscow">Europe/Moscow</option>
<option value="Europe/Oslo">Europe/Oslo</option>
<option value="Europe/Paris">Europe/Paris</option>
<option value="Europe/Prague">Europe/Prague</option>
<option value="Europe/Riga">Europe/Riga</option>
<option value="Europe/Rome">Europe/Rome</option>
<option value="Europe/Sofia">Europe/Sofia</option>
<option value="Europe/Stockholm">Europe/Stockholm</option>
<option value="Europe/Tallinn">Europe/Tallinn</option>
<option value="Europe/Vienna">Europe/Vienna</option>
<option value="Europe/Vilnius">Europe/Vilnius</option>
<option value="Europe/Warsaw">Europe/Warsaw</option>
<option value="Europe/Zurich">Europe/Zurich</option>
<option value="Pacific/Auckland">Pacific/Auckland</option>
<option value="Pacific/Fiji">Pacific/Fiji</option>
<option value="Pacific/Guam">Pacific/Guam</option>
<option value="Pacific/Honolulu">Pacific/Honolulu</option>
<option value="Etc/UTC">Etc/UTC</option>
</select>
<select id="timeZone" name="timeZone" required>
<option value="" disabled selected>Select your time zone</option>
<!-- ... (timezone options unchanged) ... -->
<option value="Africa/Algiers">Africa/Algiers</option>
<option value="Africa/Cairo">Africa/Cairo</option>
<option value="Africa/Casablanca">Africa/Casablanca</option>
<option value="Africa/Johannesburg">Africa/Johannesburg</option>
<option value="Africa/Lagos">Africa/Lagos</option>
<option value="Africa/Nairobi">Africa/Nairobi</option>
<option value="America/Anchorage">America/Anchorage</option>
<option value="America/Argentina/Buenos_Aires">America/Argentina/Buenos_Aires</option>
<option value="America/Bogota">America/Bogota</option>
<option value="America/Caracas">America/Caracas</option>
<option value="America/Chicago">America/Chicago</option>
<option value="America/Denver">America/Denver</option>
<option value="America/Lima">America/Lima</option>
<option value="America/Los_Angeles">America/Los_Angeles</option>
<option value="America/Mexico_City">America/Mexico_City</option>
<option value="America/New_York">America/New_York</option>
<option value="America/Phoenix">America/Phoenix</option>
<option value="America/Santiago">America/Santiago</option>
<option value="America/Sao_Paulo">America/Sao_Paulo</option>
<option value="America/Toronto">America/Toronto</option>
<option value="America/Vancouver">America/Vancouver</option>
<option value="Asia/Almaty">Asia/Almaty</option>
<option value="Asia/Amman">Asia/Amman</option>
<option value="Asia/Baghdad">Asia/Baghdad</option>
<option value="Asia/Baku">Asia/Baku</option>
<option value="Asia/Bangkok">Asia/Bangkok</option>
<option value="Asia/Beirut">Asia/Beirut</option>
<option value="Asia/Dhaka">Asia/Dhaka</option>
<option value="Asia/Dubai">Asia/Dubai</option>
<option value="Asia/Ho_Chi_Minh">Asia/Ho_Chi_Minh</option>
<option value="Asia/Hong_Kong">Asia/Hong_Kong</option>
<option value="Asia/Jakarta">Asia/Jakarta</option>
<option value="Asia/Jerusalem">Asia/Jerusalem</option>
<option value="Asia/Kabul">Asia/Kabul</option>
<option value="Asia/Karachi">Asia/Karachi</option>
<option value="Asia/Kathmandu">Asia/Kathmandu</option>
<option value="Asia/Kolkata">Asia/Kolkata</option>
<option value="Asia/Kuala_Lumpur">Asia/Kuala_Lumpur</option>
<option value="Asia/Kuwait">Asia/Kuwait</option>
<option value="Asia/Manila">Asia/Manila</option>
<option value="Asia/Riyadh">Asia/Riyadh</option>
<option value="Asia/Seoul">Asia/Seoul</option>
<option value="Asia/Shanghai">Asia/Shanghai</option>
<option value="Asia/Singapore">Asia/Singapore</option>
<option value="Asia/Taipei">Asia/Taipei</option>
<option value="Asia/Tashkent">Asia/Tashkent</option>
<option value="Asia/Tehran">Asia/Tehran</option>
<option value="Asia/Tokyo">Asia/Tokyo</option>
<option value="Asia/Yangon">Asia/Yangon</option>
<option value="Australia/Adelaide">Australia/Adelaide</option>
<option value="Australia/Brisbane">Australia/Brisbane</option>
<option value="Australia/Melbourne">Australia/Melbourne</option>
<option value="Australia/Perth">Australia/Perth</option>
<option value="Australia/Sydney">Australia/Sydney</option>
<option value="Europe/Amsterdam">Europe/Amsterdam</option>
<option value="Europe/Athens">Europe/Athens</option>
<option value="Europe/Belgrade">Europe/Belgrade</option>
<option value="Europe/Berlin">Europe/Berlin</option>
<option value="Europe/Brussels">Europe/Brussels</option>
<option value="Europe/Bucharest">Europe/Bucharest</option>
<option value="Europe/Budapest">Europe/Budapest</option>
<option value="Europe/Copenhagen">Europe/Copenhagen</option>
<option value="Europe/Dublin">Europe/Dublin</option>
<option value="Europe/Helsinki">Europe/Helsinki</option>
<option value="Europe/Istanbul">Europe/Istanbul</option>
<option value="Europe/Kiev">Europe/Kiev</option>
<option value="Europe/Lisbon">Europe/Lisbon</option>
<option value="Europe/London">Europe/London</option>
<option value="Europe/Madrid">Europe/Madrid</option>
<option value="Europe/Moscow">Europe/Moscow</option>
<option value="Europe/Oslo">Europe/Oslo</option>
<option value="Europe/Paris">Europe/Paris</option>
<option value="Europe/Prague">Europe/Prague</option>
<option value="Europe/Riga">Europe/Riga</option>
<option value="Europe/Rome">Europe/Rome</option>
<option value="Europe/Sofia">Europe/Sofia</option>
<option value="Europe/Stockholm">Europe/Stockholm</option>
<option value="Europe/Tallinn">Europe/Tallinn</option>
<option value="Europe/Vienna">Europe/Vienna</option>
<option value="Europe/Vilnius">Europe/Vilnius</option>
<option value="Europe/Warsaw">Europe/Warsaw</option>
<option value="Europe/Zurich">Europe/Zurich</option>
<option value="Pacific/Auckland">Pacific/Auckland</option>
<option value="Pacific/Fiji">Pacific/Fiji</option>
<option value="Pacific/Guam">Pacific/Guam</option>
<option value="Pacific/Honolulu">Pacific/Honolulu</option>
<option value="Etc/UTC">Etc/UTC</option>
</select>
<div class="form-row two-col">
<div>
@@ -319,7 +401,47 @@ body.loaded {
<label class="small">(Seconds)</label>
</div>
</div>
<br><br><br>
<button type="button" class="collapsible-toggle" aria-expanded="false">
<span class="icon-area" aria-hidden="true">
<svg width="20" height="20" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path fill="currentColor" d="M16,9V7l-2.259-0.753c-0.113-0.372-0.262-0.728-0.441-1.066l1.066-2.131L12.95,1.634L10.819,2.7 c-0.338-0.178-0.694-0.325-1.066-0.441L9,0H7L6.247,2.259C5.875,2.372,5.519,2.522,5.181,2.7L3.05,1.638L1.638,3.05l1.066,2.131 C2.522,5.519,2.375,5.875,2.259,6.247L0,7v2l2.259,0.753c0.112,0.372,0.263,0.728,0.441,1.066L1.634,12.95l1.416,1.416L5.181,13.3 c0.338,0.178,0.694,0.328,1.066,0.441L7,16h2l0.753-2.259c0.372-0.113,0.728-0.262,1.066-0.441l2.131,1.066l1.416-1.416L13.3,10.819 c0.178-0.337,0.328-0.694,0.441-1.066L16,9z M8,11c-1.656,0-3-1.344-3-3s1.344-3,3-3s3,1.344,3,3S9.656,11,8,11z" />
</svg>
</span>
<span>Advanced Settings</span>
</button>
<div class="collapsible-content" aria-hidden="true">
<!-- Custom NTP Servers -->
<label>Primary NTP Server:</label>
<input type="text" name="ntpServer1" id="ntpServer1" placeholder="Enter NTP address">
<label>Secondary NTP Server:</label>
<input type="text" name="ntpServer2" id="ntpServer2" placeholder="Enter NTP address">
<!-- 24/12hrs Clock Toggle (Styled) -->
<label style="display: flex; align-items: center; margin-top: 1.75rem;">
<span style="margin-right: 0.5em;">Display 12-hour Clock</span>
<span class="toggle-switch">
<input type="checkbox" name="twelveHourToggle" id="twelveHourToggle">
<span class="toggle-slider"></span>
</span>
</label>
<!-- Display Flip Toggle (Styled) -->
<label style="display: flex; align-items: center; margin-top: 1.75rem;">
<span style="margin-right: 0.5em;">Flip Display (180°):</span>
<span class="toggle-switch">
<input type="checkbox" name="flipDisplay" id="flipDisplay">
<span class="toggle-slider"></span>
</span>
</label>
<!-- Brightness Slider with Value -->
<label style="margin-top: 1.75rem;">Brightness: <span id="brightnessValue">10</span></label>
<input type="range" min="0" max="15" name="brightness" id="brightnessSlider" value="10" oninput="brightnessValue.textContent = brightnessSlider.value">
<br>
</div>
<input type="submit" class="primary-button" value="Save Settings">
</form>
@@ -333,50 +455,20 @@ body.loaded {
let isSaving = false;
let isAPMode = false;
function ensureReloadButton(options = {}) {
let modalContent = document.getElementById('savingModalContent');
if (!modalContent) return;
let btn = document.getElementById('reloadButton');
if (!btn) {
btn = document.createElement('button');
btn.id = 'reloadButton';
btn.className = 'primary-button';
btn.style.display = 'inline-block';
btn.style.margin = '1rem 0.5rem 0 0';
modalContent.appendChild(btn);
}
btn.textContent = options.text || "Reload Page";
btn.onclick = options.onClick || (() => location.reload());
btn.style.display = 'inline-block';
return btn;
}
// Set initial value display for brightness
document.addEventListener('DOMContentLoaded', function() {
brightnessValue.textContent = brightnessSlider.value;
});
function ensureRestoreButton(options = {}) {
let modalContent = document.getElementById('savingModalContent');
if (!modalContent) return;
let btn = document.getElementById('restoreButton');
if (!btn) {
btn = document.createElement('button');
btn.id = 'restoreButton';
btn.className = 'primary-button';
btn.style.display = 'inline-block';
btn.style.margin = '1rem 0 0 0.5rem';
modalContent.appendChild(btn);
}
btn.textContent = options.text || "Restore Backup";
btn.onclick = options.onClick || restoreBackupConfig;
btn.style.display = 'inline-block';
return btn;
}
// Show/hide password toggle
document.addEventListener("DOMContentLoaded", function () {
const passwordInput = document.getElementById("password");
const toggleCheckbox = document.getElementById("togglePassword");
function removeReloadButton() {
let btn = document.getElementById('reloadButton');
if (btn && btn.parentNode) btn.parentNode.removeChild(btn);
}
function removeRestoreButton() {
let btn = document.getElementById('restoreButton');
if (btn && btn.parentNode) btn.parentNode.removeChild(btn);
}
toggleCheckbox.addEventListener("change", function () {
passwordInput.type = this.checked ? "text" : "password";
});
});
window.onbeforeunload = function () {
if (isSaving) {
@@ -401,7 +493,13 @@ window.onload = function () {
document.getElementById('weatherUnits').value = data.weatherUnits || 'metric';
document.getElementById('clockDuration').value = (data.clockDuration || 10000) / 1000;
document.getElementById('weatherDuration').value = (data.weatherDuration || 5000) / 1000;
// Advanced:
document.getElementById('brightnessSlider').value = typeof data.brightness !== "undefined" ? data.brightness : 10;
document.getElementById('brightnessValue').textContent = document.getElementById('brightnessSlider').value;
document.getElementById('flipDisplay').checked = !!data.flipDisplay;
document.getElementById('ntpServer1').value = data.ntpServer1 || "";
document.getElementById('ntpServer2').value = data.ntpServer2 || "";
document.getElementById('twelveHourToggle').checked = !!data.twelveHourToggle;
// Auto-detect browser's timezone if not set in config
if (!data.timeZone) {
try {
@@ -442,8 +540,6 @@ window.onload = function () {
});
document.querySelector('html').style.height = 'unset';
document.body.classList.add('loaded');
};
async function submitConfig(event) {
@@ -458,6 +554,11 @@ async function submitConfig(event) {
formData.set('clockDuration', clockDuration);
formData.set('weatherDuration', weatherDuration);
// Advanced: ensure correct values are set for advanced fields
formData.set('brightness', document.getElementById('brightnessSlider').value);
formData.set('flipDisplay', document.getElementById('flipDisplay').checked ? 'on' : '');
formData.set('twelveHourToggle', document.getElementById('twelveHourToggle').checked ? 'on' : '');
const params = new URLSearchParams();
for (const pair of formData.entries()) {
params.append(pair[0], pair[1]);
@@ -579,6 +680,51 @@ function updateSavingModal(message, showSpinner = false) {
}
}
function ensureReloadButton(options = {}) {
let modalContent = document.getElementById('savingModalContent');
if (!modalContent) return;
let btn = document.getElementById('reloadButton');
if (!btn) {
btn = document.createElement('button');
btn.id = 'reloadButton';
btn.className = 'primary-button';
btn.style.display = 'inline-block';
btn.style.margin = '1rem 0.5rem 0 0';
modalContent.appendChild(btn);
}
btn.textContent = options.text || "Reload Page";
btn.onclick = options.onClick || (() => location.reload());
btn.style.display = 'inline-block';
return btn;
}
function ensureRestoreButton(options = {}) {
let modalContent = document.getElementById('savingModalContent');
if (!modalContent) return;
let btn = document.getElementById('restoreButton');
if (!btn) {
btn = document.createElement('button');
btn.id = 'restoreButton';
btn.className = 'primary-button';
btn.style.display = 'inline-block';
btn.style.margin = '1rem 0 0 0.5rem';
modalContent.appendChild(btn);
}
btn.textContent = options.text || "Restore Backup";
btn.onclick = options.onClick || restoreBackupConfig;
btn.style.display = 'inline-block';
return btn;
}
function removeReloadButton() {
let btn = document.getElementById('reloadButton');
if (btn && btn.parentNode) btn.parentNode.removeChild(btn);
}
function removeRestoreButton() {
let btn = document.getElementById('restoreButton');
if (btn && btn.parentNode) btn.parentNode.removeChild(btn);
}
function restoreBackupConfig() {
showSavingModal("Restoring backup...");
removeReloadButton();
@@ -606,16 +752,6 @@ function restoreBackupConfig() {
});
}
// Show/hide password toggle
document.addEventListener("DOMContentLoaded", function () {
const passwordInput = document.getElementById("password");
const toggleCheckbox = document.getElementById("togglePassword");
toggleCheckbox.addEventListener("change", function () {
passwordInput.type = this.checked ? "text" : "password";
});
});
function hideSavingModal() {
const modal = document.getElementById('savingModal');
if (modal) {
@@ -623,6 +759,31 @@ function hideSavingModal() {
document.body.classList.remove('modal-open');
}
}
const toggle = document.querySelector('.collapsible-toggle');
const content = document.querySelector('.collapsible-content');
toggle.addEventListener('click', function() {
const isOpen = toggle.classList.toggle('open');
toggle.setAttribute('aria-expanded', isOpen);
content.setAttribute('aria-hidden', !isOpen);
if(isOpen) {
content.style.height = content.scrollHeight + 'px';
content.addEventListener('transitionend', function handler() {
content.style.height = 'auto';
content.removeEventListener('transitionend', handler);
});
} else {
content.style.height = content.scrollHeight + 'px';
// Force reflow to make sure the browser notices the height before transitioning to 0
void content.offsetHeight;
content.style.height = '0px';
}
});
// Optional: If open on load, set height to auto
if(toggle.classList.contains('open')) {
content.style.height = 'auto';
}
</script>
</body>
</html>
</html>