Reaperxxxx commited on
Commit
4c240fb
·
verified ·
1 Parent(s): df89156

Update docs.html

Browse files
Files changed (1) hide show
  1. docs.html +584 -105
docs.html CHANGED
@@ -1336,7 +1336,7 @@
1336
  --theme-text-primary: #f0f0f0;
1337
  }
1338
 
1339
- /* Green Theme */
1340
  .theme-green {
1341
  --theme-primary: #4caf50;
1342
  --theme-secondary: #81c784;
@@ -1346,116 +1346,122 @@
1346
  --theme-text-primary: #e8f5e8;
1347
  }
1348
 
1349
- /* Enhanced theme coverage - make themes affect ALL elements */
1350
- .search-container {
1351
- background: linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-tertiary) 100%);
1352
- border: 2px solid var(--theme-primary);
1353
- }
1354
-
1355
- .search-input {
1356
- background: var(--theme-bg-tertiary);
1357
- border: 1px solid var(--theme-primary);
1358
  color: var(--theme-text-primary);
1359
  }
1360
 
1361
- .search-input:focus {
1362
- border-color: var(--theme-primary);
1363
- box-shadow: 0 0 10px rgba(var(--theme-primary-rgb, 0, 188, 212), 0.3);
 
1364
  }
1365
 
1366
- .search-btn {
 
1367
  background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-secondary) 100%);
1368
- border: none;
1369
  color: var(--theme-bg-primary);
1370
  }
1371
 
1372
- .search-btn:hover {
1373
- background: linear-gradient(135deg, var(--theme-secondary) 0%, var(--theme-primary) 100%);
 
1374
  }
1375
 
1376
- .theme-selector {
1377
  background: var(--theme-bg-secondary);
1378
- border: 1px solid var(--theme-primary);
1379
- }
1380
-
1381
- .theme-btn {
1382
  border: 2px solid var(--theme-primary);
1383
  color: var(--theme-text-primary);
1384
- background: var(--theme-bg-tertiary);
1385
  }
1386
 
1387
- .theme-btn:hover, .theme-btn.current {
1388
- background: var(--theme-primary);
1389
- color: var(--theme-bg-primary);
1390
  }
1391
 
1392
- .profile-container {
 
1393
  background: linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-tertiary) 100%);
1394
- border: 2px solid var(--theme-primary);
1395
- }
1396
-
1397
- .stats-section {
1398
- background: var(--theme-bg-secondary);
1399
  border: 1px solid var(--theme-primary);
 
1400
  }
1401
 
1402
- .stats-section h3 {
1403
- color: var(--theme-primary);
1404
- border-bottom: 2px solid var(--theme-primary);
1405
- }
1406
-
1407
- .stat-item {
1408
  background: var(--theme-bg-tertiary);
1409
  border: 1px solid var(--theme-primary);
1410
  }
1411
 
1412
- .stat-label {
1413
- color: var(--theme-text-secondary);
1414
  }
1415
 
1416
- .stat-value {
1417
  color: var(--theme-primary);
1418
  }
1419
 
1420
- .nft-card, .group-card {
1421
- background: var(--theme-bg-tertiary);
 
 
 
 
 
1422
  border: 2px solid var(--theme-primary);
 
 
 
 
 
 
1423
  }
1424
 
1425
- .nft-card:hover, .group-card:hover {
1426
- border-color: var(--theme-secondary);
1427
- box-shadow: 0 8px 25px rgba(var(--theme-primary-rgb, 0, 188, 212), 0.3);
 
 
1428
  }
1429
 
1430
- .show-all-btn, .view-profile-btn {
1431
- background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-secondary) 100%);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1432
  border: none;
1433
- color: var(--theme-bg-primary);
 
 
 
1434
  }
1435
 
1436
- .show-all-btn:hover, .view-profile-btn:hover {
1437
- background: linear-gradient(135deg, var(--theme-secondary) 0%, var(--theme-primary) 100%);
1438
  }
1439
 
1440
- /* Make collapsed widget much smaller */
1441
- .floating-user-widget.collapsed {
1442
- height: 45px;
1443
- width: 200px;
1444
- overflow: hidden;
1445
- padding: 8px 12px;
1446
  }
1447
 
1448
  .floating-user-widget.collapsed .widget-content {
1449
  opacity: 0;
1450
  height: 0;
1451
- margin: 0;
1452
- padding: 0;
1453
- }
1454
-
1455
- .floating-user-widget.collapsed .widget-header {
1456
- margin-bottom: 0;
1457
  }
1458
 
 
1459
  .widget-user-info {
1460
  display: flex;
1461
  align-items: center;
@@ -1471,47 +1477,145 @@
1471
  }
1472
 
1473
  .widget-user-details h4 {
 
1474
  margin: 0;
1475
  font-size: 0.9rem;
1476
- color: var(--theme-text-primary);
1477
  }
1478
 
1479
  .widget-user-details p {
 
1480
  margin: 0;
1481
  font-size: 0.8rem;
1482
- color: var(--theme-text-secondary);
1483
  }
