mirror of
https://github.com/nuttylmao/nutty.gg.git
synced 2026-09-18 19:50:58 -04:00
• Added language support
• Added timezone support
This commit is contained in:
@@ -188,6 +188,21 @@ function LoadJSON(settingsJson) {
|
|||||||
await PopulateFontDatalist();
|
await PopulateFontDatalist();
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
break;
|
break;
|
||||||
|
case 'timezone':
|
||||||
|
inputElement = document.createElement('input');
|
||||||
|
inputElement.type = 'text';
|
||||||
|
inputElement.placeholder = 'Type to search timezone...';
|
||||||
|
inputElement.id = setting.id;
|
||||||
|
inputElement.value = settingsMap.has(setting.id) ? settingsMap.get(setting.id) : setting.defaultValue;
|
||||||
|
inputElement.setAttribute('list', 'timezones');
|
||||||
|
inputElement.autocomplete = 'off';
|
||||||
|
|
||||||
|
// Populate datalist on focus (runs once)
|
||||||
|
inputElement.addEventListener('focus', function loadOnce() {
|
||||||
|
inputElement.removeEventListener('focus', loadOnce);
|
||||||
|
PopulateTimezoneDatalist();
|
||||||
|
}, { once: true });
|
||||||
|
break;
|
||||||
case 'button':
|
case 'button':
|
||||||
inputElement = document.createElement('button');
|
inputElement = document.createElement('button');
|
||||||
inputElement.id = setting.id; //Added setting ID
|
inputElement.id = setting.id; //Added setting ID
|
||||||
@@ -431,6 +446,30 @@ async function PopulateFontDatalist() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function PopulateTimezoneDatalist() {
|
||||||
|
try {
|
||||||
|
// Fetch all official IANA timezones natively from the browser
|
||||||
|
const timezones = Intl.supportedValuesOf('timeZone');
|
||||||
|
|
||||||
|
// Create the datalist element
|
||||||
|
const datalistElement = document.createElement('datalist');
|
||||||
|
datalistElement.id = 'timezones';
|
||||||
|
|
||||||
|
// Append each timezone as an option
|
||||||
|
timezones.forEach(tz => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = tz;
|
||||||
|
datalistElement.appendChild(option);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.appendChild(datalistElement);
|
||||||
|
console.debug(`Loaded ${timezones.length} timezones into auto-suggest.`);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error generating timezone suggestions:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
@@ -599,4 +638,7 @@ LoadSettingsFromStorage();
|
|||||||
LoadJSON(settingsJson);
|
LoadJSON(settingsJson);
|
||||||
|
|
||||||
// Populate local fonts for auto-suggest
|
// Populate local fonts for auto-suggest
|
||||||
PopulateFontDatalist();
|
PopulateFontDatalist();
|
||||||
|
|
||||||
|
// Populate timezones for auto-suggest
|
||||||
|
PopulateTimezoneDatalist();
|
||||||
|
|||||||
+36
-19
@@ -27,6 +27,8 @@ const line3 = document.getElementById('line3');
|
|||||||
/////////////
|
/////////////
|
||||||
|
|
||||||
const font = urlParams.get("font") || "";
|
const font = urlParams.get("font") || "";
|
||||||
|
const language = urlParams.get("language") || "en";
|
||||||
|
const timezone = urlParams.get("timezone") || "";
|
||||||
|
|
||||||
const enableLine1 = GetBooleanParam("enableLine1", true);
|
const enableLine1 = GetBooleanParam("enableLine1", true);
|
||||||
const line1Format = urlParams.get("line1Format") || "hh:mm:ss A";
|
const line1Format = urlParams.get("line1Format") || "hh:mm:ss A";
|
||||||
@@ -63,7 +65,7 @@ const line3TextAlignment = urlParams.get("line3TextAlignment") || "center";
|
|||||||
|
|
||||||
// Set the font for the entire page if specified
|
// Set the font for the entire page if specified
|
||||||
if (font)
|
if (font)
|
||||||
document.body.style.fontFamily = `'${font}'`;
|
document.body.style.fontFamily = `'${font}'`;
|
||||||
|
|
||||||
// Hide lines that are not enabled
|
// Hide lines that are not enabled
|
||||||
if (!enableLine1)
|
if (!enableLine1)
|
||||||
@@ -75,38 +77,53 @@ if (!enableLine3)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////
|
////////////////
|
||||||
// CLOCKO //
|
// CLOCKO //
|
||||||
////////////
|
////////////////
|
||||||
|
|
||||||
// Check if any active format string includes milliseconds (e.g., 'S', 'SS', 'SSS')
|
// Helper function to start the clock loop
|
||||||
const usesMilliseconds =
|
function StartClock() {
|
||||||
(enableLine1 && line1Format.includes('S')) ||
|
// Check if any active format string includes milliseconds (e.g., 'S', 'SS', 'SSS')
|
||||||
(enableLine2 && line2Format.includes('S')) ||
|
const usesMilliseconds =
|
||||||
(enableLine3 && line3Format.includes('S'));
|
(enableLine1 && line1Format.includes('S')) ||
|
||||||
|
(enableLine2 && line2Format.includes('S')) ||
|
||||||
|
(enableLine3 && line3Format.includes('S'));
|
||||||
|
|
||||||
UpdateTime();
|
UpdateTime();
|
||||||
|
|
||||||
if (usesMilliseconds) {
|
if (usesMilliseconds) {
|
||||||
// High-frequency updates for millisecond precision
|
function updateFrame() {
|
||||||
function updateFrame() {
|
UpdateTime();
|
||||||
UpdateTime();
|
requestAnimationFrame(updateFrame);
|
||||||
|
}
|
||||||
requestAnimationFrame(updateFrame);
|
requestAnimationFrame(updateFrame);
|
||||||
|
} else {
|
||||||
|
setInterval(UpdateTime, 1000);
|
||||||
}
|
}
|
||||||
requestAnimationFrame(updateFrame);
|
|
||||||
} else {
|
|
||||||
// Efficient 1-second interval for standard clocks
|
|
||||||
setInterval(UpdateTime, 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function UpdateTime() {
|
function UpdateTime() {
|
||||||
const now = dayjs().tz(dayjs.tz.guess());
|
const activeTimezone = timezone ? timezone : dayjs.tz.guess();
|
||||||
|
const now = dayjs().tz(activeTimezone);
|
||||||
|
|
||||||
if (enableLine1) line1.textContent = now.format(line1Format);
|
if (enableLine1) line1.textContent = now.format(line1Format);
|
||||||
if (enableLine2) line2.textContent = now.format(line2Format);
|
if (enableLine2) line2.textContent = now.format(line2Format);
|
||||||
if (enableLine3) line3.textContent = now.format(line3Format);
|
if (enableLine3) line3.textContent = now.format(line3Format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the language and start the clock only after it's loaded
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = `https://cdn.jsdelivr.net/npm/dayjs@1/locale/${language}.js`;
|
||||||
|
script.onload = () => {
|
||||||
|
dayjs.locale(language);
|
||||||
|
StartClock();
|
||||||
|
};
|
||||||
|
script.onerror = () => {
|
||||||
|
console.warn(`Locale '${language}' failed to load. Falling back to English.`);
|
||||||
|
dayjs.locale('en');
|
||||||
|
StartClock();
|
||||||
|
};
|
||||||
|
document.head.appendChild(script);
|
||||||
|
|
||||||
|
|
||||||
/////////////
|
/////////////
|
||||||
|
|||||||
@@ -1,5 +1,54 @@
|
|||||||
{
|
{
|
||||||
"settings": [
|
"settings": [
|
||||||
|
{
|
||||||
|
"id": "language",
|
||||||
|
"label": "Language",
|
||||||
|
"description": "",
|
||||||
|
"type": "select",
|
||||||
|
"options": [
|
||||||
|
{ "value": "en", "label": "English" },
|
||||||
|
{ "value": "ar", "label": "العربية (Arabic)" },
|
||||||
|
{ "value": "bg", "label": "Български (Bulgarian)" },
|
||||||
|
{ "value": "zh-cn", "label": "中文 (Chinese Simplified)" },
|
||||||
|
{ "value": "zh-tw", "label": "中文 (Chinese Traditional)" },
|
||||||
|
{ "value": "cs", "label": "Čeština (Czech)" },
|
||||||
|
{ "value": "da", "label": "Dansk (Danish)" },
|
||||||
|
{ "value": "nl", "label": "Nederlands (Dutch)" },
|
||||||
|
{ "value": "fi", "label": "Suomi (Finnish)" },
|
||||||
|
{ "value": "fr", "label": "Français (French)" },
|
||||||
|
{ "value": "de", "label": "Deutsch (German)" },
|
||||||
|
{ "value": "el", "label": "Ελληνικά (Greek)" },
|
||||||
|
{ "value": "he", "label": "עברית (Hebrew)" },
|
||||||
|
{ "value": "hi", "label": "हिन्दी (Hindi)" },
|
||||||
|
{ "value": "hu", "label": "Magyar (Hungarian)" },
|
||||||
|
{ "value": "id", "label": "Bahasa Indonesia (Indonesian)" },
|
||||||
|
{ "value": "it", "label": "Italiano (Italian)" },
|
||||||
|
{ "value": "ja", "label": "日本語 (Japanese)" },
|
||||||
|
{ "value": "ko", "label": "한국어 (Korean)" },
|
||||||
|
{ "value": "nb", "label": "Norsk bokmål (Norwegian Bokmål)" },
|
||||||
|
{ "value": "pl", "label": "Polski (Polish)" },
|
||||||
|
{ "value": "pt", "label": "Português (Portuguese)" },
|
||||||
|
{ "value": "ro", "label": "Română (Romanian)" },
|
||||||
|
{ "value": "ru", "label": "Русский (Russian)" },
|
||||||
|
{ "value": "sk", "label": "Slovenčina (Slovak)" },
|
||||||
|
{ "value": "es", "label": "Español (Spanish)" },
|
||||||
|
{ "value": "sv", "label": "Svenska (Swedish)" },
|
||||||
|
{ "value": "th", "label": "ไทย (Thai)" },
|
||||||
|
{ "value": "tr", "label": "Türkçe (Turkish)" },
|
||||||
|
{ "value": "uk", "label": "Українська (Ukrainian)" },
|
||||||
|
{ "value": "vi", "label": "Tiếng Việt (Vietnamese)" }
|
||||||
|
],
|
||||||
|
"defaultValue": "en",
|
||||||
|
"group": "General"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "timezone",
|
||||||
|
"label": "Timezone",
|
||||||
|
"description": "Enter an IANA timezone (e.g., America/New_York, Europe/London). Leave blank to use local time.",
|
||||||
|
"type": "timezone",
|
||||||
|
"defaultValue": "",
|
||||||
|
"group": "General"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "font",
|
"id": "font",
|
||||||
"label": "Font",
|
"label": "Font",
|
||||||
|
|||||||
Reference in New Issue
Block a user