4sp-dv 1.0.26 → 1.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/4simpleproblems_v5.html +87 -16
- package/component-library.html +1 -1
- package/logged-in/countdowns.html +1 -1
- package/logged-in/dailyphoto.html +1 -1
- package/logged-in/dashboard.html +140 -131
- package/logged-in/dictionary.html +1 -1
- package/logged-in/messenger-v2.html +1 -1
- package/logged-in/notes.html +1 -1
- package/logged-in/securly-tester.html +1 -1
- package/logged-in/soundboard.html +1 -1
- package/logged-in/test.html +1 -1
- package/logged-in/test2.html +1 -1
- package/logged-in/third-party-soundboard.html +1 -1
- package/logged-in/weather.html +70 -280
- package/navigation.js +1 -1
- package/package.json +1 -1
- package/test.html +1 -1
package/4simpleproblems_v5.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<title>4SP - VERSION 5 CLIENT</title>
|
|
7
7
|
<link rel="icon" type="image/png" href="https://cdn.jsdelivr.net/npm/4sp-dv@latest/images/logo.png">
|
|
8
8
|
|
|
9
|
-
<base href="https://cdn.jsdelivr.net/npm/4sp-dv@1.0.
|
|
9
|
+
<base href="https://cdn.jsdelivr.net/npm/4sp-dv@1.0.28/logged-in/">
|
|
10
10
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
11
11
|
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap" rel="stylesheet">
|
|
12
12
|
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
font-size: 1rem;
|
|
107
107
|
cursor: pointer;
|
|
108
108
|
opacity: 1;
|
|
109
|
-
transition: opacity 0.3s, color 0.3s ease;
|
|
109
|
+
transition: opacity 0.3s, color 0.3s ease, background-color 0.3s ease;
|
|
110
110
|
z-index: 55;
|
|
111
111
|
pointer-events: auto;
|
|
112
112
|
background: transparent;
|
|
@@ -115,13 +115,17 @@
|
|
|
115
115
|
|
|
116
116
|
#glide-left {
|
|
117
117
|
left: 0;
|
|
118
|
-
background:
|
|
118
|
+
background-color: var(--navbar-bg, #000000);
|
|
119
|
+
-webkit-mask-image: linear-gradient(to right, black 30%, transparent);
|
|
120
|
+
mask-image: linear-gradient(to right, black 30%, transparent);
|
|
119
121
|
justify-content: flex-start;
|
|
120
122
|
padding-left: 8px;
|
|
121
123
|
}
|
|
122
124
|
#glide-right {
|
|
123
125
|
right: 0;
|
|
124
|
-
background:
|
|
126
|
+
background-color: var(--navbar-bg, #000000);
|
|
127
|
+
-webkit-mask-image: linear-gradient(to left, black 30%, transparent);
|
|
128
|
+
mask-image: linear-gradient(to left, black 30%, transparent);
|
|
125
129
|
justify-content: flex-end;
|
|
126
130
|
padding-right: 8px;
|
|
127
131
|
}
|
|
@@ -140,7 +144,7 @@
|
|
|
140
144
|
.nav-tab:hover {
|
|
141
145
|
color: var(--tab-hover-text, #ffffff);
|
|
142
146
|
background-color: var(--tab-hover-bg, rgba(79, 70, 229, 0.05));
|
|
143
|
-
border-color: var(--tab-
|
|
147
|
+
border-color: var(--tab-active-border, #4f46e5);
|
|
144
148
|
transform: translateY(-1px);
|
|
145
149
|
z-index: 50;
|
|
146
150
|
}
|
|
@@ -424,7 +428,7 @@
|
|
|
424
428
|
}
|
|
425
429
|
.nav-tab:hover {
|
|
426
430
|
color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05);
|
|
427
|
-
border-color: #4f46e5; transform: scale(1.02);
|
|
431
|
+
border-color: var(--tab-active-border, #4f46e5); transform: scale(1.02);
|
|
428
432
|
z-index: 50;
|
|
429
433
|
}
|
|
430
434
|
|
|
@@ -611,7 +615,7 @@
|
|
|
611
615
|
</div>
|
|
612
616
|
|
|
613
617
|
<label class="block text-gray-400 text-xs mb-2 font-light">Background Color</label>
|
|
614
|
-
<div class="
|
|
618
|
+
<div class="flex flex-wrap gap-2 mb-6" id="pfp-color-grid">
|
|
615
619
|
<!-- Colors generated by JS -->
|
|
616
620
|
</div>
|
|
617
621
|
|
|
@@ -774,7 +778,16 @@
|
|
|
774
778
|
const displayUsername = document.getElementById('display-username');
|
|
775
779
|
const displayEmail = document.getElementById('display-email');
|
|
776
780
|
|
|
777
|
-
const BASE_URL = 'https://cdn.jsdelivr.net/npm/4sp-dv@1.0.
|
|
781
|
+
const BASE_URL = 'https://cdn.jsdelivr.net/npm/4sp-dv@1.0.28/logged-in/';
|
|
782
|
+
|
|
783
|
+
// Preload Logos
|
|
784
|
+
const preloadImgs = [
|
|
785
|
+
'https://cdn.jsdelivr.net/npm/4sp-dv@latest/images/logo-dark.png',
|
|
786
|
+
'https://cdn.jsdelivr.net/npm/4sp-dv@latest/images/logo-christmas.png',
|
|
787
|
+
'https://cdn.jsdelivr.net/npm/4sp-asset-library@latest/logo.png'
|
|
788
|
+
];
|
|
789
|
+
preloadImgs.forEach(src => new Image().src = src);
|
|
790
|
+
|
|
778
791
|
const STORAGE_KEY = 'local_access_code';
|
|
779
792
|
const USER_DATA_KEY = 'local_user_data';
|
|
780
793
|
const LAST_PAGE_KEY = 'local_last_page';
|
|
@@ -1109,7 +1122,26 @@
|
|
|
1109
1122
|
}
|
|
1110
1123
|
|
|
1111
1124
|
// Initial check
|
|
1112
|
-
setTimeout(
|
|
1125
|
+
setTimeout(() => {
|
|
1126
|
+
updateScrollGilders();
|
|
1127
|
+
|
|
1128
|
+
// Ensure Active Tab Visibility (Scroll if under gradient)
|
|
1129
|
+
const activeTab = tabsContainerEl.querySelector('.nav-tab.active');
|
|
1130
|
+
if (activeTab) {
|
|
1131
|
+
const containerRect = tabsContainerEl.getBoundingClientRect();
|
|
1132
|
+
const tabRect = activeTab.getBoundingClientRect();
|
|
1133
|
+
const gradientWidth = 70; // Gradient is ~60px + padding
|
|
1134
|
+
|
|
1135
|
+
// Check Left Edge
|
|
1136
|
+
if (tabRect.left < containerRect.left + gradientWidth) {
|
|
1137
|
+
tabsContainerEl.scrollBy({ left: tabRect.left - containerRect.left - gradientWidth - 20, behavior: 'smooth' });
|
|
1138
|
+
}
|
|
1139
|
+
// Check Right Edge
|
|
1140
|
+
else if (tabRect.right > containerRect.right - gradientWidth) {
|
|
1141
|
+
tabsContainerEl.scrollBy({ left: tabRect.right - containerRect.right + gradientWidth + 20, behavior: 'smooth' });
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}, 50);
|
|
1113
1145
|
}
|
|
1114
1146
|
|
|
1115
1147
|
// Auth Menu
|
|
@@ -1614,6 +1646,9 @@
|
|
|
1614
1646
|
if (sec.id === `tab-${tabId}`) sec.classList.remove('hidden');
|
|
1615
1647
|
else sec.classList.add('hidden');
|
|
1616
1648
|
});
|
|
1649
|
+
|
|
1650
|
+
// Save State
|
|
1651
|
+
localStorage.setItem('last_settings_tab', tabId);
|
|
1617
1652
|
});
|
|
1618
1653
|
});
|
|
1619
1654
|
|
|
@@ -1684,7 +1719,18 @@
|
|
|
1684
1719
|
// --- 2. Personalization ---
|
|
1685
1720
|
// Letter Avatar Setup
|
|
1686
1721
|
// Removed last color (Grey) to make 10 colors (5x2 grid)
|
|
1687
|
-
const letterColors = [
|
|
1722
|
+
const letterColors = [
|
|
1723
|
+
'EF4444', // Red
|
|
1724
|
+
'F97316', 'FDBA74', // Orange
|
|
1725
|
+
'EAB308', 'FDE047', // Yellow
|
|
1726
|
+
'22C55E', '86EFAC', // Green
|
|
1727
|
+
'06B6D4', '67E8F9', // Cyan
|
|
1728
|
+
'3B82F6', '93C5FD', // Blue
|
|
1729
|
+
'6366F1', 'A5B4FC', // Indigo
|
|
1730
|
+
'A855F7', 'D8B4FE', // Purple
|
|
1731
|
+
'EC4899', 'F9A8D4', // Pink
|
|
1732
|
+
'6B7280', '000000' // Grey & Black
|
|
1733
|
+
];
|
|
1688
1734
|
const pfpModeBtns = document.querySelectorAll('.pfp-mode-btn');
|
|
1689
1735
|
const pfpLetterOptions = document.getElementById('pfp-letter-options');
|
|
1690
1736
|
const pfpUploadOptions = document.getElementById('pfp-upload-options');
|
|
@@ -1726,6 +1772,11 @@
|
|
|
1726
1772
|
const div = document.createElement('div');
|
|
1727
1773
|
div.className = 'w-10 h-10 rounded-lg cursor-pointer hover:scale-110 transition border-2 border-transparent';
|
|
1728
1774
|
div.style.backgroundColor = '#' + color;
|
|
1775
|
+
|
|
1776
|
+
if (color === '000000') {
|
|
1777
|
+
div.style.borderColor = '#ffffff';
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1729
1780
|
div.onclick = () => {
|
|
1730
1781
|
pfpState.letterColor = '#' + color;
|
|
1731
1782
|
updatePfpPreview();
|
|
@@ -2096,24 +2147,36 @@
|
|
|
2096
2147
|
// Apply Logo & Tinting
|
|
2097
2148
|
const logoImg = document.getElementById('navbar-logo');
|
|
2098
2149
|
if (logoImg) {
|
|
2099
|
-
// Update Source (Use absolute path comparison or specific logic)
|
|
2100
|
-
// We just set it. Browser handles cache.
|
|
2101
|
-
// Note: The original navigation.js checked src endsWith to avoid reload flicker, but simple assignment is okay.
|
|
2102
2150
|
if (!logoImg.src.includes(logoSrc)) {
|
|
2103
2151
|
logoImg.src = logoSrc;
|
|
2104
2152
|
}
|
|
2105
2153
|
|
|
2106
|
-
// Apply Tinting
|
|
2107
2154
|
const noFilterThemes = ['Dark', 'Light', 'Christmas'];
|
|
2108
|
-
|
|
2155
|
+
const isNoFilter = noFilterThemes.includes(theme.name);
|
|
2156
|
+
|
|
2157
|
+
// Check if mode is changing (Tinted <-> Standard)
|
|
2158
|
+
// We check existing transform state
|
|
2159
|
+
const wasNoFilter = logoImg.style.transform === '' || logoImg.style.transform === 'none';
|
|
2160
|
+
const modeChanged = isNoFilter !== wasNoFilter;
|
|
2161
|
+
|
|
2162
|
+
if (modeChanged) {
|
|
2163
|
+
logoImg.style.transition = 'none';
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
if (isNoFilter) {
|
|
2109
2167
|
logoImg.style.filter = '';
|
|
2110
2168
|
logoImg.style.transform = '';
|
|
2111
2169
|
} else {
|
|
2112
2170
|
const tintColor = theme['tab-active-text'] || '#ffffff';
|
|
2113
|
-
// The original navigation.js used this trick for SVG coloring via filter
|
|
2114
2171
|
logoImg.style.filter = `drop-shadow(100px 0 0 ${tintColor})`;
|
|
2115
2172
|
logoImg.style.transform = 'translateX(-100px)';
|
|
2116
2173
|
}
|
|
2174
|
+
|
|
2175
|
+
if (modeChanged) {
|
|
2176
|
+
// Force Reflow
|
|
2177
|
+
void logoImg.offsetWidth;
|
|
2178
|
+
logoImg.style.transition = ''; // Restore
|
|
2179
|
+
}
|
|
2117
2180
|
}
|
|
2118
2181
|
|
|
2119
2182
|
// Save to local storage for persistence on reload
|
|
@@ -2371,6 +2434,14 @@
|
|
|
2371
2434
|
|
|
2372
2435
|
updatePfpPreview();
|
|
2373
2436
|
}
|
|
2437
|
+
|
|
2438
|
+
// Restore Tab
|
|
2439
|
+
const lastTab = localStorage.getItem('last_settings_tab');
|
|
2440
|
+
if (lastTab) {
|
|
2441
|
+
const tabBtn = document.querySelector(`.settings-tab[data-tab="${lastTab}"]`);
|
|
2442
|
+
if(tabBtn) tabBtn.click();
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2374
2445
|
loadThemes();
|
|
2375
2446
|
loadPanicKeys();
|
|
2376
2447
|
}
|
package/component-library.html
CHANGED
|
@@ -525,7 +525,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
525
525
|
.input-key-style:focus { border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5); transform: scale(1.1); }
|
|
526
526
|
.settings-box { border: 1px solid #333; border-radius: 24px; background-color: #000000; padding: 1.5rem; }
|
|
527
527
|
.nav-tab { padding: 0.5rem 1rem; color: var(--tab-text); font-size: 0.875rem; font-weight: 400; border-radius: 12px; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; border: 1px solid transparent; cursor: pointer; background: transparent; }
|
|
528
|
-
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color:
|
|
528
|
+
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color: var(--tab-active-border); transform: scale(1.05); }
|
|
529
529
|
.nav-tab.active { color: var(--tab-active-text); border-color: var(--tab-active-border); background-color: var(--tab-active-bg); transform: scale(1.05); }
|
|
530
530
|
.eagler-dropdown { position: relative; background-color: rgba(20, 20, 20, 0.98); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 14px; padding: 0.5rem; min-width: 200px; display: inline-block; }
|
|
531
531
|
.eagler-dropdown-link { display: block; padding: 0.6rem 0.8rem; color: #d1d5db; text-decoration: none; border-radius: 14px; font-size: 0.9rem; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
|
@@ -368,7 +368,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
368
368
|
.input-key-style:focus { border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5); transform: scale(1.1); }
|
|
369
369
|
.settings-box { border: 1px solid #333; border-radius: 24px; background-color: #000000; padding: 1.5rem; }
|
|
370
370
|
.nav-tab { padding: 0.5rem 1rem; color: var(--tab-text); font-size: 0.875rem; font-weight: 400; border-radius: 12px; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; border: 1px solid transparent; cursor: pointer; background: transparent; }
|
|
371
|
-
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color:
|
|
371
|
+
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color: var(--tab-active-border); transform: scale(1.05); }
|
|
372
372
|
.nav-tab.active { color: var(--tab-active-text); border-color: var(--tab-active-border); background-color: var(--tab-active-bg); transform: scale(1.05); }
|
|
373
373
|
.eagler-dropdown { position: relative; background-color: rgba(20, 20, 20, 0.98); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 14px; padding: 0.5rem; min-width: 200px; display: inline-block; }
|
|
374
374
|
.eagler-dropdown-link { display: block; padding: 0.6rem 0.8rem; color: #d1d5db; text-decoration: none; border-radius: 14px; font-size: 0.9rem; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
package/logged-in/dashboard.html
CHANGED
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
|
|
75
75
|
/* Enable absolute positioning for spinner */
|
|
76
76
|
position: relative;
|
|
77
|
+
min-height: 200px; /* Ensure height stability */
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
.dashboard-widget:hover {
|
|
@@ -125,6 +126,12 @@
|
|
|
125
126
|
width: 1px;
|
|
126
127
|
height: 100px;
|
|
127
128
|
background-color: #262626;
|
|
129
|
+
transition: opacity 0.5s ease, width 0.5s ease;
|
|
130
|
+
}
|
|
131
|
+
.vertical-divider.hidden-anim {
|
|
132
|
+
opacity: 0;
|
|
133
|
+
width: 0;
|
|
134
|
+
margin: 0;
|
|
128
135
|
}
|
|
129
136
|
|
|
130
137
|
/* --- WEATHER STYLES --- */
|
|
@@ -134,6 +141,15 @@
|
|
|
134
141
|
flex-direction: column;
|
|
135
142
|
justify-content: center;
|
|
136
143
|
gap: 0.5rem;
|
|
144
|
+
transition: opacity 0.5s ease, transform 0.5s ease;
|
|
145
|
+
opacity: 1;
|
|
146
|
+
transform: translateY(0);
|
|
147
|
+
}
|
|
148
|
+
.weather-section.hidden-anim {
|
|
149
|
+
opacity: 0;
|
|
150
|
+
transform: translateY(10px);
|
|
151
|
+
pointer-events: none;
|
|
152
|
+
position: absolute; /* Take out of flow when hidden */
|
|
137
153
|
}
|
|
138
154
|
|
|
139
155
|
.weather-main {
|
|
@@ -213,6 +229,38 @@
|
|
|
213
229
|
font-size: 1.2rem;
|
|
214
230
|
}
|
|
215
231
|
|
|
232
|
+
/* Retry Button */
|
|
233
|
+
#retry-weather-btn {
|
|
234
|
+
position: fixed;
|
|
235
|
+
bottom: 2rem;
|
|
236
|
+
right: 2rem;
|
|
237
|
+
width: 40px;
|
|
238
|
+
height: 40px;
|
|
239
|
+
border-radius: 14px;
|
|
240
|
+
border: 1px solid #4b5563;
|
|
241
|
+
background: transparent;
|
|
242
|
+
color: #d1d5db;
|
|
243
|
+
display: flex;
|
|
244
|
+
align-items: center;
|
|
245
|
+
justify-content: center;
|
|
246
|
+
cursor: pointer;
|
|
247
|
+
z-index: 100;
|
|
248
|
+
opacity: 0;
|
|
249
|
+
pointer-events: none;
|
|
250
|
+
transition: opacity 0.5s ease, transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), background-color 0.2s;
|
|
251
|
+
transform: scale(0.8) translateY(20px);
|
|
252
|
+
}
|
|
253
|
+
#retry-weather-btn:hover {
|
|
254
|
+
background-color: #374151;
|
|
255
|
+
color: white;
|
|
256
|
+
transform: scale(1.1) translateY(0);
|
|
257
|
+
}
|
|
258
|
+
#retry-weather-btn.visible {
|
|
259
|
+
opacity: 1;
|
|
260
|
+
pointer-events: auto;
|
|
261
|
+
transform: scale(1) translateY(0);
|
|
262
|
+
}
|
|
263
|
+
|
|
216
264
|
/* Font Awesome's base spin animation (needed for custom speed) */
|
|
217
265
|
@keyframes fa-spin {
|
|
218
266
|
0% {
|
|
@@ -250,7 +298,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
250
298
|
.input-key-style:focus { border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5); transform: scale(1.1); }
|
|
251
299
|
.settings-box { border: 1px solid #333; border-radius: 24px; background-color: #000000; padding: 1.5rem; }
|
|
252
300
|
.nav-tab { padding: 0.5rem 1rem; color: var(--tab-text); font-size: 0.875rem; font-weight: 400; border-radius: 12px; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; border: 1px solid transparent; cursor: pointer; background: transparent; }
|
|
253
|
-
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color:
|
|
301
|
+
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color: var(--tab-active-border); transform: scale(1.05); }
|
|
254
302
|
.nav-tab.active { color: var(--tab-active-text); border-color: var(--tab-active-border); background-color: var(--tab-active-bg); transform: scale(1.05); }
|
|
255
303
|
.eagler-dropdown { position: relative; background-color: rgba(20, 20, 20, 0.98); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 14px; padding: 0.5rem; min-width: 200px; display: inline-block; }
|
|
256
304
|
.eagler-dropdown-link { display: block; padding: 0.6rem 0.8rem; color: #d1d5db; text-decoration: none; border-radius: 14px; font-size: 0.9rem; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
|
@@ -276,9 +324,9 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
276
324
|
<div id="clock-date" class="date-display">--------</div>
|
|
277
325
|
</div>
|
|
278
326
|
|
|
279
|
-
<div class="vertical-divider"></div>
|
|
327
|
+
<div class="vertical-divider" id="weather-divider"></div>
|
|
280
328
|
|
|
281
|
-
<div class="weather-section">
|
|
329
|
+
<div class="weather-section" id="weather-content">
|
|
282
330
|
<div class="weather-main">
|
|
283
331
|
<div id="w-icon" class="weather-icon"><i class="fa-solid fa-cloud"></i></div>
|
|
284
332
|
<div id="w-temp" class="weather-temp">--°</div>
|
|
@@ -301,6 +349,10 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
301
349
|
</div>
|
|
302
350
|
</div>
|
|
303
351
|
|
|
352
|
+
<button id="retry-weather-btn" onclick="retryWeather()" title="Retry Weather">
|
|
353
|
+
<i class="fa-solid fa-cloud-sun"></i>
|
|
354
|
+
</button>
|
|
355
|
+
|
|
304
356
|
<div id="weather-loader">
|
|
305
357
|
<i class="fa-solid fa-circle-notch fa-spin-slow"></i>
|
|
306
358
|
</div>
|
|
@@ -329,6 +381,10 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
329
381
|
const wWindArrow = document.getElementById('w-wind-arrow');
|
|
330
382
|
const wLocLink = document.getElementById('w-location-link');
|
|
331
383
|
const weatherLoader = document.getElementById('weather-loader');
|
|
384
|
+
|
|
385
|
+
const weatherContent = document.getElementById('weather-content');
|
|
386
|
+
const weatherDivider = document.getElementById('weather-divider');
|
|
387
|
+
const retryBtn = document.getElementById('retry-weather-btn');
|
|
332
388
|
|
|
333
389
|
// --- LOADER FUNCTIONS ---
|
|
334
390
|
function showLoader() {
|
|
@@ -339,6 +395,35 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
339
395
|
weatherLoader.classList.remove('loading');
|
|
340
396
|
}
|
|
341
397
|
|
|
398
|
+
// --- ERROR STATE UI ---
|
|
399
|
+
function showRetryState() {
|
|
400
|
+
hideLoader();
|
|
401
|
+
weatherContent.classList.add('hidden-anim');
|
|
402
|
+
weatherDivider.classList.add('hidden-anim');
|
|
403
|
+
retryBtn.classList.add('visible');
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function hideRetryState() {
|
|
407
|
+
retryBtn.classList.remove('visible');
|
|
408
|
+
// We don't immediately show weatherContent, wait for data or loader
|
|
409
|
+
// But we can prep them
|
|
410
|
+
weatherContent.classList.remove('hidden-anim');
|
|
411
|
+
weatherDivider.classList.remove('hidden-anim');
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// --- RETRY LOGIC ---
|
|
415
|
+
window.retryWeather = function() {
|
|
416
|
+
hideRetryState();
|
|
417
|
+
showLoader();
|
|
418
|
+
|
|
419
|
+
// If we have coords, use them. If not, re-init.
|
|
420
|
+
if (CURRENT_LAT && CURRENT_LON) {
|
|
421
|
+
loadWeatherPrimary(CURRENT_LAT, CURRENT_LON);
|
|
422
|
+
} else {
|
|
423
|
+
initWeather();
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
|
|
342
427
|
// --- FIREBASE INIT WAITER ---
|
|
343
428
|
function waitForFirebase(callback) {
|
|
344
429
|
const check = setInterval(() => {
|
|
@@ -416,30 +501,42 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
416
501
|
// Cache is fresh, use it
|
|
417
502
|
console.log("Using cached weather data.");
|
|
418
503
|
updateWeatherUI(cache.weatherData);
|
|
419
|
-
hideLoader();
|
|
504
|
+
hideLoader();
|
|
505
|
+
// Ensure UI is visible
|
|
506
|
+
weatherContent.classList.remove('hidden-anim');
|
|
507
|
+
weatherDivider.classList.remove('hidden-anim');
|
|
508
|
+
retryBtn.classList.remove('visible');
|
|
420
509
|
} else {
|
|
421
510
|
// Cache is stale or non-existent, fetch new data
|
|
422
511
|
console.log("Weather cache stale or missing. Fetching new data.");
|
|
423
512
|
resetWeatherDisplay();
|
|
424
|
-
|
|
513
|
+
loadWeatherPrimary(lat, lon);
|
|
425
514
|
}
|
|
426
515
|
}
|
|
427
516
|
|
|
428
517
|
// --- LOCATION FETCH (IP Fallback) ---
|
|
429
518
|
async function initWeather() {
|
|
430
|
-
showLoader();
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
519
|
+
showLoader();
|
|
520
|
+
// Hide previous state to avoid clutter during load
|
|
521
|
+
weatherContent.classList.add('hidden-anim');
|
|
522
|
+
weatherDivider.classList.add('hidden-anim');
|
|
523
|
+
retryBtn.classList.remove('visible');
|
|
524
|
+
|
|
525
|
+
try {
|
|
526
|
+
const ipRes = await fetch('https://ipapi.co/json/');
|
|
527
|
+
if (!ipRes.ok) throw new Error('IP API Error');
|
|
528
|
+
const ipData = await ipRes.json();
|
|
529
|
+
|
|
530
|
+
// Store globally so retry can use it
|
|
531
|
+
CURRENT_LAT = ipData.latitude;
|
|
532
|
+
CURRENT_LON = ipData.longitude;
|
|
533
|
+
|
|
534
|
+
loadWeatherPrimary(CURRENT_LAT, CURRENT_LON);
|
|
535
|
+
} catch (e) {
|
|
536
|
+
console.warn("IP location fetch failed:", e);
|
|
537
|
+
// Even if location fails, show retry button
|
|
538
|
+
showRetryState();
|
|
539
|
+
}
|
|
443
540
|
}
|
|
444
541
|
|
|
445
542
|
// --- LOCATION FETCH (Browser Geolocation) ---
|
|
@@ -449,8 +546,13 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
449
546
|
return;
|
|
450
547
|
}
|
|
451
548
|
|
|
452
|
-
showLoader();
|
|
549
|
+
showLoader();
|
|
453
550
|
resetWeatherDisplay();
|
|
551
|
+
|
|
552
|
+
// Hide content while locating
|
|
553
|
+
weatherContent.classList.add('hidden-anim');
|
|
554
|
+
weatherDivider.classList.add('hidden-anim');
|
|
555
|
+
retryBtn.classList.remove('visible');
|
|
454
556
|
|
|
455
557
|
try {
|
|
456
558
|
const pos = await new Promise((resolve, reject) => {
|
|
@@ -463,131 +565,33 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
463
565
|
CURRENT_LAT = pos.coords.latitude;
|
|
464
566
|
CURRENT_LON = pos.coords.longitude;
|
|
465
567
|
|
|
466
|
-
|
|
467
|
-
loadWeatherWithFallback(CURRENT_LAT, CURRENT_LON);
|
|
568
|
+
loadWeatherPrimary(CURRENT_LAT, CURRENT_LON);
|
|
468
569
|
|
|
469
570
|
} catch(e) {
|
|
470
571
|
console.error("Geolocation failed:", e);
|
|
471
|
-
//
|
|
472
|
-
|
|
572
|
+
// On geo fail, try init (IP) again? Or just error state.
|
|
573
|
+
// Let's go to error state to let user retry or see issue
|
|
574
|
+
showRetryState();
|
|
473
575
|
}
|
|
474
576
|
}
|
|
475
577
|
|
|
476
|
-
// ---
|
|
477
|
-
async function
|
|
478
|
-
// Loader is already shown by calling functions (initWeather or getUserBrowserLocation)
|
|
578
|
+
// --- PRIMARY FETCH (OPEN METEO ONLY) ---
|
|
579
|
+
async function loadWeatherPrimary(lat, lon) {
|
|
479
580
|
try {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
} catch(e) {
|
|
485
|
-
console.warn("Google Weather failed, attempting NWS:", e);
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
// 2. NWS - SECONDARY
|
|
489
|
-
try {
|
|
490
|
-
await fetchNWS(lat, lon);
|
|
491
|
-
return;
|
|
492
|
-
} catch(e) {
|
|
493
|
-
console.warn("NWS failed, attempting Open-Meteo:", e);
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// 3. Open-Meteo - TERTIARY
|
|
497
|
-
try {
|
|
498
|
-
await fetchOpenMeteo(lat, lon);
|
|
499
|
-
} catch(e) {
|
|
500
|
-
console.error("All weather sources failed", e);
|
|
501
|
-
hideLoader(); // Hide on absolute failure
|
|
502
|
-
}
|
|
503
|
-
} catch (finalError) {
|
|
504
|
-
// Catches errors during the fallback chain setup
|
|
505
|
-
hideLoader();
|
|
581
|
+
await fetchOpenMeteo(lat, lon);
|
|
582
|
+
} catch (error) {
|
|
583
|
+
console.error("Weather fetch failed:", error);
|
|
584
|
+
showRetryState();
|
|
506
585
|
}
|
|
507
586
|
}
|
|
508
587
|
|
|
509
|
-
// --- GOOGLE WEATHER FETCH ---
|
|
510
|
-
async function fetchGoogleWeather(lat, lon) {
|
|
511
|
-
const apiKey = firebaseConfig.apiKey;
|
|
512
|
-
const url = `https://weather.googleapis.com/v1/currentConditions:lookup?key=${apiKey}&location.latitude=${lat}&location.longitude=${lon}`;
|
|
513
|
-
|
|
514
|
-
const res = await fetch(url);
|
|
515
|
-
if (!res.ok) {
|
|
516
|
-
const errText = await res.text();
|
|
517
|
-
console.error("Google Weather API Failed. Details:", errText);
|
|
518
|
-
throw new Error(`Google Weather Error: ${res.status} - ${errText}`);
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
const data = await res.json();
|
|
522
|
-
if (!data.currentConditions) throw new Error("Invalid Google Weather Data");
|
|
523
|
-
|
|
524
|
-
const curr = data.currentConditions;
|
|
525
|
-
|
|
526
|
-
let tempF = curr.temperature?.value;
|
|
527
|
-
if (curr.temperature?.unit?.toLowerCase() === 'celsius' || curr.temperature?.unit?.toLowerCase() === 'c') {
|
|
528
|
-
tempF = (tempF * 9/5) + 32;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
const weatherCode = curr.weatherCondition || "CLOUDY";
|
|
532
|
-
|
|
533
|
-
const weatherData = {
|
|
534
|
-
temp: Math.round(tempF || 0),
|
|
535
|
-
iconCode: weatherCode,
|
|
536
|
-
isDay: true,
|
|
537
|
-
high: "--",
|
|
538
|
-
low: "--",
|
|
539
|
-
windSpeed: (curr.windSpeed?.value || 0) + " mph",
|
|
540
|
-
windDir: curr.windDirection || 0,
|
|
541
|
-
isNWS: false,
|
|
542
|
-
isGoogle: true
|
|
543
|
-
};
|
|
544
|
-
|
|
545
|
-
setWeatherCache(weatherData);
|
|
546
|
-
updateWeatherUI(weatherData);
|
|
547
|
-
hideLoader(); // Hide loader on success
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// --- NWS FETCH ---
|
|
551
|
-
async function fetchNWS(lat, lon) {
|
|
552
|
-
const pointsRes = await fetch(`https://api.weather.gov/points/${lat},${lon}`);
|
|
553
|
-
if (!pointsRes.ok) throw new Error("NWS Point Fail");
|
|
554
|
-
const pointsData = await pointsRes.json();
|
|
555
|
-
|
|
556
|
-
const [forecastRes, hourlyRes] = await Promise.all([
|
|
557
|
-
fetch(pointsData.properties.forecast),
|
|
558
|
-
fetch(pointsData.properties.forecastHourly)
|
|
559
|
-
]);
|
|
560
|
-
|
|
561
|
-
const dailyData = await forecastRes.json();
|
|
562
|
-
const hourlyData = await hourlyRes.json();
|
|
563
|
-
|
|
564
|
-
const current = hourlyData.properties.periods[0];
|
|
565
|
-
|
|
566
|
-
const first24 = hourlyData.properties.periods.slice(0, 24);
|
|
567
|
-
const temps = first24.map(p => p.temperature);
|
|
568
|
-
const high = Math.max(...temps);
|
|
569
|
-
const low = Math.min(...temps);
|
|
570
|
-
|
|
571
|
-
const weatherData = {
|
|
572
|
-
temp: current.temperature,
|
|
573
|
-
iconCode: current.shortForecast,
|
|
574
|
-
isDay: current.isDaytime,
|
|
575
|
-
high: high,
|
|
576
|
-
low: low,
|
|
577
|
-
windSpeed: current.windSpeed,
|
|
578
|
-
windDir: current.windDirection,
|
|
579
|
-
isNWS: true
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
setWeatherCache(weatherData);
|
|
583
|
-
updateWeatherUI(weatherData);
|
|
584
|
-
hideLoader(); // Hide loader on success
|
|
585
|
-
}
|
|
586
|
-
|
|
587
588
|
// --- OPEN METEO FETCH ---
|
|
588
589
|
async function fetchOpenMeteo(lat, lon) {
|
|
589
590
|
const url = `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}¤t=temperature_2m,is_day,weather_code,wind_speed_10m,wind_direction_10m&daily=temperature_2m_max,temperature_2m_min&temperature_unit=fahrenheit&wind_speed_unit=mph&timezone=auto`;
|
|
591
|
+
|
|
590
592
|
const res = await fetch(url);
|
|
593
|
+
if (!res.ok) throw new Error("Open-Meteo API response not OK");
|
|
594
|
+
|
|
591
595
|
const data = await res.json();
|
|
592
596
|
|
|
593
597
|
const weatherData = {
|
|
@@ -603,7 +607,12 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
603
607
|
|
|
604
608
|
setWeatherCache(weatherData);
|
|
605
609
|
updateWeatherUI(weatherData);
|
|
606
|
-
|
|
610
|
+
|
|
611
|
+
hideLoader();
|
|
612
|
+
// Success: Reveal UI
|
|
613
|
+
weatherContent.classList.remove('hidden-anim');
|
|
614
|
+
weatherDivider.classList.remove('hidden-anim');
|
|
615
|
+
retryBtn.classList.remove('visible');
|
|
607
616
|
}
|
|
608
617
|
|
|
609
618
|
// --- UI UPDATE (Unchanged) ---
|
|
@@ -248,7 +248,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
248
248
|
.input-key-style:focus { border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5); transform: scale(1.1); }
|
|
249
249
|
.settings-box { border: 1px solid #333; border-radius: 24px; background-color: #000000; padding: 1.5rem; }
|
|
250
250
|
.nav-tab { padding: 0.5rem 1rem; color: var(--tab-text); font-size: 0.875rem; font-weight: 400; border-radius: 12px; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; border: 1px solid transparent; cursor: pointer; background: transparent; }
|
|
251
|
-
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color:
|
|
251
|
+
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color: var(--tab-active-border); transform: scale(1.05); }
|
|
252
252
|
.nav-tab.active { color: var(--tab-active-text); border-color: var(--tab-active-border); background-color: var(--tab-active-bg); transform: scale(1.05); }
|
|
253
253
|
.eagler-dropdown { position: relative; background-color: rgba(20, 20, 20, 0.98); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 14px; padding: 0.5rem; min-width: 200px; display: inline-block; }
|
|
254
254
|
.eagler-dropdown-link { display: block; padding: 0.6rem 0.8rem; color: #d1d5db; text-decoration: none; border-radius: 14px; font-size: 0.9rem; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
|
@@ -265,7 +265,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
265
265
|
.input-key-style:focus { border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5); transform: scale(1.1); }
|
|
266
266
|
.settings-box { border: 1px solid #333; border-radius: 24px; background-color: #000000; padding: 1.5rem; }
|
|
267
267
|
.nav-tab { padding: 0.5rem 1rem; color: var(--tab-text); font-size: 0.875rem; font-weight: 400; border-radius: 12px; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; border: 1px solid transparent; cursor: pointer; background: transparent; }
|
|
268
|
-
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color:
|
|
268
|
+
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color: var(--tab-active-border); transform: scale(1.05); }
|
|
269
269
|
.nav-tab.active { color: var(--tab-active-text); border-color: var(--tab-active-border); background-color: var(--tab-active-bg); transform: scale(1.05); }
|
|
270
270
|
.eagler-dropdown { position: relative; background-color: rgba(20, 20, 20, 0.98); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 14px; padding: 0.5rem; min-width: 200px; display: inline-block; }
|
|
271
271
|
.eagler-dropdown-link { display: block; padding: 0.6rem 0.8rem; color: #d1d5db; text-decoration: none; border-radius: 14px; font-size: 0.9rem; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
package/logged-in/notes.html
CHANGED
|
@@ -395,7 +395,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
395
395
|
.input-key-style:focus { border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5); transform: scale(1.1); }
|
|
396
396
|
.settings-box { border: 1px solid #333; border-radius: 24px; background-color: #000000; padding: 1.5rem; }
|
|
397
397
|
.nav-tab { padding: 0.5rem 1rem; color: var(--tab-text); font-size: 0.875rem; font-weight: 400; border-radius: 12px; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; border: 1px solid transparent; cursor: pointer; background: transparent; }
|
|
398
|
-
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color:
|
|
398
|
+
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color: var(--tab-active-border); transform: scale(1.05); }
|
|
399
399
|
.nav-tab.active { color: var(--tab-active-text); border-color: var(--tab-active-border); background-color: var(--tab-active-bg); transform: scale(1.05); }
|
|
400
400
|
.eagler-dropdown { position: relative; background-color: rgba(20, 20, 20, 0.98); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 14px; padding: 0.5rem; min-width: 200px; display: inline-block; }
|
|
401
401
|
.eagler-dropdown-link { display: block; padding: 0.6rem 0.8rem; color: #d1d5db; text-decoration: none; border-radius: 14px; font-size: 0.9rem; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
|
@@ -211,7 +211,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
211
211
|
.input-key-style:focus { border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5); transform: scale(1.1); }
|
|
212
212
|
.settings-box { border: 1px solid #333; border-radius: 24px; background-color: #000000; padding: 1.5rem; }
|
|
213
213
|
.nav-tab { padding: 0.5rem 1rem; color: var(--tab-text); font-size: 0.875rem; font-weight: 400; border-radius: 12px; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; border: 1px solid transparent; cursor: pointer; background: transparent; }
|
|
214
|
-
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color:
|
|
214
|
+
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color: var(--tab-active-border); transform: scale(1.05); }
|
|
215
215
|
.nav-tab.active { color: var(--tab-active-text); border-color: var(--tab-active-border); background-color: var(--tab-active-bg); transform: scale(1.05); }
|
|
216
216
|
.eagler-dropdown { position: relative; background-color: rgba(20, 20, 20, 0.98); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 14px; padding: 0.5rem; min-width: 200px; display: inline-block; }
|
|
217
217
|
.eagler-dropdown-link { display: block; padding: 0.6rem 0.8rem; color: #d1d5db; text-decoration: none; border-radius: 14px; font-size: 0.9rem; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
|
@@ -287,7 +287,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
287
287
|
.input-key-style:focus { border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5); transform: scale(1.1); }
|
|
288
288
|
.settings-box { border: 1px solid #333; border-radius: 24px; background-color: #000000; padding: 1.5rem; }
|
|
289
289
|
.nav-tab { padding: 0.5rem 1rem; color: var(--tab-text); font-size: 0.875rem; font-weight: 400; border-radius: 12px; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; border: 1px solid transparent; cursor: pointer; background: transparent; }
|
|
290
|
-
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color:
|
|
290
|
+
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color: var(--tab-active-border); transform: scale(1.05); }
|
|
291
291
|
.nav-tab.active { color: var(--tab-active-text); border-color: var(--tab-active-border); background-color: var(--tab-active-bg); transform: scale(1.05); }
|
|
292
292
|
.eagler-dropdown { position: relative; background-color: rgba(20, 20, 20, 0.98); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 14px; padding: 0.5rem; min-width: 200px; display: inline-block; }
|
|
293
293
|
.eagler-dropdown-link { display: block; padding: 0.6rem 0.8rem; color: #d1d5db; text-decoration: none; border-radius: 14px; font-size: 0.9rem; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
package/logged-in/test.html
CHANGED
|
@@ -271,7 +271,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
271
271
|
.input-key-style:focus { border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5); transform: scale(1.1); }
|
|
272
272
|
.settings-box { border: 1px solid #333; border-radius: 24px; background-color: #000000; padding: 1.5rem; }
|
|
273
273
|
.nav-tab { padding: 0.5rem 1rem; color: var(--tab-text); font-size: 0.875rem; font-weight: 400; border-radius: 12px; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; border: 1px solid transparent; cursor: pointer; background: transparent; }
|
|
274
|
-
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color:
|
|
274
|
+
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color: var(--tab-active-border); transform: scale(1.05); }
|
|
275
275
|
.nav-tab.active { color: var(--tab-active-text); border-color: var(--tab-active-border); background-color: var(--tab-active-bg); transform: scale(1.05); }
|
|
276
276
|
.eagler-dropdown { position: relative; background-color: rgba(20, 20, 20, 0.98); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 14px; padding: 0.5rem; min-width: 200px; display: inline-block; }
|
|
277
277
|
.eagler-dropdown-link { display: block; padding: 0.6rem 0.8rem; color: #d1d5db; text-decoration: none; border-radius: 14px; font-size: 0.9rem; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
package/logged-in/test2.html
CHANGED
|
@@ -270,7 +270,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
270
270
|
.input-key-style:focus { border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5); transform: scale(1.1); }
|
|
271
271
|
.settings-box { border: 1px solid #333; border-radius: 24px; background-color: #000000; padding: 1.5rem; }
|
|
272
272
|
.nav-tab { padding: 0.5rem 1rem; color: var(--tab-text); font-size: 0.875rem; font-weight: 400; border-radius: 12px; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; border: 1px solid transparent; cursor: pointer; background: transparent; }
|
|
273
|
-
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color:
|
|
273
|
+
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color: var(--tab-active-border); transform: scale(1.05); }
|
|
274
274
|
.nav-tab.active { color: var(--tab-active-text); border-color: var(--tab-active-border); background-color: var(--tab-active-bg); transform: scale(1.05); }
|
|
275
275
|
.eagler-dropdown { position: relative; background-color: rgba(20, 20, 20, 0.98); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 14px; padding: 0.5rem; min-width: 200px; display: inline-block; }
|
|
276
276
|
.eagler-dropdown-link { display: block; padding: 0.6rem 0.8rem; color: #d1d5db; text-decoration: none; border-radius: 14px; font-size: 0.9rem; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
|
@@ -216,7 +216,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
216
216
|
.input-key-style:focus { border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5); transform: scale(1.1); }
|
|
217
217
|
.settings-box { border: 1px solid #333; border-radius: 24px; background-color: #000000; padding: 1.5rem; }
|
|
218
218
|
.nav-tab { padding: 0.5rem 1rem; color: var(--tab-text); font-size: 0.875rem; font-weight: 400; border-radius: 12px; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; border: 1px solid transparent; cursor: pointer; background: transparent; }
|
|
219
|
-
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color:
|
|
219
|
+
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color: var(--tab-active-border); transform: scale(1.05); }
|
|
220
220
|
.nav-tab.active { color: var(--tab-active-text); border-color: var(--tab-active-border); background-color: var(--tab-active-bg); transform: scale(1.05); }
|
|
221
221
|
.eagler-dropdown { position: relative; background-color: rgba(20, 20, 20, 0.98); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 14px; padding: 0.5rem; min-width: 200px; display: inline-block; }
|
|
222
222
|
.eagler-dropdown-link { display: block; padding: 0.6rem 0.8rem; color: #d1d5db; text-decoration: none; border-radius: 14px; font-size: 0.9rem; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
package/logged-in/weather.html
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
<script src="../injector.js"></script>
|
|
19
19
|
|
|
20
20
|
<style>
|
|
21
|
-
/* --- 4SP BASE STYLING
|
|
21
|
+
/* --- 4SP BASE STYLING --- */
|
|
22
22
|
:root {
|
|
23
23
|
--bg-page: #040404;
|
|
24
24
|
--bg-container: #000000;
|
|
@@ -46,55 +46,70 @@
|
|
|
46
46
|
font-weight: 400 !important;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
/* --- UI COMPONENTS
|
|
49
|
+
/* --- UI COMPONENTS --- */
|
|
50
50
|
.btn-toolbar-style {
|
|
51
51
|
background: var(--menu-bg, #000000);
|
|
52
52
|
border: 1px solid var(--menu-border, #333);
|
|
53
53
|
border-radius: 0.75rem;
|
|
54
54
|
color: #d1d5db;
|
|
55
|
-
padding: 0.
|
|
55
|
+
padding: 0.6rem 1.2rem;
|
|
56
56
|
font-weight: 500;
|
|
57
57
|
cursor: pointer;
|
|
58
58
|
transition: all 0.2s;
|
|
59
59
|
display: inline-flex;
|
|
60
60
|
align-items: center;
|
|
61
61
|
justify-content: center;
|
|
62
|
-
gap: 0.
|
|
62
|
+
gap: 0.75rem;
|
|
63
|
+
font-size: 0.95rem;
|
|
64
|
+
white-space: nowrap;
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
.btn-toolbar-style:hover {
|
|
66
68
|
background-color: #000000;
|
|
67
69
|
border-color: #fff;
|
|
68
70
|
color: #ffffff;
|
|
71
|
+
transform: translateY(-1px);
|
|
69
72
|
}
|
|
70
73
|
|
|
71
|
-
.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
.btn-toolbar-style.btn-primary-override:hover {
|
|
77
|
-
background-color: rgba(79, 70, 229, 0.15);
|
|
78
|
-
border-color: #6366f1;
|
|
79
|
-
color: #6366f1;
|
|
74
|
+
.provider-select-wrapper {
|
|
75
|
+
position: relative;
|
|
76
|
+
display: inline-block;
|
|
77
|
+
min-width: 180px; /* Minimum width */
|
|
80
78
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
border-radius: 0.75rem;
|
|
89
|
-
|
|
90
|
-
transition: all 0.2s;
|
|
79
|
+
|
|
80
|
+
.provider-select {
|
|
81
|
+
appearance: none;
|
|
82
|
+
background: #0d0d0d;
|
|
83
|
+
border: 1px solid #333;
|
|
84
|
+
color: #fff;
|
|
85
|
+
padding: 0.6rem 2.5rem 0.6rem 1rem;
|
|
86
|
+
border-radius: 0.75rem;
|
|
87
|
+
font-family: 'Geist', sans-serif;
|
|
91
88
|
font-size: 0.95rem;
|
|
92
|
-
|
|
89
|
+
cursor: pointer;
|
|
90
|
+
width: auto; /* Allow width to change based on content */
|
|
91
|
+
min-width: 100%;
|
|
92
|
+
transition: border-color 0.2s;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.provider-select:hover {
|
|
96
|
+
border-color: #6366f1;
|
|
93
97
|
}
|
|
94
|
-
|
|
95
|
-
|
|
98
|
+
|
|
99
|
+
.provider-select:focus {
|
|
96
100
|
outline: none;
|
|
97
|
-
|
|
101
|
+
border-color: #6366f1;
|
|
102
|
+
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.select-icon {
|
|
106
|
+
position: absolute;
|
|
107
|
+
right: 1rem;
|
|
108
|
+
top: 50%;
|
|
109
|
+
transform: translateY(-50%);
|
|
110
|
+
pointer-events: none;
|
|
111
|
+
color: #6b7280;
|
|
112
|
+
font-size: 0.75rem;
|
|
98
113
|
}
|
|
99
114
|
|
|
100
115
|
/* --- LAYOUT UTILS --- */
|
|
@@ -107,7 +122,7 @@
|
|
|
107
122
|
header {
|
|
108
123
|
display: flex;
|
|
109
124
|
flex-direction: column;
|
|
110
|
-
gap:
|
|
125
|
+
gap: 1.5rem;
|
|
111
126
|
padding: 1.5rem;
|
|
112
127
|
border-bottom: 1px solid #1a1a1a;
|
|
113
128
|
background-color: var(--bg-page);
|
|
@@ -120,61 +135,6 @@
|
|
|
120
135
|
}
|
|
121
136
|
}
|
|
122
137
|
|
|
123
|
-
/* --- SEARCH DROPDOWN --- */
|
|
124
|
-
.search-container {
|
|
125
|
-
position: relative;
|
|
126
|
-
width: 100%;
|
|
127
|
-
max-width: 350px;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.search-dropdown {
|
|
131
|
-
position: absolute;
|
|
132
|
-
top: calc(100% + 0.5rem);
|
|
133
|
-
left: 0;
|
|
134
|
-
right: 0;
|
|
135
|
-
background: #000000;
|
|
136
|
-
border: 1px solid #333;
|
|
137
|
-
border-radius: 1rem;
|
|
138
|
-
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
|
|
139
|
-
z-index: 100;
|
|
140
|
-
max-height: 300px;
|
|
141
|
-
overflow-y: auto;
|
|
142
|
-
display: none;
|
|
143
|
-
padding: 0.5rem;
|
|
144
|
-
}
|
|
145
|
-
.search-dropdown.active {
|
|
146
|
-
display: block;
|
|
147
|
-
animation: fadeIn 0.2s ease-out;
|
|
148
|
-
}
|
|
149
|
-
@keyframes fadeIn { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: translateY(0); } }
|
|
150
|
-
|
|
151
|
-
.search-item {
|
|
152
|
-
padding: 0.6rem 0.8rem;
|
|
153
|
-
cursor: pointer;
|
|
154
|
-
border-radius: 0.5rem;
|
|
155
|
-
display: flex;
|
|
156
|
-
flex-direction: column;
|
|
157
|
-
gap: 2px;
|
|
158
|
-
transition: background 0.2s;
|
|
159
|
-
border-bottom: 1px solid transparent;
|
|
160
|
-
}
|
|
161
|
-
.search-item:hover { background: #1a1a1a; color: #fff; }
|
|
162
|
-
.search-item-main { font-size: 0.95rem; color: #e5e7eb; }
|
|
163
|
-
.search-item-sub { color: #6b7280; font-size: 0.8rem; }
|
|
164
|
-
|
|
165
|
-
.geo-btn-absolute {
|
|
166
|
-
position: absolute;
|
|
167
|
-
right: 0.75rem;
|
|
168
|
-
top: 50%;
|
|
169
|
-
transform: translateY(-50%);
|
|
170
|
-
color: #6b7280;
|
|
171
|
-
cursor: pointer;
|
|
172
|
-
transition: color 0.2s;
|
|
173
|
-
background: none;
|
|
174
|
-
border: none;
|
|
175
|
-
}
|
|
176
|
-
.geo-btn-absolute:hover { color: #4f46e5; }
|
|
177
|
-
|
|
178
138
|
/* --- WEATHER CARDS --- */
|
|
179
139
|
.weather-card {
|
|
180
140
|
background-color: #0d0d0d;
|
|
@@ -200,11 +160,10 @@
|
|
|
200
160
|
color: var(--color-indigo);
|
|
201
161
|
}
|
|
202
162
|
|
|
203
|
-
/* Hourly Scroll
|
|
163
|
+
/* Hourly Scroll */
|
|
204
164
|
.scroll-mask-container {
|
|
205
165
|
position: relative;
|
|
206
166
|
width: 100%;
|
|
207
|
-
/* CSS Mask for fading edges */
|
|
208
167
|
-webkit-mask-image: linear-gradient(to right, transparent 0%, black 5%, black 95%, transparent 100%);
|
|
209
168
|
mask-image: linear-gradient(to right, transparent 0%, black 5%, black 95%, transparent 100%);
|
|
210
169
|
}
|
|
@@ -213,12 +172,12 @@
|
|
|
213
172
|
display: flex;
|
|
214
173
|
overflow-x: auto;
|
|
215
174
|
gap: 0.75rem;
|
|
216
|
-
padding: 1rem 1.5rem;
|
|
175
|
+
padding: 1rem 1.5rem;
|
|
217
176
|
margin-top: 0.5rem;
|
|
218
|
-
scrollbar-width: none;
|
|
219
|
-
-ms-overflow-style: none;
|
|
177
|
+
scrollbar-width: none;
|
|
178
|
+
-ms-overflow-style: none;
|
|
220
179
|
}
|
|
221
|
-
.hourly-container::-webkit-scrollbar { display: none; }
|
|
180
|
+
.hourly-container::-webkit-scrollbar { display: none; }
|
|
222
181
|
|
|
223
182
|
.hourly-item {
|
|
224
183
|
min-width: 80px;
|
|
@@ -309,55 +268,16 @@
|
|
|
309
268
|
.detail-label { color: #707070; font-size: 0.9rem; }
|
|
310
269
|
.detail-value { color: #fff; font-weight: 500; }
|
|
311
270
|
|
|
312
|
-
/*
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
:
|
|
321
|
-
|
|
322
|
-
.shake-anim { animation: shake 0.4s cubic-bezier(.36,.07,.19,.97) both; }
|
|
323
|
-
body.no-animations * { transition: none !important; animation: none !important; transform: none !important; }
|
|
324
|
-
body:not(.no-animations) .btn-toolbar-style, body:not(.no-animations) .btn-lock-screen, body:not(.no-animations) .icon-btn, body:not(.no-animations) .nav-tab, body:not(.no-animations) .btn-card-action, body:not(.no-animations) .input-text-style, body:not(.no-animations) .input-lock-screen, body:not(.no-animations) .input-key-style { transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) !important; }
|
|
325
|
-
body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .btn-lock-screen:active, body:not(.no-animations) .icon-btn:active, body:not(.no-animations) .nav-tab:active, body:not(.no-animations) .btn-card-action:active { transform: scale(0.96); transition: transform 0.05s ease-out !important; }
|
|
326
|
-
.btn-toolbar-style { background: #0a0a0a; border: 1px solid #333; border-radius: 14px; color: #d1d5db; padding: 0.75rem 1.25rem; font-weight: 500; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.6); }
|
|
327
|
-
.btn-toolbar-style:hover { transform: scale(1.05) translateY(-2px); box-shadow: 0 6px 20px rgba(255, 255, 255, 0.1); border-color: #fff; color: #ffffff; }
|
|
328
|
-
.btn-toolbar-style.btn-primary-override { background-color: rgba(79, 70, 229, 0.1); border: 1px solid #4f46e5; color: #4f46e5; }
|
|
329
|
-
.btn-toolbar-style.btn-primary-override:hover { background-color: rgba(79, 70, 229, 0.2); border-color: #6366f1; color: #6366f1; box-shadow: 0 6px 20px rgba(79, 70, 229, 0.4); }
|
|
330
|
-
.btn-toolbar-style.btn-primary-override-danger { background-color: rgba(220, 38, 38, 0.1); border: 1px solid #dc2626; color: #dc2626; }
|
|
331
|
-
.btn-toolbar-style.btn-primary-override-danger:hover { background-color: rgba(220, 38, 38, 0.2); border-color: #ef4444; color: #ef4444; box-shadow: 0 6px 20px rgba(220, 38, 38, 0.4); }
|
|
332
|
-
.btn-lock-screen { padding: 0.75rem 1.25rem; font-size: 0.875rem; font-weight: 500; border-radius: 14px; color: rgb(99 102 241); background-color: rgba(99, 102, 241, 0.1); border: 1px solid rgb(99 102 241); box-shadow: 0 4px 15px rgba(0, 0, 0, 0.6); }
|
|
333
|
-
.btn-lock-screen:hover { transform: scale(1.05) translateY(-2px); box-shadow: 0 6px 20px rgba(79, 70, 229, 0.4); background-color: rgba(99, 102, 241, 0.2); }
|
|
334
|
-
.icon-btn { width: 40px; height: 40px; border-radius: 14px; border: 1px solid #4b5563; display: flex; align-items: center; justify-content: center; color: #d1d5db; cursor: pointer; background: transparent; }
|
|
335
|
-
.icon-btn:hover { background-color: #374151; color: white; transform: scale(1.1); }
|
|
336
|
-
.btn-card-action { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; border-radius: 14px; background-color: transparent; border: 1px solid transparent; color: #9ca3af; cursor: pointer; }
|
|
337
|
-
.btn-card-action:hover { background-color: rgba(79, 70, 229, 0.1); color: #4f46e5; border-color: #4f46e5; transform: scale(1.15); }
|
|
338
|
-
.input-text-style, .input-select-style { width: 100%; padding: 0.75rem; border: 1px solid #252525; background-color: #111111; border-radius: 14px; color: #c0c0c0; }
|
|
339
|
-
.input-text-style:focus, .input-select-style:focus { border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5); transform: scale(1.02); }
|
|
340
|
-
.input-lock-screen { background-color: #111; border: 1px solid #252525; color: white; border-radius: 14px; padding: 0.75rem; text-align: center; letter-spacing: 0.2em; outline: none; }
|
|
341
|
-
.input-lock-screen:focus { border-color: rgb(99 102 241); transform: scale(1.02); }
|
|
342
|
-
.input-key-style { width: 4rem; padding: 0.75rem; border: 1px solid #252525; background-color: #111111; border-radius: 14px; color: #c0c0c0; font-size: 1.1rem; text-align: center; font-weight: 500; text-transform: uppercase; }
|
|
343
|
-
.input-key-style:focus { border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5); transform: scale(1.1); }
|
|
344
|
-
.settings-box { border: 1px solid #333; border-radius: 24px; background-color: #000000; padding: 1.5rem; }
|
|
345
|
-
.nav-tab { padding: 0.5rem 1rem; color: var(--tab-text); font-size: 0.875rem; font-weight: 400; border-radius: 12px; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; border: 1px solid transparent; cursor: pointer; background: transparent; }
|
|
346
|
-
.nav-tab:hover { color: var(--tab-hover-text); background-color: rgba(79, 70, 229, 0.05); border-color: #4f46e5; transform: scale(1.05); }
|
|
347
|
-
.nav-tab.active { color: var(--tab-active-text); border-color: var(--tab-active-border); background-color: var(--tab-active-bg); transform: scale(1.05); }
|
|
348
|
-
.eagler-dropdown { position: relative; background-color: rgba(20, 20, 20, 0.98); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 14px; padding: 0.5rem; min-width: 200px; display: inline-block; }
|
|
349
|
-
.eagler-dropdown-link { display: block; padding: 0.6rem 0.8rem; color: #d1d5db; text-decoration: none; border-radius: 14px; font-size: 0.9rem; transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
|
350
|
-
.eagler-dropdown-link:hover { background-color: rgba(255, 255, 255, 0.1); color: white; transform: translateX(4px); }
|
|
351
|
-
#notification-container { position: fixed; bottom: 2rem; right: 2rem; display: flex; flex-direction: column; gap: 0.75rem; z-index: 1000; pointer-events: none; }
|
|
352
|
-
.notification-toast { background-color: #0a0a0a; border: 1px solid #333; border-radius: 14px; padding: 0.75rem 1.25rem; color: #fff; box-shadow: 0 4px 15px rgba(0,0,0,0.5); display: flex; align-items: center; gap: 0.75rem; font-size: 0.9rem; min-width: 200px; transform: translateX(120%); transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity 0.3s ease, background-color 0.2s; opacity: 0; pointer-events: auto; cursor: default; }
|
|
353
|
-
.notification-toast.show { transform: translateX(0); opacity: 1; }
|
|
354
|
-
.notification-toast.show:hover { transform: scale(1.05) translateX(-5px); background-color: #151515; border-color: #555; box-shadow: 0 8px 25px rgba(0,0,0,0.7); }
|
|
355
|
-
.notification-icon { font-size: 1.1rem; }
|
|
356
|
-
.notification-icon.success { color: #4ade80; }
|
|
357
|
-
.notification-icon.info { color: #60a5fa; }
|
|
358
|
-
.notification-icon.warning { color: #fbbf24; }
|
|
359
|
-
|
|
360
|
-
</style>
|
|
271
|
+
/* Option Styling (Limited support) */
|
|
272
|
+
option { background-color: #000; color: #fff; padding: 10px; }
|
|
273
|
+
|
|
274
|
+
/* INJECTED STYLES (Animations) */
|
|
275
|
+
:root { --bg-page: #040404; --bg-container: #000000; --border-color: #333; --text-primary: #c0c0c0; --text-light-grey: #d1d5db; --accent-color: #6366f1; }
|
|
276
|
+
@keyframes shake { 0% { transform: translateX(0); } 25% { transform: translateX(-5px) rotate(-5deg); } 50% { transform: translateX(5px) rotate(5deg); } 75% { transform: translateX(-5px) rotate(-5deg); } 100% { transform: translateX(0); } }
|
|
277
|
+
.shake-anim { animation: shake 0.4s cubic-bezier(.36,.07,.19,.97) both; }
|
|
278
|
+
body:not(.no-animations) .btn-toolbar-style, body:not(.no-animations) .hourly-item, body:not(.no-animations) .daily-row { transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
|
279
|
+
body:not(.no-animations) .btn-toolbar-style:active { transform: scale(0.96); }
|
|
280
|
+
</style>
|
|
361
281
|
|
|
362
282
|
</head>
|
|
363
283
|
<body class="min-h-screen">
|
|
@@ -378,7 +298,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
378
298
|
</div>
|
|
379
299
|
<div id="modal-details-list" class="flex flex-col gap-3 pt-2">
|
|
380
300
|
</div>
|
|
381
|
-
<button class="btn-toolbar-style w-full mt-4" onclick="closeHourlyModal()">Close</button>
|
|
301
|
+
<button class="btn-toolbar-style w-full mt-4 justify-center" onclick="closeHourlyModal()">Close</button>
|
|
382
302
|
</div>
|
|
383
303
|
</div>
|
|
384
304
|
|
|
@@ -391,22 +311,17 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
391
311
|
</div>
|
|
392
312
|
|
|
393
313
|
<div class="flex flex-col md:flex-row items-center gap-4 w-full md:w-auto">
|
|
394
|
-
<
|
|
395
|
-
<
|
|
396
|
-
<
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
<
|
|
401
|
-
</
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
<div class="relative w-full md:w-auto">
|
|
405
|
-
<select id="provider-select" class="btn-toolbar-style w-full appearance-none pr-8 outline-none">
|
|
406
|
-
<option value="nws">🇺🇸 NWS (USA)</option>
|
|
407
|
-
<option value="open-meteo">🌍 Open-Meteo</option>
|
|
314
|
+
<button id="btn-geo" class="btn-toolbar-style w-full md:w-auto">
|
|
315
|
+
<i class="fa-solid fa-location-crosshairs text-[#6366f1]"></i>
|
|
316
|
+
<span>Use Current Location</span>
|
|
317
|
+
</button>
|
|
318
|
+
|
|
319
|
+
<div class="provider-select-wrapper w-full md:w-auto">
|
|
320
|
+
<select id="provider-select" class="provider-select">
|
|
321
|
+
<option value="nws">🇺🇸 NWS (Official)</option>
|
|
322
|
+
<option value="open-meteo">🌍 Open-Meteo (Global)</option>
|
|
408
323
|
</select>
|
|
409
|
-
<i class="fa-solid fa-chevron-down
|
|
324
|
+
<i class="fa-solid fa-chevron-down select-icon"></i>
|
|
410
325
|
</div>
|
|
411
326
|
</div>
|
|
412
327
|
</header>
|
|
@@ -479,10 +394,6 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
479
394
|
const mainContent = document.getElementById('main-content');
|
|
480
395
|
const locNameEl = document.getElementById('loc-name');
|
|
481
396
|
const providerSelect = document.getElementById('provider-select');
|
|
482
|
-
|
|
483
|
-
// Search Elements
|
|
484
|
-
const searchInput = document.getElementById('loc-search-input');
|
|
485
|
-
const searchResults = document.getElementById('search-results');
|
|
486
397
|
const btnGeo = document.getElementById('btn-geo');
|
|
487
398
|
|
|
488
399
|
// Current Els
|
|
@@ -570,7 +481,7 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
570
481
|
loadWeather();
|
|
571
482
|
} catch (err) {
|
|
572
483
|
loadingText.innerText = "Location Failed.";
|
|
573
|
-
alert("Could not determine location.
|
|
484
|
+
alert("Could not determine location. Check browser permissions.");
|
|
574
485
|
loadingOverlay.style.opacity = '0';
|
|
575
486
|
loadingOverlay.style.pointerEvents = 'none';
|
|
576
487
|
}
|
|
@@ -607,131 +518,10 @@ body:not(.no-animations) .btn-toolbar-style:active, body:not(.no-animations) .bt
|
|
|
607
518
|
}
|
|
608
519
|
}
|
|
609
520
|
|
|
610
|
-
// --- SEARCH LOGIC ---
|
|
611
|
-
let debounceTimer;
|
|
612
|
-
searchInput.addEventListener('input', (e) => {
|
|
613
|
-
clearTimeout(debounceTimer);
|
|
614
|
-
const query = e.target.value.trim();
|
|
615
|
-
if(query.length < 3) {
|
|
616
|
-
searchResults.classList.remove('active');
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
// Show loading state in dropdown
|
|
620
|
-
searchResults.innerHTML = '<div class="search-item text-gray-500"><i class="fa-solid fa-spinner fa-spin mr-2"></i> Searching...</div>';
|
|
621
|
-
searchResults.classList.add('active');
|
|
622
|
-
|
|
623
|
-
debounceTimer = setTimeout(() => fetchSearchResults(query), 500);
|
|
624
|
-
});
|
|
625
|
-
|
|
626
|
-
document.addEventListener('click', (e) => {
|
|
627
|
-
if(!searchInput.contains(e.target) && !searchResults.contains(e.target)) {
|
|
628
|
-
searchResults.classList.remove('active');
|
|
629
|
-
}
|
|
630
|
-
});
|
|
631
|
-
|
|
632
521
|
btnGeo.addEventListener('click', () => {
|
|
633
|
-
searchInput.value = '';
|
|
634
522
|
triggerAutoLocation();
|
|
635
523
|
});
|
|
636
524
|
|
|
637
|
-
async function fetchSearchResults(query) {
|
|
638
|
-
let viewbox = '';
|
|
639
|
-
if (STATE.lat && STATE.lon) {
|
|
640
|
-
const b = 1;
|
|
641
|
-
viewbox = `&viewbox=${STATE.lon-b},${STATE.lat+b},${STATE.lon+b},${STATE.lat-b}`;
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
try {
|
|
645
|
-
const url = `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(query)}&limit=10&addressdetails=1${viewbox}`;
|
|
646
|
-
const res = await fetch(url);
|
|
647
|
-
const data = await res.json();
|
|
648
|
-
|
|
649
|
-
const filtered = data.filter(item => {
|
|
650
|
-
const type = item.type;
|
|
651
|
-
const category = item.class;
|
|
652
|
-
const validClasses = ['place', 'boundary'];
|
|
653
|
-
const validTypes = ['city', 'town', 'village', 'hamlet', 'administrative'];
|
|
654
|
-
|
|
655
|
-
if (!validClasses.includes(category)) return false;
|
|
656
|
-
if (category === 'boundary' && type !== 'administrative') return false;
|
|
657
|
-
return true;
|
|
658
|
-
});
|
|
659
|
-
|
|
660
|
-
renderSearchResults(filtered.slice(0, 5));
|
|
661
|
-
} catch (e) {
|
|
662
|
-
console.error("Search failed", e);
|
|
663
|
-
searchResults.innerHTML = '<div class="search-item text-red-500">Error searching.</div>';
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
function renderSearchResults(results) {
|
|
668
|
-
searchResults.innerHTML = '';
|
|
669
|
-
|
|
670
|
-
if (results.length === 0) {
|
|
671
|
-
const empty = document.createElement('div');
|
|
672
|
-
empty.className = 'search-item text-gray-500 cursor-default';
|
|
673
|
-
empty.innerText = 'No places found';
|
|
674
|
-
searchResults.appendChild(empty);
|
|
675
|
-
} else {
|
|
676
|
-
results.forEach(loc => {
|
|
677
|
-
const div = document.createElement('div');
|
|
678
|
-
div.className = 'search-item';
|
|
679
|
-
|
|
680
|
-
const address = loc.address || {};
|
|
681
|
-
const city = address.city || address.town || address.village || address.hamlet || loc.name;
|
|
682
|
-
const state = address.state || address.country;
|
|
683
|
-
|
|
684
|
-
div.innerHTML = `
|
|
685
|
-
<div class="search-item-main">${city}</div>
|
|
686
|
-
<div class="search-item-sub">${state}</div>
|
|
687
|
-
`;
|
|
688
|
-
|
|
689
|
-
div.addEventListener('click', () => {
|
|
690
|
-
selectLocation(parseFloat(loc.lat), parseFloat(loc.lon), city, state, address.country_code);
|
|
691
|
-
});
|
|
692
|
-
|
|
693
|
-
searchResults.appendChild(div);
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
// Add "Use Current Location" at the bottom
|
|
698
|
-
const currDiv = document.createElement('div');
|
|
699
|
-
currDiv.className = 'search-item border-t border-[#333] mt-1 pt-2';
|
|
700
|
-
if (STATE.locationAllowed) {
|
|
701
|
-
currDiv.innerHTML = `<div class="search-item-main text-[#6366f1]"><i class="fa-solid fa-location-crosshairs mr-2"></i> Use Current Location</div>`;
|
|
702
|
-
currDiv.addEventListener('click', () => {
|
|
703
|
-
searchInput.value = '';
|
|
704
|
-
searchResults.classList.remove('active');
|
|
705
|
-
triggerAutoLocation();
|
|
706
|
-
});
|
|
707
|
-
} else {
|
|
708
|
-
currDiv.innerHTML = `<div class="search-item-main text-gray-500 cursor-not-allowed"><i class="fa-solid fa-location-slash mr-2"></i> Current Location Unavailable</div>`;
|
|
709
|
-
}
|
|
710
|
-
searchResults.appendChild(currDiv);
|
|
711
|
-
|
|
712
|
-
searchResults.classList.add('active');
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
function selectLocation(lat, lon, city, region, countryCode) {
|
|
716
|
-
STATE.lat = lat;
|
|
717
|
-
STATE.lon = lon;
|
|
718
|
-
STATE.city = city;
|
|
719
|
-
STATE.region = region;
|
|
720
|
-
|
|
721
|
-
searchInput.value = '';
|
|
722
|
-
searchResults.classList.remove('active');
|
|
723
|
-
|
|
724
|
-
const isUS = (countryCode && countryCode === 'us');
|
|
725
|
-
|
|
726
|
-
if (!isUS) {
|
|
727
|
-
STATE.provider = 'open-meteo';
|
|
728
|
-
providerSelect.value = 'open-meteo';
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
updateLocationDisplay();
|
|
732
|
-
loadWeather();
|
|
733
|
-
}
|
|
734
|
-
|
|
735
525
|
// --- WEATHER FETCHING LOGIC ---
|
|
736
526
|
|
|
737
527
|
async function loadWeather() {
|
package/navigation.js
CHANGED
|
@@ -1138,7 +1138,7 @@ let db;
|
|
|
1138
1138
|
text-decoration: none; line-height: 1.5; display: flex; align-items: center; margin-right: 8px;
|
|
1139
1139
|
border: 1px solid transparent;
|
|
1140
1140
|
}
|
|
1141
|
-
.nav-tab:not(.active):hover { color: var(--tab-hover-text); border-color: var(--tab-
|
|
1141
|
+
.nav-tab:not(.active):hover { color: var(--tab-hover-text); border-color: var(--tab-active-border); background-color: var(--tab-hover-bg); }
|
|
1142
1142
|
.nav-tab.active { color: var(--tab-active-text); border-color: var(--tab-active-border); background-color: var(--tab-active-bg); }
|
|
1143
1143
|
.nav-tab.active:hover { color: var(--tab-active-hover-text); border-color: var(--tab-active-hover-border); background-color: var(--tab-active-hover-bg); }
|
|
1144
1144
|
|
package/package.json
CHANGED
package/test.html
CHANGED
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
.nav-tab:hover {
|
|
54
54
|
color: var(--tab-hover-text, #ffffff);
|
|
55
55
|
background-color: var(--tab-hover-bg, rgba(79, 70, 229, 0.05));
|
|
56
|
-
border-color: var(--tab-
|
|
56
|
+
border-color: var(--tab-active-border, #4f46e5);
|
|
57
57
|
}
|
|
58
58
|
.nav-tab.active {
|
|
59
59
|
color: var(--tab-active-text, #4f46e5);
|