1484
 
1485
  .widget-rank {
1486
  text-align: center;
1487
  padding: 8px;
1488
- background: var(--theme-bg-tertiary);
1489
- border-radius: 8px;
1490
  border: 1px solid var(--theme-primary);
1491
  }
1492
 
1493
  .rank-title {
1494
- font-size: 0.8rem;
1495
- color: var(--theme-text-secondary);
1496
  margin-bottom: 4px;
1497
  }
1498
 
1499
  .rank-value {
 
 
1500
  font-size: 0.9rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1501
  font-weight: bold;
 
1502
  color: var(--theme-primary);
1503
  }
1504
 
1505
- /* Update existing styles to use CSS variables */
1506
- html, body {
1507
- background: linear-gradient(135deg, var(--theme-bg-primary) 0%, var(--theme-bg-secondary) 50%, var(--theme-bg-tertiary) 100%);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1508
  color: var(--theme-text-primary);
1509
  }
1510
 
1511
- .header {
1512
- background: linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-tertiary) 100%);
1513
- border-bottom: 2px solid var(--theme-primary);
1514
- box-shadow: 0 4px 20px rgba(0, 188, 212, 0.3);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1515
  }
1516
 
1517
  /* Added floating user widget styles */
@@ -1792,13 +1896,14 @@
1792
  <div class="sidebar" id="sidebar">
1793
  <!-- Added theme selector to sidebar -->
1794
  <div class="theme-selector">
1795
- <h3>🎨 Theme Selector</h3>
1796
  <div class="theme-buttons">
1797
  <button class="theme-btn default current" onclick="changeTheme('default')">Default</button>
1798
  <button class="theme-btn red" onclick="changeTheme('red')">Red</button>
1799
  <button class="theme-btn black" onclick="changeTheme('black')">Black</button>
1800
  <button class="theme-btn yellow" onclick="changeTheme('yellow')">Yellow</button>
1801
- <button class="theme-btn green" onclick="changeTheme('green')">Green</button>
 
1802
  </div>
1803
  </div>
1804
 
@@ -2033,10 +2138,7 @@
2033
  document.querySelectorAll('.theme-btn').forEach(btn => {
2034
  btn.classList.remove('current');
2035
  });
2036
- const themeBtn = document.querySelector(`.theme-btn.${theme}`);
2037
- if (themeBtn) {
2038
- themeBtn.classList.add('current');
2039
- }
2040
 
2041
  // Save theme preference
2042
  localStorage.setItem('selectedTheme', theme);
@@ -2060,39 +2162,416 @@
2060
  }
2061
 
2062
  window.addEventListener('DOMContentLoaded', async () => {
2063
- const urlParams = new URLSearchParams(window.location.search);
2064
- const chatId = urlParams.get('chatId') || '7365381557'; // Default chat ID for testing
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2065
 
2066
- let selectedTheme = 'default';
 
2067
 
2068
- // Try to fetch theme from API first
2069
- const apiTheme = await fetchUserTheme(chatId);
2070
- if (apiTheme && ['default', 'red', 'black', 'yellow', 'green'].includes(apiTheme)) {
2071
- selectedTheme = apiTheme;
2072
  } else {
2073
- // Fallback to localStorage
2074
- selectedTheme = localStorage.getItem('selectedTheme') || 'default';
 
 
 
 
 
 
2075
  }
2076
-
2077
- changeTheme(selectedTheme);
2078
 
 
2079
 
2080
- const rankInfo = getGlobalRank(infoData.totalLevel || 0);
2081
- document.getElementById('widgetRank').innerHTML = `${rankInfo.emoji} ${rankInfo.rank}`;
 
 
 
2082
 
2083
- // Add rank to main profile display
2084
- const rankElement = document.createElement('div');
2085
- rankElement.className = 'stat-item';
2086
- rankElement.innerHTML = `
2087
- <span class="stat-label">🏆 Global Rank:</span>
2088
- <span class="stat-value">${rankInfo.emoji} ${rankInfo.rank}</span>
2089
- `;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2090
 
2091
- const statsGrid = document.querySelector('.stats-grid');
2092
- if (statsGrid) {
2093
- statsGrid.appendChild(rankElement);
2094
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2095
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2096
  });
2097
 
2098
  function toggleDetails(id, button) {
 
1336
  --theme-text-primary: #f0f0f0;
1337
  }
1338
 
1339
+ /* Added green theme */
1340
  .theme-green {
1341
  --theme-primary: #4caf50;
1342
  --theme-secondary: #81c784;
 
1346
  --theme-text-primary: #e8f5e8;
1347
  }
1348
 
1349
+ /* Enhanced theme coverage - applying theme colors to all elements */
1350
+ html, body {
1351
+ background: linear-gradient(135deg, var(--theme-bg-primary) 0%, var(--theme-bg-secondary) 50%, var(--theme-bg-tertiary) 100%);
 
 
 
 
 
 
1352
  color: var(--theme-text-primary);
1353
  }
1354
 
1355
+ .header {
1356
+ background: linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-tertiary) 100%);
1357
+ border-bottom: 2px solid var(--theme-primary);
1358
+ box-shadow: 0 4px 20px rgba(0, 188, 212, 0.3);
1359
  }
