4sp-dv 1.0.30 → 1.0.32
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 +2 -2
- package/logged-in/games.html +128 -49
- package/package.json +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.31/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
|
|
|
@@ -778,7 +778,7 @@
|
|
|
778
778
|
const displayUsername = document.getElementById('display-username');
|
|
779
779
|
const displayEmail = document.getElementById('display-email');
|
|
780
780
|
|
|
781
|
-
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.31/logged-in/';
|
|
782
782
|
|
|
783
783
|
// Preload Logos
|
|
784
784
|
const preloadImgs = [
|
package/logged-in/games.html
CHANGED
|
@@ -83,9 +83,9 @@
|
|
|
83
83
|
.btn-toolbar-style {
|
|
84
84
|
background: var(--menu-bg);
|
|
85
85
|
border: 1px solid var(--menu-border);
|
|
86
|
-
border-radius:
|
|
86
|
+
border-radius: 14px; /* MATCHES auth-btn */
|
|
87
87
|
color: var(--menu-text);
|
|
88
|
-
padding: 0.5rem
|
|
88
|
+
padding: 0.5rem 1.25rem;
|
|
89
89
|
font-weight: 500;
|
|
90
90
|
cursor: pointer;
|
|
91
91
|
transition: all 0.2s;
|
|
@@ -100,6 +100,7 @@
|
|
|
100
100
|
background-color: var(--menu-bg);
|
|
101
101
|
border-color: #fff;
|
|
102
102
|
color: var(--tab-hover-text);
|
|
103
|
+
transform: translateY(-1px);
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
/* --- Card Action Buttons --- */
|
|
@@ -109,7 +110,7 @@
|
|
|
109
110
|
justify-content: center;
|
|
110
111
|
width: 2.25rem;
|
|
111
112
|
height: 2.25rem;
|
|
112
|
-
border-radius:
|
|
113
|
+
border-radius: 14px; /* MATCHES auth-btn */
|
|
113
114
|
background-color: transparent;
|
|
114
115
|
border: 1px solid transparent;
|
|
115
116
|
color: #9ca3af;
|
|
@@ -121,6 +122,7 @@
|
|
|
121
122
|
background-color: var(--tab-active-bg);
|
|
122
123
|
color: var(--tab-active-text);
|
|
123
124
|
border-color: var(--tab-active-border);
|
|
125
|
+
transform: scale(1.1);
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
/* Favorite Button Logic */
|
|
@@ -161,31 +163,62 @@
|
|
|
161
163
|
}
|
|
162
164
|
|
|
163
165
|
/* --- Animations --- */
|
|
166
|
+
@keyframes fadeIn {
|
|
167
|
+
from { opacity: 0; transform: scale(0.98); }
|
|
168
|
+
to { opacity: 1; transform: scale(1); }
|
|
169
|
+
}
|
|
164
170
|
@keyframes fadeOut {
|
|
165
171
|
from { opacity: 1; transform: scale(1); }
|
|
166
|
-
to { opacity: 0; transform: scale(0.
|
|
172
|
+
to { opacity: 0; transform: scale(0.98); }
|
|
167
173
|
}
|
|
168
|
-
.fade-out
|
|
174
|
+
.animate-fade-in { animation: fadeIn 0.3s ease-out forwards; }
|
|
175
|
+
.animate-fade-out { animation: fadeOut 0.3s ease-out forwards; }
|
|
176
|
+
|
|
177
|
+
.fade-out-card {
|
|
169
178
|
animation: fadeOut 0.3s ease-out forwards;
|
|
170
179
|
pointer-events: none;
|
|
171
180
|
}
|
|
172
181
|
|
|
173
182
|
/* Search Bar & Results */
|
|
183
|
+
#bottom-fixed-bar {
|
|
184
|
+
transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity 0.3s ease;
|
|
185
|
+
}
|
|
186
|
+
#bottom-fixed-bar:focus-within {
|
|
187
|
+
transform: translateY(-5px);
|
|
188
|
+
border-color: #4f46e5;
|
|
189
|
+
box-shadow: 0 10px 30px rgba(0,0,0,0.8), 0 0 0 2px rgba(79, 70, 229, 0.2);
|
|
190
|
+
}
|
|
191
|
+
|
|
174
192
|
.search-results-container {
|
|
175
193
|
max-height: 300px;
|
|
176
194
|
overflow-y: auto;
|
|
177
195
|
scrollbar-width: thin;
|
|
178
196
|
scrollbar-color: #333 transparent;
|
|
197
|
+
transition: opacity 0.3s ease;
|
|
179
198
|
}
|
|
180
199
|
.search-item {
|
|
181
200
|
display: flex;
|
|
182
201
|
cursor: pointer;
|
|
183
|
-
transition:
|
|
202
|
+
transition: all 0.2s;
|
|
184
203
|
color: #e5e7eb;
|
|
185
204
|
text-decoration: none;
|
|
186
205
|
padding: 10px 15px;
|
|
187
206
|
}
|
|
188
|
-
.search-item:hover {
|
|
207
|
+
.search-item:hover {
|
|
208
|
+
background-color: rgba(255, 255, 255, 0.05);
|
|
209
|
+
padding-left: 20px;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.category-badge {
|
|
213
|
+
font-size: 0.6rem;
|
|
214
|
+
padding: 1px 6px;
|
|
215
|
+
border-radius: 6px;
|
|
216
|
+
font-weight: 400;
|
|
217
|
+
margin-top: 4px;
|
|
218
|
+
border: 1px solid currentColor;
|
|
219
|
+
background: transparent !important;
|
|
220
|
+
display: inline-block;
|
|
221
|
+
}
|
|
189
222
|
|
|
190
223
|
@media (max-width: 768px) {
|
|
191
224
|
#bottom-fixed-bar {
|
|
@@ -200,45 +233,56 @@
|
|
|
200
233
|
.aspect-w-3 > * { position: absolute; height: 100%; width: 100%; top: 0; right: 0; bottom: 0; left: 0; }
|
|
201
234
|
|
|
202
235
|
/* --- Game Viewer Modal --- */
|
|
203
|
-
#zoneViewer {
|
|
236
|
+
#zoneViewer {
|
|
237
|
+
display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%;
|
|
238
|
+
background-color: #000; z-index: 5000; flex-direction: column;
|
|
239
|
+
opacity: 0;
|
|
240
|
+
}
|
|
241
|
+
#zoneViewer.active { display: flex; opacity: 1; }
|
|
242
|
+
|
|
204
243
|
#zoneViewer .zone-header {
|
|
205
|
-
background-color: #
|
|
206
|
-
padding: 12px
|
|
244
|
+
background-color: #0a0a0a;
|
|
245
|
+
padding: 12px 24px;
|
|
207
246
|
display: flex;
|
|
208
247
|
justify-content: space-between;
|
|
209
248
|
align-items: center;
|
|
210
|
-
border-bottom: 1px solid #
|
|
211
|
-
box-shadow: 0 2px
|
|
249
|
+
border-bottom: 1px solid #1a1a1a;
|
|
250
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.5);
|
|
212
251
|
flex-shrink: 0;
|
|
213
252
|
}
|
|
214
253
|
#zoneViewer .zone-header .zone-title h2 {
|
|
215
254
|
margin: 0;
|
|
216
|
-
font-size: 1.
|
|
255
|
+
font-size: 1.2rem;
|
|
217
256
|
color: #ffffff;
|
|
218
257
|
font-family: 'Geist', sans-serif;
|
|
258
|
+
font-weight: 500;
|
|
219
259
|
}
|
|
220
|
-
#zoneViewer .zone-header .zone-controls { display: flex; align-items: center; }
|
|
260
|
+
#zoneViewer .zone-header .zone-controls { display: flex; align-items: center; gap: 8px; }
|
|
261
|
+
|
|
221
262
|
#zoneViewer .zone-header .zone-controls button,
|
|
222
263
|
#zoneViewer .zone-header .zone-controls a {
|
|
223
|
-
margin
|
|
264
|
+
margin: 0;
|
|
224
265
|
width: 40px;
|
|
225
266
|
height: 40px;
|
|
226
|
-
background-color:
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
231
|
-
border-radius: 0.5rem;
|
|
267
|
+
background-color: #1a1a1a;
|
|
268
|
+
color: #d1d5db;
|
|
269
|
+
border: 1px solid #333;
|
|
270
|
+
border-radius: 14px; /* MATCHES auth-btn */
|
|
232
271
|
cursor: pointer;
|
|
233
|
-
font-size:
|
|
272
|
+
font-size: 1rem;
|
|
234
273
|
display: flex;
|
|
235
274
|
align-items: center;
|
|
236
275
|
justify-content: center;
|
|
237
|
-
transition:
|
|
276
|
+
transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
238
277
|
text-decoration: none;
|
|
239
278
|
}
|
|
240
279
|
#zoneViewer .zone-header .zone-controls button:hover,
|
|
241
|
-
#zoneViewer .zone-header .zone-controls a:hover {
|
|
280
|
+
#zoneViewer .zone-header .zone-controls a:hover {
|
|
281
|
+
background-color: rgba(79, 70, 229, 0.1);
|
|
282
|
+
border-color: #4f46e5;
|
|
283
|
+
color: #4f46e5;
|
|
284
|
+
transform: scale(1.1);
|
|
285
|
+
}
|
|
242
286
|
#zoneViewer iframe { flex-grow: 1; border: none; background-color: #000; }
|
|
243
287
|
.hidden { display: none !important; }
|
|
244
288
|
|
|
@@ -710,7 +754,7 @@
|
|
|
710
754
|
<div class="absolute inset-0 p-4 sm:p-6 flex flex-col justify-between rounded-2xl">
|
|
711
755
|
<div class="flex items-start justify-between w-full">
|
|
712
756
|
<h3 class="text-4xl font-bold text-white truncate drop-shadow-lg" style="max-width: 80%;" title="${game.name}">${game.name}</h3>
|
|
713
|
-
<div class="flex items-center
|
|
757
|
+
<div class="flex items-center gap-2 bg-black/80 backdrop-blur-md rounded-2xl p-2">
|
|
714
758
|
${gameButtonsHtml}
|
|
715
759
|
${favoriteButtonHtml}
|
|
716
760
|
</div>
|
|
@@ -765,7 +809,7 @@
|
|
|
765
809
|
<div class="relative w-full cursor-pointer group">
|
|
766
810
|
<div class="aspect-w-3 aspect-h-2"><img data-src="${imgSrc}" alt="${game.name}" class="w-full h-full object-cover"></div>
|
|
767
811
|
<h3 class="absolute top-2 right-2 z-10 max-w-[80%] bg-black/60 backdrop-blur-md rounded-xl px-3 py-1.5 text-white truncate text-sm font-semibold shadow-lg" title="${game.name}">${game.name}</h3>
|
|
768
|
-
<div class="absolute bottom-2 right-2 bg-black/80 backdrop-blur-md rounded-
|
|
812
|
+
<div class="absolute bottom-2 right-2 bg-black/80 backdrop-blur-md rounded-2xl p-2 flex items-center gap-2 shadow-lg">
|
|
769
813
|
<button class="btn-card-action play-action" title="Play Game"><i class="fa-solid fa-play transition-colors"></i></button>
|
|
770
814
|
<button class="btn-card-action fav-action ${isFavorite ? 'favorited' : ''}" title="${isFavorite ? 'Remove from Favorites' : 'Add to Favorites'}"><i class="fa-solid fa-star fa-solid-star transition-colors"></i><i class="fa-regular fa-star fa-regular-star transition-colors"></i></button>
|
|
771
815
|
</div>
|
|
@@ -805,7 +849,8 @@
|
|
|
805
849
|
const zoneFrame = document.getElementById('zoneFrame');
|
|
806
850
|
const zoneNameEl = document.getElementById('zoneNameEl');
|
|
807
851
|
const downloadBtn = document.getElementById('downloadBtnZone');
|
|
808
|
-
|
|
852
|
+
const controls = zoneViewer.querySelector('.zone-controls');
|
|
853
|
+
|
|
809
854
|
// Setup Download Button (Specific to Eaglercraft)
|
|
810
855
|
if (game.baseGameId === 'other-eaglercraft' || game.id === 'other-eaglercraft') {
|
|
811
856
|
downloadBtn.href = game.url;
|
|
@@ -818,6 +863,26 @@
|
|
|
818
863
|
downloadBtn.removeAttribute('download');
|
|
819
864
|
}
|
|
820
865
|
|
|
866
|
+
// --- INJECT FAVORITE BUTTON IN PLAYER HEADER ---
|
|
867
|
+
// Remove existing if any
|
|
868
|
+
const existingFav = controls.querySelector('.player-fav-btn');
|
|
869
|
+
if (existingFav) existingFav.remove();
|
|
870
|
+
|
|
871
|
+
const favBtn = document.createElement('button');
|
|
872
|
+
favBtn.className = 'player-fav-btn btn-card-action fav-action';
|
|
873
|
+
favBtn.innerHTML = '<i class="fa-solid fa-star fa-solid-star"></i><i class="fa-regular fa-star fa-regular-star"></i>';
|
|
874
|
+
const isFavorited = getFavorites().map(String).includes(String(game.id));
|
|
875
|
+
if (isFavorited) favBtn.classList.add('favorited');
|
|
876
|
+
|
|
877
|
+
favBtn.onclick = (e) => {
|
|
878
|
+
e.stopPropagation();
|
|
879
|
+
toggleFavorite(game.id);
|
|
880
|
+
favBtn.classList.toggle('favorited');
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
// Prepend to controls (Left side)
|
|
884
|
+
controls.prepend(favBtn);
|
|
885
|
+
|
|
821
886
|
zoneNameEl.textContent = game.name;
|
|
822
887
|
|
|
823
888
|
// RESET FRAME BEFORE LOAD
|
|
@@ -829,16 +894,16 @@
|
|
|
829
894
|
zoneFrame.setAttribute('allow', 'fullscreen; pointer-lock; autoplay; clipboard-write');
|
|
830
895
|
|
|
831
896
|
// --- REVISED LOGIC FOR LOADING GAMES ---
|
|
832
|
-
// With raw.githack.com, we can treat GN-Math games as standard URL games again
|
|
833
|
-
// because Githack serves correct Content-Type: text/html headers.
|
|
834
897
|
const isStandardURLGame = game.category === 'StrongdogXP' || game.category === 'Others' || game.category === 'GN-Math';
|
|
835
898
|
|
|
836
899
|
if (isStandardURLGame) {
|
|
837
|
-
// Load URL directly for standard games
|
|
838
900
|
zoneFrame.src = game.url;
|
|
901
|
+
|
|
902
|
+
// SHOW WITH ANIMATION
|
|
839
903
|
zoneViewer.style.display = "flex";
|
|
904
|
+
zoneViewer.classList.remove('animate-fade-out');
|
|
905
|
+
zoneViewer.classList.add('active', 'animate-fade-in');
|
|
840
906
|
} else {
|
|
841
|
-
// Fallback for other potential categories (same logic as before: fetch & write)
|
|
842
907
|
fetch(`${game.url}?t=${Date.now()}`)
|
|
843
908
|
.then(response => {
|
|
844
909
|
if (!response.ok) throw new Error(`HTTP error ${response.status}`);
|
|
@@ -849,29 +914,43 @@
|
|
|
849
914
|
doc.open();
|
|
850
915
|
doc.write(html);
|
|
851
916
|
doc.close();
|
|
917
|
+
|
|
918
|
+
// SHOW WITH ANIMATION
|
|
852
919
|
zoneViewer.style.display = "flex";
|
|
920
|
+
zoneViewer.classList.remove('animate-fade-out');
|
|
921
|
+
zoneViewer.classList.add('active', 'animate-fade-in');
|
|
853
922
|
})
|
|
854
923
|
.catch(error => {
|
|
855
924
|
console.error(`Failed to load game "${game.name}": ${error.message}`);
|
|
856
925
|
zoneFrame.src = game.url;
|
|
926
|
+
|
|
857
927
|
zoneViewer.style.display = "flex";
|
|
928
|
+
zoneViewer.classList.remove('animate-fade-out');
|
|
929
|
+
zoneViewer.classList.add('active', 'animate-fade-in');
|
|
858
930
|
});
|
|
859
931
|
}
|
|
860
932
|
}
|
|
861
933
|
|
|
862
934
|
function closeZoneViewer() {
|
|
863
|
-
updateURL(categories[currentCategoryIndex]);
|
|
864
|
-
const downloadBtn = document.getElementById('downloadBtnZone');
|
|
865
|
-
downloadBtn.classList.add('hidden');
|
|
866
|
-
downloadBtn.href = '#';
|
|
867
|
-
downloadBtn.removeAttribute('download');
|
|
868
|
-
downloadBtn.removeAttribute('target');
|
|
869
935
|
const zoneViewer = document.getElementById('zoneViewer');
|
|
870
936
|
const zoneFrame = document.getElementById('zoneFrame');
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
937
|
+
|
|
938
|
+
zoneViewer.classList.remove('animate-fade-in');
|
|
939
|
+
zoneViewer.classList.add('animate-fade-out');
|
|
940
|
+
|
|
941
|
+
setTimeout(() => {
|
|
942
|
+
zoneViewer.style.display = "none";
|
|
943
|
+
zoneViewer.classList.remove('active', 'animate-fade-out');
|
|
944
|
+
if (zoneFrame) {
|
|
945
|
+
zoneFrame.src = 'about:blank';
|
|
946
|
+
}
|
|
947
|
+
updateURL(categories[currentCategoryIndex]);
|
|
948
|
+
const downloadBtn = document.getElementById('downloadBtnZone');
|
|
949
|
+
downloadBtn.classList.add('hidden');
|
|
950
|
+
downloadBtn.href = '#';
|
|
951
|
+
downloadBtn.removeAttribute('download');
|
|
952
|
+
downloadBtn.removeAttribute('target');
|
|
953
|
+
}, 300);
|
|
875
954
|
}
|
|
876
955
|
|
|
877
956
|
// --- Render Lists ---
|
|
@@ -893,16 +972,10 @@
|
|
|
893
972
|
else if (game.versions) {
|
|
894
973
|
game.versions.forEach(v => {
|
|
895
974
|
if (favoriteIds.includes(String(v.favoriteId))) {
|
|
896
|
-
// Need to resolve URL here for favorites too!
|
|
897
975
|
let vUrl = v.url;
|
|
898
976
|
if (game.category === 'Others' || game.category === 'Gameboy Games') {
|
|
899
977
|
vUrl = resolveGameUrl(v.url);
|
|
900
|
-
} else if (game.category === 'StrongdogXP') {
|
|
901
|
-
// Strongdog favorites usually just rely on the ID to regenerate logic, but for safety in this object:
|
|
902
|
-
// Logic remains handled inside createGameCard via ID lookup generally, but let's leave as is
|
|
903
|
-
// because strongdog logic inside createGameCard regenerates paths based on ID/Page props anyway.
|
|
904
978
|
}
|
|
905
|
-
|
|
906
979
|
favoriteGames.push({ ...game, id: v.favoriteId, name: `${game.name} - ${v.name}`, url: vUrl, versions: undefined });
|
|
907
980
|
}
|
|
908
981
|
});
|
|
@@ -980,13 +1053,19 @@
|
|
|
980
1053
|
linkEl.dataset.gameId = game.id;
|
|
981
1054
|
let isFavorite = favorites.includes(String(game.id));
|
|
982
1055
|
|
|
1056
|
+
const catLabel = game.category === 'StrongdogXP' ? 'StrongdogXP' : (game.category === 'GN-Math' ? 'GN-Math' : 'Others');
|
|
1057
|
+
const catColor = game.category === 'StrongdogXP' ? 'text-strongdog-orange' : (game.category === 'GN-Math' ? 'text-gn-math' : 'text-gray-400');
|
|
1058
|
+
|
|
983
1059
|
linkEl.innerHTML = `
|
|
984
1060
|
<div class="flex items-center truncate min-w-0">
|
|
985
1061
|
<img src="${imgSrc}" alt="${game.name}" class="w-10 h-10 rounded-lg object-cover flex-shrink-0">
|
|
986
|
-
<
|
|
1062
|
+
<div class="flex flex-col ml-3 truncate min-w-0">
|
|
1063
|
+
<span class="font-medium truncate text-gray-200" title="${game.name}">${game.name}</span>
|
|
1064
|
+
<span class="category-badge w-fit ${catColor}">${catLabel}</span>
|
|
1065
|
+
</div>
|
|
987
1066
|
</div>
|
|
988
1067
|
<div class="flex items-center flex-shrink-0">
|
|
989
|
-
<div class="bg-black/80 backdrop-blur-md rounded-
|
|
1068
|
+
<div class="bg-black/80 backdrop-blur-md rounded-2xl p-2 flex items-center gap-2">
|
|
990
1069
|
<button class="btn-card-action play-action" title="Play Game">
|
|
991
1070
|
<i class="fa-solid fa-play transition-colors"></i>
|
|
992
1071
|
</button>
|