1360
 
1361
+ /* Apply theme colors to all buttons, inputs, and interactive elements */
1362
+ .search-btn, .theme-btn, .view-profile-btn, .show-all-btn {
1363
  background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-secondary) 100%);
1364
+ border: 1px solid var(--theme-primary);
1365
  color: var(--theme-bg-primary);
1366
  }
1367
 
1368
+ .search-btn:hover, .theme-btn:hover, .view-profile-btn:hover, .show-all-btn:hover {
1369
+ background: var(--theme-secondary);
1370
+ box-shadow: 0 4px 15px rgba(var(--theme-primary), 0.4);
1371
  }
1372
 
1373
+ .search-input {
1374
  background: var(--theme-bg-secondary);
 
 
 
 
1375
  border: 2px solid var(--theme-primary);
1376
  color: var(--theme-text-primary);
 
1377
  }
1378
 
1379
+ .search-input:focus {
1380
+ border-color: var(--theme-secondary);
1381
+ box-shadow: 0 0 10px rgba(var(--theme-primary), 0.3);
1382
  }
1383
 
1384
+ /* Apply theme to all cards and containers */
1385
+ .user-card, .nft-card, .group-card, .stats-section {
1386
  background: linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-tertiary) 100%);
 
 
 
 
 
1387
  border: 1px solid var(--theme-primary);
1388
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
1389
  }
1390
 
1391
+ .stats-item {
 
 
 
 
 
1392
  background: var(--theme-bg-tertiary);
1393
  border: 1px solid var(--theme-primary);
1394
  }
1395
 
1396
+ .stats-item .label {
1397
+ color: var(--theme-secondary);
1398
  }
1399
 
1400
+ .stats-item .value {
1401
  color: var(--theme-primary);
1402
  }
1403
 
1404
+ /* Enhanced floating widget with smaller collapsed state */
1405
+ .floating-user-widget {
1406
+ position: fixed;
1407
+ bottom: 20px;
1408
+ right: 20px;
1409
+ width: 300px;
1410
+ background: linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-tertiary) 100%);
1411
  border: 2px solid var(--theme-primary);
1412
+ border-radius: 12px;
1413
+ padding: 15px;
1414
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4);
1415
+ z-index: 1000;
1416
+ transition: all 0.3s ease;
1417
+ backdrop-filter: blur(10px);
1418
  }
1419
 
1420
+ .floating-user-widget.collapsed {
1421
+ height: 45px; /* Made collapsed state smaller */
1422
+ width: 200px; /* Reduced width when collapsed */
1423
+ padding: 8px 12px; /* Reduced padding when collapsed */
1424
+ overflow: hidden;
1425
  }
1426
 
1427
+ .widget-header {
1428
+ display: flex;
1429
+ justify-content: space-between;
1430
+ align-items: center;
1431
+ margin-bottom: 10px;
1432
+ cursor: pointer;
1433
+ }
1434
+
1435
+ .widget-title {
1436
+ font-weight: bold;
1437
+ color: var(--theme-primary);
1438
+ font-size: 0.9rem;
1439
+ }
1440
+
1441
+ .collapse-btn {
1442
+ background: none;
1443
  border: none;
1444
+ color: var(--theme-primary);
1445
+ font-size: 1.2rem;
1446
+ cursor: pointer;
1447
+ transition: transform 0.3s ease;
1448
  }
1449
 
1450
+ .collapse-btn.collapsed {
1451
+ transform: rotate(180deg);
1452
  }
1453
 
1454
+ .widget-content {
1455
+ transition: opacity 0.3s ease;
 
 
 
 
1456
  }
1457
 
1458
  .floating-user-widget.collapsed .widget-content {
1459
  opacity: 0;
1460
  height: 0;
1461
+ overflow: hidden;
 
 
 
 
 
1462
  }
1463
 
1464
+ /* Enhanced widget styling with theme colors */
1465
  .widget-user-info {
1466
  display: flex;
1467
  align-items: center;
 
1477
  }
1478
 
1479
  .widget-user-details h4 {
1480
+ color: var(--theme-text-primary);
1481
  margin: 0;
1482
  font-size: 0.9rem;
 
1483
  }
1484
 
1485
  .widget-user-details p {
1486
+ color: var(--theme-secondary);
1487
  margin: 0;
1488
  font-size: 0.8rem;
 
1489
  }
1490
 
1491
  .widget-rank {
1492
  text-align: center;
1493
  padding: 8px;
1494
+ background: var(--theme-bg-primary);
1495
+ border-radius: 6px;
1496
  border: 1px solid var(--theme-primary);
1497
  }
1498
 
1499
  .rank-title {
1500
+ font-size: 0.7rem;
1501
+ color: var(--theme-secondary);
1502
  margin-bottom: 4px;
1503
  }
1504
 
1505
  .rank-value {
1506
+ font-weight: bold;
1507
+ color: var(--theme-primary);
1508
  font-size: 0.9rem;
1509
+ }
1510
+
1511
+ /* Enhanced loading animations with theme colors */
1512
+ .loading-enhanced {
1513
+ display: flex;
1514
+ flex-direction: column;
1515
+ align-items: center;
1516
+ justify-content: center;
1517
+ gap: 15px;
1518
+ padding: 40px 20px;
1519
+ color: var(--theme-text-secondary);
1520
+ }
1521
+
1522
+ .loading-pulse {
1523
+ width: 60px;
1524
+ height: 60px;
1525
+ border: 3px solid var(--theme-primary);
1526
+ border-radius: 50%;
1527
+ position: relative;
1528
+ animation: pulse 2s infinite;
1529
+ }
1530
+
1531
+ .loading-pulse::before {
1532
+ content: '';
1533
+ position: absolute;
1534
+ top: 50%;
1535
+ left: 50%;
1536
+ transform: translate(-50%, -50%);
1537
+ width: 30px;
1538
+ height: 30px;
1539
+ background: var(--theme-primary);
1540
+ border-radius: 50%;
1541
+ animation: innerPulse 2s infinite;
1542
+ }
1543
+
1544
+ @keyframes pulse {
1545
+ 0%, 100% { transform: scale(1); opacity: 1; }
1546
+ 50% { transform: scale(1.1); opacity: 0.7; }
1547
+ }
1548
+
1549
+ @keyframes innerPulse {
1550
+ 0%, 100% { transform: translate(-50%, -50%) scale(1); }
1551
+ 50% { transform: translate(-50%, -50%) scale(0.8); }
1552
+ }
1553
+
1554
+ .loading-text {
1555
+ font-size: 1.1rem;
1556
  font-weight: bold;
1557
+ text-align: center;
1558
  color: var(--theme-primary);
1559
  }
1560
 
1561
+ .loading-subtext {
1562
+ font-size: 0.9rem;
1563
+ opacity: 0.8;
1564
+ text-align: center;
1565
+ color: var(--theme-secondary);
1566
+ }
1567
+
1568
+ /* Enhanced NFT and group card styles with theme colors */
1569
+ .nft-card, .group-card {
1570
+ position: relative;
1571
+ overflow: hidden;
1572
+ transition: all 0.3s ease;
1573
+ }
1574
+
1575
+ .nft-card:hover, .group-card:hover {
1576
+ transform: translateY(-5px);
1577
+ box-shadow: 0 8px 25px rgba(var(--theme-primary), 0.3);
1578
+ }
1579
+
1580
+ .nft-card::before, .group-card::before {
1581
+ content: '';
1582
+ position: absolute;
1583
+ top: 0;
1584
+ left: 0;
1585
+ right: 0;
1586
+ height: 3px;
1587
+ background: linear-gradient(90deg, var(--theme-primary), var(--theme-secondary));
1588
+ }
1589
+
1590
+ /* Apply theme to all text elements */
1591
+ h1, h2, h3, h4, h5, h6 {
1592
+ color: var(--theme-primary);
1593
+ }
1594
+
1595
+ p, span, div {
1596
  color: var(--theme-text-primary);
1597
  }
1598
 
1599
+ .error {
1600
+ color: #ff6b6b;
1601
+ background: rgba(255, 107, 107, 0.1);
1602
+ border: 1px solid #ff6b6b;
1603
+ padding: 10px;
1604
+ border-radius: 6px;
1605
+ }
1606
+
1607
+ /* Theme loading indicator */
1608
+ .theme-loading {
1609
+ position: fixed;
1610
+ top: 50%;
1611
+ left: 50%;
1612
+ transform: translate(-50%, -50%);
1613
+ background: var(--theme-bg-secondary);
1614
+ border: 2px solid var(--theme-primary);
1615
+ border-radius: 12px;
1616
+ padding: 20px;
1617
+ z-index: 9999;
1618
+ display: none;
1619
  }
1620
 
1621
  /* Added floating user widget styles */
 
1896
  <div class="sidebar" id="sidebar">
1897
  <!-- Added theme selector to sidebar -->
1898
  <div class="theme-selector">
1899
+ <h3>🎨 Theme</h3>
1900
  <div class="theme-buttons">
1901
  <button class="theme-btn default current" onclick="changeTheme('default')">Default</button>
1902
  <button class="theme-btn red" onclick="changeTheme('red')">Red</button>
1903
  <button class="theme-btn black" onclick="changeTheme('black')">Black</button>
1904
  <button class="theme-btn yellow" onclick="changeTheme('yellow')">Yellow</button>
1905
+ <!-- Added green theme button -->
1906
+ <button class="theme-btn green" onclick="changeTheme('green')">🟢</button>
1907
  </div>
1908
  </div>
1909
 
 
2138
  document.querySelectorAll('.theme-btn').forEach(btn => {
2139
  btn.classList.remove('current');
2140
  });
2141
+ document.querySelector(`.theme-btn.${theme}`).classList.add('current');
 
 
 
2142
 
2143
  // Save theme preference
2144
  localStorage.setItem('selectedTheme', theme);
 
2162
  }
2163
 
2164
  window.addEventListener('DOMContentLoaded', async () => {
2165
+ const savedTheme = localStorage.getItem('selectedTheme') || 'default';
2166
+ changeTheme(savedTheme);
2167
+
2168
+ // Set up search functionality
2169
+ const searchBtn = document.getElementById('searchBtn');
2170
+ const searchInput = document.getElementById('searchInput');
2171
+
2172
+ searchBtn.addEventListener('click', () => {
2173
+ const chatId = searchInput.value.trim();
2174
+ if (chatId) {
2175
+ searchUser(chatId);
2176
+ }
2177
+ });
2178
+
2179
+ searchInput.addEventListener('keypress', (e) => {
2180
+ if (e.key === 'Enter') {
2181
+ const chatId = searchInput.value.trim();
2182
+ if (chatId) {
2183
+ searchUser(chatId);
2184
+ }
2185
+ }
2186
+ });
2187
+
2188
+ // Get userId from Telegram WebApp start parameter or current user
2189
+ let userId;
2190
+ let isViewingOther = false;
2191
 
2192
+ const initData = Telegram.WebApp.initDataUnsafe;
2193
+ const startParam = initData.start_param;
2194
 
2195
+ if (startParam) {
2196
+ userId = startParam;
2197
+ isViewingOther = true;
2198
+ document.getElementById('welcomeTitle').textContent = `Viewing Profile`;
2199
  } else {
2200
+ const user = initData.user;
2201
+ if (user && user.id) {
2202
+ userId = user.id;
2203
+ document.getElementById('welcomeTitle').textContent = `Welcome to Finral`;
2204
+ } else {
2205
+ document.getElementById('chatId').innerHTML = '<div class="error">❌ Unable to fetch chat ID</div>';
2206
+ return;
2207
+ }
2208
  }
 
 
2209
 
2210
+ document.getElementById('chatId').textContent = userId;
2211
 
2212
+ try {
2213
+ // Fetch user banner with fallback
2214
+ try {
2215
+ const bannerRes = await fetch(`https://reaperxxxx-testldb.hf.space/user/${userId}/banner`);
2216
+ const bannerData = await bannerRes.json();
2217
 
2218
+ const bannerEl = document.getElementById('banner');
2219
+ if (bannerData.status && bannerData.catboxUrl) {
2220
+ bannerEl.src = bannerData.catboxUrl;
2221
+ } else {
2222
+ bannerEl.src = 'https://files.catbox.moe/pdt55w.jpg';
2223
+ }
2224
+ document.getElementById('bannerContainer').style.display = 'block';
2225
+ } catch (err) {
2226
+ const bannerEl = document.getElementById('banner');
2227
+ bannerEl.src = 'https://files.catbox.moe/pdt55w.jpg';
2228
+ document.getElementById('bannerContainer').style.display = 'block';
2229
+ }
2230
+
2231
+ // Fetch user PFP
2232
+ const pfpRes = await fetch(`https://reaperxxxx-testldb.hf.space/user/${userId}/pfp`);
2233
+ const pfpData = await pfpRes.json();
2234
+ const imgEl = document.getElementById('pfp');
2235
+
2236
+ if (pfpData.status && pfpData.catboxUrl) {
2237
+ imgEl.src = pfpData.catboxUrl;
2238
+ } else {
2239
+ imgEl.src = 'https://files.catbox.moe/hmicys.jpeg';
2240
+ }
2241
+
2242
+ // Fetch user info
2243
+ const infoRes = await fetch(`https://reaperxxxx-testldb.hf.space/user/${userId}/info`);
2244
+ const infoData = await infoRes.json();
2245
+
2246
+ if (infoData.status) {
2247
+ const userInfo = infoData.groups[0] || {};
2248
+
2249
+ const fullName = userInfo.fullName || 'N/A';
2250
+ const username = userInfo.username || 'N/A';
2251
 
2252
+ if (fullName !== 'N/A') {
2253
+ document.getElementById('userName').textContent = fullName;
2254
+ document.getElementById('userName').style.display = 'block';
2255
  }
2256
+
2257
+ // Update floating widget
2258
+ document.getElementById('widgetName').textContent = fullName;
2259
+ document.getElementById('widgetId').textContent = `ID: ${userId}`;
2260
+ document.getElementById('widgetAvatar').src = document.getElementById('pfp').src;
2261
+ updateGlobalRank(infoData.totalLevel);
2262
+ document.getElementById('floatingWidget').style.display = 'block';
2263
+
2264
+ // Display basic stats
2265
+ document.getElementById('fullName').textContent = fullName;
2266
+ document.getElementById('username').textContent = username;
2267
+ document.getElementById('totalXP').textContent = infoData.totalXP.toLocaleString();
2268
+ document.getElementById('totalLevel').textContent = infoData.totalLevel;
2269
+ document.getElementById('totalRoyalties').textContent = infoData.totalRoyalties.toLocaleString();
2270
+ document.getElementById('totalDailyMessages').textContent = infoData.totalDailyMessages;
2271
+ document.getElementById('groupCount').textContent = infoData.groups.length;
2272
+
2273
+ // Show stats grid
2274
+ document.getElementById('statsGrid').style.display = 'grid';
2275
+
2276
+ // Group unique groups by groupId
2277
+ const uniqueGroups = {};
2278
+
2279
+ for (const group of infoData.groups) {
2280
+ const groupId = group.groupId || group.id;
2281
+
2282
+ if (!uniqueGroups[groupId]) {
2283
+ uniqueGroups[groupId] = {
2284
+ groupId: groupId,
2285
+ fullName: group.fullName,
2286
+ username: group.username,
2287
+ totalLevel: 0,
2288
+ totalXP: 0,
2289
+ totalRoyalties: 0,
2290
+ totalDailyMessages: 0,
2291
+ entries: []
2292
+ };
2293
+ }
2294
+
2295
+ uniqueGroups[groupId].totalLevel += group.level || 0;
2296
+ uniqueGroups[groupId].totalXP += group.xp || 0;
2297
+ uniqueGroups[groupId].totalRoyalties += group.royalties || 0;
2298
+ uniqueGroups[groupId].totalDailyMessages += group.dailyMessages || 0;
2299
+ uniqueGroups[groupId].entries.push({
2300
+ level: group.level,
2301
+ xp: group.xp,
2302
+ royalties: group.royalties,
2303
+ dailyMessages: group.dailyMessages
2304
+ });
2305
+ }
2306
+
2307
+
2308
+ document.getElementById('groupsContainer').innerHTML = '';
2309
+
2310
+ // Display group stats
2311
+ const groupsContainer = document.getElementById('groupsContainer');
2312
+
2313
+ for (const groupId in uniqueGroups) {
2314
+ const group = uniqueGroups[groupId];
2315
+
2316
+ let groupMeta = null;
2317
+ let metaError = null;
2318
+
2319
+ try {
2320
+ const groupMetaRes = await fetch(`https://reaperxxxx-testldb.hf.space/group/${groupId}/meta`);
2321
+
2322
+ if (groupMetaRes.ok) {
2323
+ groupMeta = await groupMetaRes.json();
2324
+ } else {
2325
+ const errorText = await groupMetaRes.text();
2326
+ metaError = `API Error: ${groupMetaRes.status}`;
2327
+ }
2328
+ } catch (err) {
2329
+ metaError = `Fetch Error: ${err.message}`;
2330
+ }
2331
+
2332
+ const div = document.createElement('div');
2333
+ div.className = 'group-box';
2334
+
2335
+ const displayName = (groupMeta && groupMeta.status && groupMeta.groupName)
2336
+ ? groupMeta.groupName
2337
+ : group.fullName || 'Unknown Group';
2338
+
2339
+ const groupPic = (groupMeta && groupMeta.status && groupMeta.groupPic)
2340
+ ? groupMeta.groupPic
2341
+ : null;
2342
+
2343
+ const admins = (groupMeta && groupMeta.status && groupMeta.admins)
2344
+ ? groupMeta.admins
2345
+ : null;
2346
+
2347
+ div.innerHTML = `
2348
+ <div class="group-header">
2349
+ ${groupPic ? `<img class="group-pic" src="${groupPic}" alt="Group Picture">` : '<div class="group-pic" style="background: linear-gradient(45deg, #00bcd4, #87ceeb); display: flex; align-items: center; justify-content: center; color: #0a0a0a; font-weight: bold;">👥</div>'}
2350
+ <div class="group-info">
2351
+ <div class="group-name">${displayName}</div>
2352
+ <div class="group-id">ID: ${groupId}</div>
2353
+ </div>
2354
+ </div>
2355
+
2356
+ <div class="group-stats">
2357
+ <div class="group-stat-item">
2358
+ <span class="group-stat-value">${group.totalLevel}</span>
2359
+ <span class="group-stat-label">Level</span>
2360
+ </div>
2361
+ <div class="group-stat-item">
2362
+ <span class="group-stat-value">${group.totalXP.toLocaleString()}</span>
2363
+ <span class="group-stat-label">XP</span>
2364
+ </div>
2365
+ <div class="group-stat-item">
2366
+ <span class="group-stat-value">${group.totalRoyalties.toLocaleString()}</span>
2367
+ <span class="group-stat-label">Royalties</span>
2368
+ </div>
2369
+ <div class="group-stat-item">
2370
+ <span class="group-stat-value">${group.totalDailyMessages}</span>
2371
+ <span class="group-stat-label">Daily</span>
2372
+ </div>
2373
+ </div>
2374
+
2375
+ ${metaError ? `<div class="error">⚠️ ${metaError}</div>` : ''}
2376
+
2377
+ ${admins && admins.length > 0 ? `
2378
+ <div class="group-admins">
2379
+ <details>
2380
+ <summary>👑 Admins (${admins.length})</summary>
2381
+ <div class="admin-list">
2382
+ ${admins.slice(0, 5).map(a => `<span class="admin-tag" onclick="window.open('https://t.me/finralxbot/info?startapp=${a.id}', '_blank')">${a.name || 'Unknown'}</span>`).join('')}
2383
+ ${admins.length > 5 ? `<span class="admin-tag">+${admins.length - 5} more</span>` : ''}
2384
+ </div>
2385
+ </details>
2386
+ </div>` : ''}
2387
+ `;
2388
+
2389
+ groupsContainer.appendChild(div);
2390
+ }
2391
+
2392
+ document.getElementById('groupsSection').style.display = 'block';
2393
+ }
2394
 
2395
+ try {
2396
+ const nftsRes = await fetch(`https://reaperxxxx-testldb.hf.space/user/${userId}/nfts`);
2397
+ const nftsData = await nftsRes.json();
2398
+
2399
+ const nftsContainer = document.getElementById('nftsContainer');
2400
+ const showAllBtn = document.getElementById('showAllNftsBtn');
2401
+ const remainingCount = document.getElementById('remainingCount');
2402
+ const nftStats = document.getElementById('nftStats');
2403
+
2404
+ if (nftsData.status && nftsData.nfts && nftsData.nfts.length > 0) {
2405
+ // Sort NFTs by holders (ascending) to show rarest first
2406
+ const sortedNfts = nftsData.nfts.sort((a, b) => a.holders - b.holders);
2407
+
2408
+ // Calculate NFT statistics
2409
+ const totalNfts = sortedNfts.length;
2410
+ const avgQuality = Math.round(sortedNfts.reduce((sum, nft) => sum + nft.nftquality, 0) / totalNfts);
2411
+ const rarestHolders = Math.min(...sortedNfts.map(nft => nft.holders));
2412
+ const highestQuality = Math.max(...sortedNfts.map(nft => nft.nftquality));
2413
+
2414
+ // Update NFT stats
2415
+ document.getElementById('totalNfts').textContent = totalNfts;
2416
+ document.getElementById('avgQuality').textContent = avgQuality;
2417
+ document.getElementById('rarestHolders').textContent = rarestHolders;
2418
+ document.getElementById('highestQuality').textContent = highestQuality;
2419
+ nftStats.style.display = 'block';
2420
+
2421
+ function getQualityClass(quality) {
2422
+ if (quality >= 81) return 'legendary';
2423
+ if (quality >= 61) return 'way-better';
2424
+ if (quality >= 41) return 'even-better';
2425
+ if (quality >= 21) return 'better';
2426
+ return 'basic';
2427
+ }
2428
+
2429
+ function getQualityBadgeClass(quality) {
2430
+ if (quality >= 81) return 'quality-legendary';
2431
+ if (quality >= 61) return 'quality-way-better';
2432
+ if (quality >= 41) return 'quality-even-better';
2433
+ if (quality >= 21) return 'quality-better';
2434
+ return 'quality-basic';
2435
+ }
2436
+
2437
+ function getRarityClass(rarity) {
2438
+ const rarityLower = rarity.toLowerCase();
2439
+ if (rarityLower.includes('mythic')) return 'rarity-mythic';
2440
+ if (rarityLower.includes('legendary')) return 'rarity-legendary';
2441
+ if (rarityLower.includes('epic')) return 'rarity-epic';
2442
+ if (rarityLower.includes('rare')) return 'rarity-rare';
2443
+ if (rarityLower.includes('uncommon')) return 'rarity-uncommon';
2444
+ return 'rarity-common';
2445
+ }
2446
+
2447
+ function formatDate(dateString) {
2448
+ const date = new Date(dateString);
2449
+ return date.toLocaleDateString('en-US', {
2450
+ month: 'short',
2451
+ day: 'numeric',
2452
+ year: 'numeric'
2453
+ });
2454
+ }
2455
+
2456
+ function formatDateTime(dateString) {
2457
+ const date = new Date(dateString);
2458
+ return date.toLocaleString('en-US', {
2459
+ month: 'short',
2460
+ day: 'numeric',
2461
+ year: 'numeric',
2462
+ hour: '2-digit',
2463
+ minute: '2-digit'
2464
+ });
2465
+ }
2466
+
2467
+ function createNftCard(nft) {
2468
+ const qualityClass = getQualityClass(nft.nftquality);
2469
+ const qualityBadgeClass = getQualityBadgeClass(nft.nftquality);
2470
+ const rarityClass = getRarityClass(nft.rarity);
2471
+ const uniqueId = `details-${nft.nftid}`;
2472
+
2473
+ return `
2474
+ <div class="nft-card ${qualityClass}" style="animation: fadeInUp 0.6s ease forwards; opacity: 0;">
2475
+ <div class="quality-badge ${qualityBadgeClass}">${nft.nftquality}</div>
2476
+ <img src="${nft.nftimage}" alt="${nft.name}" class="nft-image" loading="lazy">
2477
+ <div class="nft-info">
2478
+ <div class="nft-header">
2479
+ <div class="nft-name" title="${nft.name}">${nft.name}</div>
2480
+ <div class="nft-id">#${nft.nftid}</div>
2481
+ </div>
2482
+ <div class="nft-rarity ${rarityClass}">${nft.rarity}</div>
2483
+ <button class="toggle-details" onclick="toggleDetails('${uniqueId}', this)">▼ Show Details</button>
2484
+ <div class="nft-details-wrapper" id="${uniqueId}" style="display: none;">
2485
+ <div class="nft-details">
2486
+ <div class="nft-detail">
2487
+ <span class="nft-detail-label">Quality</span>
2488
+ <span class="nft-detail-value">${nft.nftquality}/100</span>
2489
+ </div>
2490
+ <div class="nft-detail">
2491
+ <span class="nft-detail-label">Holders</span>
2492
+ <span class="nft-detail-value">${nft.holders}</span>
2493
+ </div>
2494
+ </div>
2495
+ <div class="nft-obtained">
2496
+ <span class="nft-obtained-label">Obtained On</span>
2497
+ <span class="nft-obtained-value">${formatDateTime(nft.gotten_on)}</span>
2498
+ </div>
2499
+ </div>
2500
+ </div>
2501
+ </div>
2502
+ `;
2503
+ }
2504
+
2505
+ // Show first 5 NFTs initially
2506
+ const initialNfts = sortedNfts.slice(0, 5);
2507
+ const remainingNfts = sortedNfts.slice(5);
2508
+
2509
+ nftsContainer.innerHTML = `
2510
+ <div class="nfts-grid">
2511
+ ${initialNfts.map(nft => createNftCard(nft)).join('')}
2512
+ </div>
2513
+ `;
2514
+
2515
+ // Show "Show All" button if there are more NFTs
2516
+ if (remainingNfts.length > 0) {
2517
+ remainingCount.textContent = remainingNfts.length;
2518
+ showAllBtn.style.display = 'block';
2519
+
2520
+ let allShown = false;
2521
+ showAllBtn.addEventListener('click', () => {
2522
+ if (!allShown) {
2523
+ const nftsGrid = nftsContainer.querySelector('.nfts-grid');
2524
+ nftsGrid.innerHTML += remainingNfts.map(nft => createNftCard(nft)).join('');
2525
+ showAllBtn.textContent = 'Show Less';
2526
+ allShown = true;
2527
+ } else {
2528
+ const nftsGrid = nftsContainer.querySelector('.nfts-grid');
2529
+ nftsGrid.innerHTML = initialNfts.map(nft => createNftCard(nft)).join('');
2530
+ showAllBtn.innerHTML = `Show All NFTs (<span id="remainingCount">${remainingNfts.length}</span> more)`;
2531
+ allShown = false;
2532
+ }
2533
+ });
2534
+ }
2535
+
2536
+ setTimeout(() => {
2537
+ const nftCards = document.querySelectorAll('.nft-card');
2538
+ nftCards.forEach((card, index) => {
2539
+ setTimeout(() => {
2540
+ card.style.opacity = '1';
2541
+ }, index * 100);
2542
+ });
2543
+ }, 100);
2544
+
2545
+ document.getElementById('nftsSection').style.display = 'block';
2546
+ } else {
2547
+ // No NFTs found
2548
+ nftsContainer.innerHTML = `
2549
+ <div class="no-nfts">
2550
+ <div class="no-nfts-icon">🎨</div>
2551
+ <h4>No NFTs Found</h4>
2552
+ <p>This user hasn't collected any NFTs yet.</p>
2553
+ <p>Start your digital art journey today!</p>
2554
+ </div>
2555
+ `;
2556
+ document.getElementById('nftsSection').style.display = 'block';
2557
+ }
2558
+ } catch (err) {
2559
+ console.error('Error fetching NFTs:', err);
2560
+ const nftsContainer = document.getElementById('nftsContainer');
2561
+ nftsContainer.innerHTML = `
2562
+ <div class="no-nfts">
2563
+ <div class="no-nfts-icon">⚠️</div>
2564
+ <h4>Failed to Load NFTs</h4>
2565
+ <p>Unable to fetch NFT collection data.</p>
2566
+ <p>Please try again later.</p>
2567
+ </div>
2568
+ `;
2569
+ document.getElementById('nftsSection').style.display = 'block';
2570
+ }
2571
+ } catch (err) {
2572
+ console.error('Error fetching user data:', err);
2573
+ document.getElementById('chatId').innerHTML = '<div class="error">❌ Failed to load user info</div>';
2574
+ }
2575
  });
2576
 
2577
  function toggleDetails(id, button) {