lava / docs.html
Reaperxxxx's picture
Update docs.html
502b558 verified
Raw
History Blame Contribute Delete
80.3 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Finral - User Profile Search</title>
<script src="https://telegram.org/js/telegram-web-app.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a2e 50%, #16213e 100%);
color: #e0e6ed;
padding: 0;
margin: 0;
min-height: 100vh;
position: relative;
overflow-x: hidden;
max-width: 100vw;
}
.header {
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
border-bottom: 2px solid #00bcd4;
padding: 10px;
text-align: center;
box-shadow: 0 4px 20px rgba(0, 188, 212, 0.3);
position: relative;
z-index: 100;
}
.header::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(45deg, transparent 30%, rgba(0, 188, 212, 0.1) 50%, transparent 70%);
animation: shimmer 3s infinite;
}
@keyframes shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
.page-title {
font-size: 1.6rem;
font-weight: 900;
background: linear-gradient(45deg, var(--theme-primary), var(--theme-secondary), #ffffff, var(--theme-primary));
background-size: 300% 300%;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 3px;
text-shadow: 0 0 30px rgba(0, 188, 212, 0.8);
animation: gradientShift 4s ease-in-out infinite;
letter-spacing: 1px;
position: relative;
z-index: 3;
}
.page-title::after {
content: '🔍';
position: absolute;
right: -25px;
top: -3px;
font-size: 1rem;
animation: spark 2s infinite;
}
@keyframes gradientShift {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
@keyframes spark {
0%, 100% { transform: rotate(0deg) scale(1); opacity: 0.7; }
50% { transform: rotate(15deg) scale(1.2); opacity: 1; }
}
.creator {
font-size: 0.7rem;
background: linear-gradient(45deg, var(--theme-secondary), var(--theme-primary));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 3px;
font-weight: 600;
letter-spacing: 0.5px;
position: relative;
z-index: 3;
}
.page-subtitle {
font-size: 0.65rem;
color: rgba(135, 206, 235, 0.8);
margin-bottom: 0;
font-style: italic;
font-weight: 300;
position: relative;
z-index: 3;
}
.main-layout {
display: flex;
min-height: calc(100vh - 80px);
}
.sidebar {
width: 280px;
background: linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-primary) 100%);
border-right: 2px solid var(--theme-primary);
padding: 15px;
position: fixed;
left: 0;
top: 80px;
height: calc(100vh - 80px);
overflow-y: auto;
z-index: 50;
box-shadow: 4px 0 20px rgba(var(--theme-primary-rgb), 0.3);
}
.sidebar-toggle {
display: none;
position: fixed;
top: 90px;
left: 10px;
z-index: 60;
background: linear-gradient(45deg, var(--theme-primary), var(--theme-secondary));
border: none;
border-radius: 50%;
width: 40px;
height: 40px;
color: #0a0a0a;
font-size: 1.2rem;
cursor: pointer;
box-shadow: 0 4px 15px rgba(0, 188, 212, 0.5);
}
.search-section {
background: linear-gradient(135deg, var(--theme-bg-primary) 0%, var(--theme-bg-secondary) 100%);
border: 1px solid var(--theme-primary);
border-radius: 10px;
padding: 15px;
margin-bottom: 15px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
position: relative;
overflow: hidden;
}
.search-section::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, var(--theme-primary), transparent);
}
.search-section h3 {
font-size: 1rem;
color: var(--theme-primary);
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 6px;
}
.search-section h3::before {
content: '';
width: 3px;
height: 15px;
background: linear-gradient(45deg, #00bcd4, #87ceeb);
border-radius: 2px;
}
.search-input {
padding: 10px 12px;
font-size: 0.9rem;
width: 100%;
border: 2px solid #00bcd4;
border-radius: 6px;
margin-bottom: 10px;
background: rgba(26, 26, 46, 0.8);
color: #e0e6ed;
transition: all 0.3s ease;
}
.search-input:focus {
outline: none;
border-color: var(--theme-secondary);
box-shadow: 0 0 10px rgba(0, 188, 212, 0.4);
}
.search-input::placeholder {
color: var(--theme-secondary);
}
.search-btn {
padding: 10px 16px;
font-size: 0.9rem;
background: linear-gradient(45deg, var(--theme-primary), var(--theme-secondary));
color: #0a0a0a;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s ease;
width: 100%;
}
.search-btn:hover {
transform: translateY(-1px);
box-shadow: 0 4px 15px rgba(0, 188, 212, 0.4);
}
.search-btn:disabled {
background: #555;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.search-result {
margin-top: 10px;
padding: 12px;
background: rgba(0, 188, 212, 0.1);
border: 1px solid rgba(0, 188, 212, 0.3);
border-radius: 6px;
font-size: 0.85rem;
}
.view-profile-btn {
padding: 6px 12px;
background: linear-gradient(45deg, #4caf50, #66bb6a);
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-top: 8px;
font-weight: bold;
font-size: 0.8rem;
transition: all 0.3s ease;
width: 100%;
}
.view-profile-btn:hover {
transform: translateY(-1px);
box-shadow: 0 3px 10px rgba(76, 175, 80, 0.4);
}
.content {
flex: 1;
margin-left: 280px;
padding: 15px;
overflow-x: auto;
}
.top-section {
display: grid;
grid-template-columns: 1fr 300px;
gap: 15px;
margin-bottom: 15px;
min-height: 200px;
}
.banner-profile-container {
position: relative;
background: linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-primary) 100%);
border: 1px solid var(--theme-primary);
border-radius: 10px;
overflow: hidden;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
}
.banner-profile-container::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, var(--theme-primary), transparent);
z-index: 2;
}
#banner {
width: 100%;
height: 140px;
object-fit: cover;
border-radius: 0;
}
.banner-overlay {
position: absolute;
top: 2px;
left: 0;
right: 0;
height: 138px;
background: linear-gradient(
to bottom,
rgba(0, 0, 0, 0.1) 0%,
rgba(0, 0, 0, 0.3) 50%,
rgba(26, 26, 46, 0.8) 100%
);
z-index: 2;
}
#pfp {
position: absolute;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
width: 105px;
height: 105px;
object-fit: cover;
border-radius: 5%;
border: 3px solid var(--theme-primary); /* use theme color */
box-shadow:
0 0 20px rgba(var(--theme-primary-rgb), 0.8), /* use theme RGB for shadow */
0 0 40px rgba(var(--theme-primary-rgb), 0.4);
background: var(--theme-bg-secondary);
z-index: 4;
}
.profile-glow {
position: absolute;
bottom: -30px;
left: 50%;
transform: translateX(-50%);
width: 100px;
height: 100px;
border-radius: 50%;
background: radial-gradient(
circle,
rgba(var(--theme-primary-rgb), 0.4) 0%,
rgba(var(--theme-primary-rgb), 0.2) 50%,
transparent 70%
);
z-index: 3;
animation: profileGlow 3s ease-in-out infinite alternate;
}
@keyframes profileGlow {
0% { transform: translateX(-50%) scale(1); opacity: 0.6; }
100% { transform: translateX(-50%) scale(1.1); opacity: 0.9; }
}
.user-info-card {
background: linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-primary) 100%);
border: 1px solid var(--theme-primary);
border-radius: 10px;
padding: 15px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
}
.user-info-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, var(--theme-primary), transparent);
}
.welcome-title {
font-size: 1.2rem;
font-weight: bold;
color: #e0e6ed;
margin-bottom: 8px;
background: linear-gradient(45deg, #e0e6ed, #87ceeb);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-align: center;
}
.chat-id {
font-size: 1rem;
font-weight: bold;
color: #00bcd4;
background: rgba(0, 188, 212, 0.1);
border: 1px solid rgba(0, 188, 212, 0.3);
border-radius: 6px;
padding: 8px;
text-align: center;
margin-bottom: 10px;
}
.stats-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
margin-bottom: 15px;
}
.stats-section {
background:
var(--theme-stats-bg-image, none), /* optional image */
linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
background-size: contain; /* or cover, depending on whether you want full image or cropped */
background-position: center;
background-repeat: no-repeat;
border: 1px solid #00bcd4;
border-radius: 10px;
padding: 15px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
position: relative;
overflow: hidden;
}
.stats-section::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, #00bcd4, transparent);
}
.stats-section h3 {
font-size: 1.1rem;
color: #00bcd4;
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 6px;
}
.stats-section h3::before {
content: '';
width: 3px;
height: 15px;
background: linear-gradient(45deg, #00bcd4, #87ceeb);
border-radius: 2px;
}
.basic-stats-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
.stat-item {
background: rgba(0, 188, 212, 0.1);
border: 1px solid rgba(0, 188, 212, 0.3);
border-radius: 6px;
padding: 8px 6px;
text-align: center;
transition: all 0.3s ease;
}
.stat-item:hover {
border-color: #00bcd4;
box-shadow: 0 2px 8px rgba(0, 188, 212, 0.3);
transform: translateY(-1px);
}
.stat-item strong {
color: #87ceeb;
font-size: 0.75rem;
display: block;
margin-bottom: 2px;
}
.stat-value {
color: #00bcd4;
font-weight: bold;
font-size: 0.9rem;
}
.groups-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 12px;
}
.group-box {
background: linear-gradient(135deg, var(--theme-bg-tertiary) 0%, var(--theme-bg-secondary) 100%);
border: 1px solid var(--theme-primary);
border-radius: 8px;
padding: 12px;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.group-box::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(90deg, transparent, var(--theme-primary), transparent);
}
.group-box:hover {
border-color: var(--theme-primary);
box-shadow: 0 4px 15px rgba(0, 188, 212, 0.3);
transform: translateY(-2px);
}
.group-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
}
.group-pic {
width: 50px;
height: 50px;
object-fit: cover;
border-radius: 8px;
border: 2px solid var(--theme-primary);
flex-shrink: 0;
}
.group-info {
flex: 1;
min-width: 0;
}
.group-name {
font-weight: bold;
color: var(--theme-primary);
font-size: 0.9rem;
margin-bottom: 2px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.group-id {
font-size: 0.75rem;
color: var(--theme-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.group-stats {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6px;
margin-bottom: 8px;
}
.group-stat-item {
background: rgba(0, 188, 212, 0.05);
border: 1px solid var(--theme-primary);
border-radius: 4px;
padding: 4px 6px;
text-align: center;
}
.group-stat-value {
font-weight: bold;
color: var(--theme-primary);
font-size: 0.8rem;
display: block;
}
.group-stat-label {
font-size: 0.65rem;
color: var(--theme-secondary);
}
.group-admins {
margin-top: 8px;
font-size: 0.8rem;
}
.group-admins summary {
color: var(--theme-secondary);
cursor: pointer;
font-weight: bold;
margin-bottom: 4px;
}
.admin-list {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-top: 4px;
}
.admin-tag {
background: rgba(0, 188, 212, 0.2);
border: 1px solid var(--theme-primary);
border-radius: 12px;
padding: 2px 6px;
font-size: 0.7rem;
color: var(--theme-secondary);
cursor: pointer;
transition: all 0.3s ease;
}
.admin-tag:hover {
background: rgba(0, 188, 212, 0.3);
color: #00bcd4;
}
.error {
color: #ff6b6b;
font-style: italic;
background: rgba(255, 107, 107, 0.1);
border: 1px solid rgba(255, 107, 107, 0.3);
border-radius: 4px;
padding: 6px;
margin: 6px 0;
font-size: 0.8rem;
}
.loading {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
color: #87ceeb;
font-size: 1rem;
padding: 40px 20px;
}
.loading-spinner {
width: 20px;
height: 20px;
border: 2px solid #87ceeb;
border-top: 2px solid #00bcd4;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-dots {
display: inline-flex;
gap: 4px;
}
.loading-dot {
width: 6px;
height: 6px;
background: #00bcd4;
border-radius: 50%;
animation: loadingDots 1.4s infinite ease-in-out;
}
@keyframes loadingDots {
0%, 80%, 100% { transform: scale(0); opacity: 0.5; }
40% { transform: scale(1); opacity: 1; }
}
/* NFT Styles */
.nfts-section {
background: var(--theme-nft-bg-image, none), /* optional image */
linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-tertiary) 100%);
background-size: cover;
background-position: center;
background-repeat: no-repeat;
border: 1px solid var(--theme-primary);
border-radius: 10px;
padding: 15px;
margin-bottom: 15px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
position: relative;
overflow: hidden;
}
.nfts-section::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, var(--theme-primary), transparent);
}
.nfts-section h3 {
font-size: 1.1rem;
color: var(--theme-primary);
margin-bottom: 15px;
display: flex;
align-items: center;
gap: 8px;
}
.nfts-section h3::before {
content: '';
width: 3px;
height: 15px;
background: linear-gradient(45deg, var(--theme-primary), var(--theme-secondary));
border-radius: 2px;
}
.nfts-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 15px;
margin-bottom: 15px;
}
.nft-card {
border-radius: 12px;
padding: 12px;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
cursor: pointer;
}
/* Basic Quality (0-20) */
.nft-card.basic {
background: linear-gradient(135deg, #2a2a3e 0%, #1e1e32 100%);
border: 1px solid #555;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.nft-card.basic:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(85, 85, 85, 0.4);
}
/* Better Quality (21-40) */
.nft-card.better {
background: linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-tertiary) 100%);
border: 1px solid #4caf50;
box-shadow: 0 3px 10px rgba(76, 175, 80, 0.3);
}
.nft-card.better::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, #4caf50, transparent);
}
.nft-card.better:hover {
transform: translateY(-3px);
box-shadow: 0 6px 15px rgba(76, 175, 80, 0.5);
}
/* Even Better Quality (41-60) */
.nft-card.even-better {
background: linear-gradient(135deg, #1a1e3e 0%, #2e1a3e 100%);
border: 1px solid #9c27b0;
box-shadow: 0 4px 12px rgba(156, 39, 176, 0.4);
position: relative;
}
.nft-card.even-better::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, #9c27b0, #e91e63, transparent);
}
.nft-card.even-better::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(45deg, transparent 30%, rgba(156, 39, 176, 0.1) 50%, transparent 70%);
animation: shimmer 3s infinite;
pointer-events: none;
}
.nft-card.even-better:hover {
transform: translateY(-4px);
box-shadow: 0 8px 20px rgba(156, 39, 176, 0.6);
}
/* Way Better Quality (61-80) */
.nft-card.way-better {
background: linear-gradient(135deg, #3e1a1a 0%, #3e2a1a 100%);
border: 2px solid #ff9800;
box-shadow: 0 5px 15px rgba(255, 152, 0, 0.5);
position: relative;
}
.nft-card.way-better::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg, #ff9800, #ffc107, #ff5722, #ff9800);
background-size: 300% 300%;
border-radius: 12px;
z-index: -1;
animation: gradientShift 2s ease-in-out infinite;
}
.nft-card.way-better::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(45deg, transparent 30%, rgba(255, 152, 0, 0.2) 50%, transparent 70%);
animation: shimmer 2s infinite;
pointer-events: none;
}
.nft-card.way-better:hover {
transform: translateY(-5px) scale(1.02);
box-shadow: 0 10px 25px rgba(255, 152, 0, 0.7);
}
/* Legendary Quality (81-100) */
.nft-card.legendary {
background: linear-gradient(135deg, #3e1a3e 0%, #1a3e3e 100%);
border: 3px solid #ffd700;
box-shadow:
0 0 20px rgba(255, 215, 0, 0.6),
0 0 40px rgba(255, 215, 0, 0.4),
0 0 60px rgba(255, 215, 0, 0.2);
position: relative;
overflow: hidden;
}
.nft-card.legendary::before {
content: '';
position: absolute;
top: -3px;
left: -3px;
right: -3px;
bottom: -3px;
background: linear-gradient(45deg, #ffd700, #ffeb3b, #ff6f00, #ffd700);
background-size: 400% 400%;
border-radius: 12px;
z-index: -1;
animation: legendaryGlow 1.5s ease-in-out infinite;
}
.nft-card.legendary::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background:
radial-gradient(circle at 20% 20%, rgba(255, 215, 0, 0.3) 0%, transparent 50%),
radial-gradient(circle at 80% 80%, rgba(255, 235, 59, 0.3) 0%, transparent 50%),
linear-gradient(45deg, transparent 30%, rgba(255, 215, 0, 0.1) 50%, transparent 70%);
animation: legendaryShimmer 3s infinite;
pointer-events: none;
}
.nft-card.legendary:hover {
transform: translateY(-6px) scale(1.05);
box-shadow:
0 0 30px rgba(255, 215, 0, 0.8),
0 0 60px rgba(255, 215, 0, 0.6),
0 0 90px rgba(255, 215, 0, 0.4);
}
@keyframes legendaryGlow {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
@keyframes legendaryShimmer {
0% { transform: translateX(-100%) rotate(45deg); }
100% { transform: translateX(100%) rotate(45deg); }
}
.nft-image {
width: 100%;
aspect-ratio: 1;
object-fit: cover;
border-radius: 8px;
margin-bottom: 12px;
transition: all 0.3s ease;
}
.nft-card:hover .nft-image {
transform: scale(1.05);
}
.nft-info {
position: relative;
z-index: 2;
}
.nft-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 8px;
}
.nft-name {
font-weight: bold;
font-size: 1rem;
color: #e0e6ed;
flex: 1;
margin-right: 8px;
line-height: 1.2;
}
.nft-id {
font-size: 0.7rem;
color: #87ceeb;
background: rgba(0, 188, 212, 0.1);
border: 1px solid rgba(0, 188, 212, 0.3);
border-radius: 4px;
padding: 2px 6px;
white-space: nowrap;
}
.nft-rarity {
font-size: 0.8rem;
padding: 3px 8px;
border-radius: 12px;
display: inline-block;
margin-bottom: 8px;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* Keep rarity colors as they represent game mechanics, but make rare use theme color */
.rarity-common { background: #666; color: #fff; }
.rarity-uncommon { background: #4caf50; color: #fff; }
.rarity-rare { background: var(--theme-primary); color: #fff; }
.rarity-epic { background: #9c27b0; color: #fff; }
.rarity-legendary { background: #ff9800; color: #fff; }
.rarity-mythic { background: #f44336; color: #fff; }
.nft-details {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6px;
margin-bottom: 10px;
}
.nft-detail {
background: rgba(0, 188, 212, 0.1);
border: 1px solid rgba(0, 188, 212, 0.2);
border-radius: 6px;
padding: 6px 8px;
text-align: center;
transition: all 0.3s ease;
}
.nft-detail:hover {
background: rgba(0, 188, 212, 0.15);
border-color: rgba(0, 188, 212, 0.4);
}
.nft-detail-label {
color: #87ceeb;
display: block;
font-size: 0.7rem;
margin-bottom: 2px;
font-weight: 500;
}
.nft-detail-value {
color: #00bcd4;
font-weight: bold;
font-size: 0.85rem;
display: block;
}
.nft-obtained {
background: rgba(135, 206, 235, 0.1);
border: 1px solid rgba(135, 206, 235, 0.3);
border-radius: 6px;
padding: 6px 8px;
text-align: center;
grid-column: 1 / -1;
}
.nft-obtained-label {
color: #87ceeb;
font-size: 0.7rem;
margin-bottom: 2px;
display: block;
}
.nft-obtained-value {
color: #87ceeb;
font-weight: bold;
font-size: 0.8rem;
}
.quality-badge {
position: absolute;
top: 8px;
right: 8px;
padding: 4px 8px;
border-radius: 12px;
font-size: 0.75rem;
font-weight: bold;
z-index: 3;
display: flex;
align-items: center;
gap: 4px;
}
.quality-basic {
background: linear-gradient(45deg, #666, #888);
color: #fff;
}
.quality-better {
background: linear-gradient(45deg, #4caf50, #66bb6a);
color: #fff;
}
.quality-even-better {
background: linear-gradient(45deg, #9c27b0, #ba68c8);
color: #fff;
}
.quality-way-better {
background: linear-gradient(45deg, #ff9800, #ffb74d);
color: #fff;
}
.quality-legendary {
background: linear-gradient(45deg, #ffd700, #ffeb3b);
color: #000;
box-shadow: 0 0 10px rgba(255, 215, 0, 0.5);
}
.quality-badge::before {
content: '💠';
font-size: 0.8rem;
}
.no-nfts {
text-align: center;
padding: 60px 20px;
color: #87ceeb;
font-style: italic;
}
.no-nfts-icon {
font-size: 4rem;
margin-bottom: 15px;
opacity: 0.5;
}
.no-nfts h4 {
font-size: 1.2rem;
margin-bottom: 8px;
color: #e0e6ed;
}
.no-nfts p {
font-size: 0.9rem;
margin-bottom: 5px;
}
.show-all-btn {
background: linear-gradient(45deg, #00bcd4, #87ceeb);
color: #0a0a0a;
border: none;
border-radius: 8px;
padding: 12px 24px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
display: block;
margin: 0 auto;
font-size: 0.9rem;
}
.show-all-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0, 188, 212, 0.4);
}
.nft-loading {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
padding: 60px;
color: #87ceeb;
}
.nft-stats {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding: 10px 15px;
background: rgba(0, 188, 212, 0.1);
border: 1px solid rgba(0, 188, 212, 0.3);
border-radius: 8px;
}
.nft-stat {
text-align: center;
}
.nft-stat-value {
font-size: 1.2rem;
font-weight: bold;
color: #00bcd4;
display: block;
}
.nft-stat-label {
font-size: 0.7rem;
color: #87ceeb;
margin-top: 2px;
}
/* Mobile Responsive */
@media (max-width: 768px) {
.sidebar {
transform: translateX(-100%);
transition: transform 0.3s ease;
}
.sidebar.open {
transform: translateX(0);
}
.sidebar-toggle {
display: block;
}
.content {
margin-left: 0;
padding: 10px;
}
.top-section {
grid-template-columns: 1fr;
gap: 10px;
}
.stats-grid {
grid-template-columns: 1fr;
gap: 10px;
}
.basic-stats-grid {
grid-template-columns: repeat(3, 1fr);
gap: 6px;
}
.groups-container {
grid-template-columns: 1fr;
gap: 10px;
}
.group-stats {
grid-template-columns: repeat(4, 1fr);
gap: 4px;
}
.group-stat-item {
padding: 3px 4px;
}
.group-stat-value {
font-size: 0.75rem;
}
.toggle-details {
background: none;
border: none;
color: var(--theme-primary);
cursor: pointer;
font-weight: bold;
margin-top: 5px;
padding: 0;
}
.toggle-details:hover {
text-decoration: underline;
}
.group-stat-label {
font-size: 0.6rem;
}
.nfts-grid {
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 10px;
}
.nft-card {
padding: 10px;
}
.nft-name {
font-size: 0.9rem;
}
.nft-details {
gap: 4px;
}
.nft-detail {
padding: 4px 6px;
}
.nft-stats {
flex-direction: column;
gap: 8px;
}
.nft-stats > div {
display: flex;
justify-content: space-around;
width: 100%;
}
}
@media (max-width: 480px) {
.page-title {
font-size: 1.4rem;
}
.page-title::after {
right: -20px;
font-size: 0.9rem;
}
.header {
padding: 8px;
}
.content {
padding: 8px;
}
.basic-stats-grid {
grid-template-columns: 1fr 1fr;
gap: 4px;
}
.stat-item {
padding: 6px 4px;
}
.stat-item strong {
font-size: 0.7rem;
}
.stat-value {
font-size: 0.8rem;
}
.nfts-grid {
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
gap: 8px;
}
.nft-card {
padding: 8px;
}
.nft-name {
font-size: 0.8rem;
}
.nft-rarity {
font-size: 0.7rem;
padding: 2px 6px;
}
.nft-details {
grid-template-columns: 1fr;
gap: 3px;
}
.nft-detail {
padding: 4px 6px;
}
.quality-badge {
padding: 2px 6px;
font-size: 0.7rem;
}
}
/* Added theme variables and floating widget styles */
:root {
--theme-primary: #00bcd4;
--theme-secondary: #87ceeb;
--theme-bg-primary: #0a0a0a;
--theme-bg-secondary: #1a1a2e;
--theme-bg-tertiary: #16213e;
--theme-text-primary: #e0e6ed;
--theme-text-secondary: #87ceeb;
}
/* Red Theme */
.theme-red {
--theme-primary: #ff4444;
--theme-secondary: #ff6b6b;
--theme-bg-primary: #1a0a0a;
--theme-bg-secondary: #2e1a1a;
--theme-bg-tertiary: #3e1616;
--theme-stats-bg-image: url('https://files.catbox.moe/0im7km.jpeg');
}
/* Black Theme */
.theme-black {
--theme-primary: #ffffff;
--theme-secondary: #cccccc;
--theme-bg-primary: #000000;
--theme-bg-secondary: #1a1a1a;
--theme-bg-tertiary: #2a2a2a;
}
.username-wrapper {
display: inline-flex; /* keeps username and icon in one row */
align-items: center; /* vertical alignment */
gap: 6px; /* spacing between username and icon */
margin-bottom: 8px;
}
.username-icon {
width: 20px;
height: 20px;
object-fit: contain; /* keeps icon proportion */
}
/* Yellow Theme */
.theme-yellow {
--theme-primary: #ffd700;
--theme-secondary: #ffeb3b;
--theme-bg-primary: #1a1a0a;
--theme-bg-secondary: #2e2e1a;
--theme-bg-tertiary: #3e3e16;
--theme-text-primary: #f0f0f0;
}
/* Added green theme */
.theme-green {
--theme-primary: #4caf50;
--theme-secondary: #81c784;
--theme-bg-primary: #0a1a0a;
--theme-bg-secondary: #1a2e1a;
--theme-bg-tertiary: #163e16;
--theme-text-primary: #e8f5e8;
}
.theme-pink {
--theme-primary: #ff66b2;
--theme-secondary: #ff99cc;
--theme-bg-primary: #1a0a12;
--theme-bg-secondary: #2e1a24;
--theme-bg-tertiary: #3e1630;
--theme-text-primary: #ffe6f0;
}
/* Purple Theme */
.theme-purple {
--theme-primary: #9b59b6;
--theme-secondary: #b57edc;
--theme-bg-primary: #140a1a;
--theme-bg-secondary: #23142e;
--theme-bg-tertiary: #31163e;
--theme-text-primary: #e6d9f0;
--theme-nft-bg-image: url('');
}
/* Brown Theme */
.theme-brown {
--theme-primary: #a0522d; /* sienna */
--theme-secondary: #cd853f; /* peru */
--theme-bg-primary: #1a120a;
--theme-bg-secondary: #2e1f14;
--theme-bg-tertiary: #3e2a1a;
--theme-text-primary: #f5e6d3; /* light beige */
}
/* White Theme */
.theme-white {
--theme-primary: #cccccc;
--theme-secondary: #e0e0e0;
--theme-bg-primary: #1f1f1f;
--theme-bg-secondary: #2a2a2a;
--theme-bg-tertiary: #333333;
--theme-text-primary: #f0f0f0;
--theme-text-secondary: #b0b0b0;
--theme-bg-image: url('');
}
/* Cyan Theme */
.theme-cyan {
--theme-primary: #00bcd4; /* bright cyan */
--theme-secondary: #33e0f0; /* lighter cyan */
--theme-bg-primary: #0a1a1f; /* dark cyanish background */
--theme-bg-secondary: #0f2a33;
--theme-bg-tertiary: #162a3e;
--theme-text-primary: #e0f7fa; /* light cyan text */
--theme-text-secondary: #a0e0e5;
--theme-bg-image: url(''); /* optional background image */
}
/* Teal Theme */
.theme-teal {
--theme-primary: #008080; /* teal */
--theme-secondary: #20b2aa; /* lightseagreen */
--theme-bg-primary: #0a1a1a;
--theme-bg-secondary: #1a2e2e;
--theme-bg-tertiary: #163e3e;
--theme-text-primary: #e0f7f7;
}
/* Orange Theme */
.theme-orange {
--theme-primary: #ff7f50; /* coral */
--theme-secondary: #ffa07a; /* lightsalmon */
--theme-bg-primary: #1a0f0a;
--theme-bg-secondary: #2e1a14;
--theme-bg-tertiary: #3e2616;
--theme-text-primary: #fff2e6;
}
/* Splash Theme */
.theme-splash {
--theme-primary: #0d47a1; /* dark navy blue */
--theme-secondary: #1a237e; /* deeper blue */
--theme-bg-primary: #0d47a1; /* main dark blue background */
--theme-bg-secondary: #000000; /* subtle black touch */
--theme-bg-tertiary: #1b5e20; /* hint of dark green */
--theme-text-primary: #ffffff; /* white text */
--theme-text-secondary: #a5d6a7; /* light green accent */
--theme-bg-image: url(''); /* optional image */
}
.theme-coral {
--theme-primary: #ff7f50;
--theme-secondary: #ff9f7f;
--theme-bg-primary: #1a0a0a;
--theme-bg-secondary: #2e1a1a;
--theme-bg-tertiary: #3e1616;
--theme-text-primary: #fff0e6;
}
.theme-magenta {
--theme-primary: #ff00ff;
--theme-secondary: #ff66ff;
--theme-bg-primary: #1a001a;
--theme-bg-secondary: #2e002e;
--theme-bg-tertiary: #3e003e;
--theme-text-primary: #ffe6ff;
}
.theme-gold {
--theme-primary: #ffd700;
--theme-secondary: #ffdf40;
--theme-bg-primary: #1a1500;
--theme-bg-secondary: #2e2700;
--theme-bg-tertiary: #3e3600;
--theme-text-primary: #fff9e6;
}
/* Violet Theme */
.theme-violet {
--theme-primary: #8a2be2; /* blue violet */
--theme-secondary: #b266ff; /* lighter violet */
--theme-bg-primary: #1a0a1f;
--theme-bg-secondary: #2e1a3e;
--theme-bg-tertiary: #3e163e;
--theme-text-primary: #e6d9f0; /* light violet text */
}
/* Olive Theme */
.theme-olive {
--theme-primary: #808000; /* classic olive */
--theme-secondary: #a0a050; /* lighter olive */
--theme-bg-primary: #1a1a0a; /* dark oliveish background */
--theme-bg-secondary: #2e2e1a;
--theme-bg-tertiary: #3e3e16;
--theme-text-primary: #f5f5e0; /* off-white text */
--theme-text-secondary: #d0d0b0;
--theme-bg-image: url(''); /* optional background image */
}
/* Enhanced theme coverage - applying theme colors to all elements */
html, body {
background:
var(--theme-bg-image, none),
linear-gradient(
135deg,
var(--theme-bg-primary) 0%,
var(--theme-bg-secondary) 50%,
var(--theme-bg-tertiary) 100%
);
background-size: cover;
background-position: center;
background-attachment: fixed; /* keeps image in place */
color: var(--theme-text-primary);
}
.header {
background: linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-tertiary) 100%);
border-bottom: 2px solid var(--theme-primary);
box-shadow: 0 4px 20px rgba(0, 188, 212, 0.3);
}
/* Apply theme colors to all buttons, inputs, and interactive elements */
.search-btn, .theme-btn, .view-profile-btn, .show-all-btn {
background: linear-gradient(135deg, var(--theme-primary) 0%, var(--theme-secondary) 100%);
border: 1px solid var(--theme-primary);
color: var(--theme-bg-primary);
}
.search-btn:hover, .theme-btn:hover, .view-profile-btn:hover, .show-all-btn:hover {
background: var(--theme-secondary);
box-shadow: 0 4px 15px rgba(var(--theme-primary), 0.4);
}
.search-input {
background: var(--theme-bg-secondary);
border: 2px solid var(--theme-primary);
color: var(--theme-text-primary);
}
.search-input:focus {
border-color: var(--theme-secondary);
box-shadow: 0 0 10px rgba(var(--theme-primary), 0.3);
}
/* Apply theme to all cards and containers */
.user-card, .nft-card, .group-card, .stats-section {
background: linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-tertiary) 100%);
border: 1px solid var(--theme-primary);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
}
.stats-item {
background: var(--theme-bg-tertiary);
border: 1px solid var(--theme-primary);
}
.stats-item .label {
color: var(--theme-secondary);
}
.stats-item .value {
color: var(--theme-primary);
}
/* Enhanced floating widget with smaller collapsed state */
.floating-user-widget {
position: fixed;
bottom: 15px;
right: 15px;
width: 200px;
background: rgba(255, 255, 255, 0.06); /* even more transparent */
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 8px;
padding: 2px 6px; /* minimal padding */
font-size: 11px; /* smaller text */
line-height: 1; /* very tight line spacing */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
z-index: 1000;
transition: all 0.3s ease;
backdrop-filter: blur(4px);
}
.floating-user-widget.collapsed {
height: 20px; /* smaller */
width: 70px; /* smaller */
padding: 2px 4px;
font-size: 10px; /* tiny text */
overflow: hidden;
opacity: 0.8; /* slightly see-through when collapsed */
}
.widget-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
cursor: pointer;
}
.widget-title {
font-weight: bold;
color: var(--theme-primary);
font-size: 0.9rem;
}
.collapse-btn {
background: none;
border: none;
color: var(--theme-primary);
font-size: 1.2rem;
cursor: pointer;
transition: transform 0.3s ease;
}
.collapse-btn.collapsed {
transform: rotate(180deg);
}
.widget-content {
transition: opacity 0.3s ease;
}
.floating-user-widget.collapsed .widget-content {
opacity: 0;
height: 0;
overflow: hidden;
}
/* Enhanced widget styling with theme colors */
.widget-user-info {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
}
.widget-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
border: 2px solid var(--theme-primary);
}
.widget-user-details h4 {
color: var(--theme-text-primary);
margin: 0;
font-size: 0.9rem;
}
.widget-user-details p {
color: var(--theme-secondary);
margin: 0;
font-size: 0.8rem;
}
.widget-rank {
background: rgba(var(--theme-primary-rgb), 0.1);
border: 1px solid var(--theme-primary);
text-align: center;
padding: 8px;
border-radius: 6px;
border: 1px solid var(--theme-primary);
}
.rank-title {
font-size: 0.7rem;
color: var(--theme-secondary);
margin-bottom: 4px;
}
.rank-value {
font-weight: bold;
color: var(--theme-primary);
font-size: 0.9rem;
}
/* Enhanced loading animations with theme colors */
.loading-enhanced {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 15px;
padding: 40px 20px;
color: var(--theme-text-secondary);
}
.loading-pulse {
width: 60px;
height: 60px;
border: 3px solid var(--theme-primary);
border-radius: 50%;
position: relative;
animation: pulse 2s infinite;
}
.loading-pulse::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 30px;
height: 30px;
background: var(--theme-primary);
border-radius: 50%;
animation: innerPulse 2s infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.1); opacity: 0.7; }
}
@keyframes innerPulse {
0%, 100% { transform: translate(-50%, -50%) scale(1); }
50% { transform: translate(-50%, -50%) scale(0.8); }
}
.loading-text {
font-size: 1.1rem;
font-weight: bold;
text-align: center;
color: var(--theme-primary);
}
.loading-subtext {
font-size: 0.9rem;
opacity: 0.8;
text-align: center;
color: var(--theme-secondary);
}
/* Enhanced NFT and group card styles with theme colors */
.nft-card, .group-card {
position: relative;
overflow: hidden;
transition: all 0.3s ease;
}
.nft-card:hover, .group-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(var(--theme-primary), 0.3);
}
.nft-card::before, .group-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, var(--theme-primary), var(--theme-secondary));
}
/* Apply theme to all text elements */
h1, h2, h3, h4, h5, h6 {
color: var(--theme-primary);
}
p, span, div {
color: var(--theme-text-primary);
}
.error {
color: #ff6b6b;
background: rgba(255, 107, 107, 0.1);
border: 1px solid #ff6b6b;
padding: 10px;
border-radius: 6px;
}
/* Theme loading indicator */
.theme-loading {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--theme-bg-secondary);
border: 2px solid var(--theme-primary);
border-radius: 12px;
padding: 20px;
z-index: 9999;
display: none;
}
/* Added floating user widget styles */
.floating-user-widget {
position: fixed;
bottom: 20px;
right: 20px;
width: 300px;
background: linear-gradient(135deg, var(--theme-bg-secondary) 0%, var(--theme-bg-tertiary) 100%);
border: 2px solid var(--theme-primary);
border-radius: 12px;
padding: 15px;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4);
z-index: 1000;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
}
.floating-user-widget.collapsed {
height: 60px;
overflow: hidden;
}
.widget-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
cursor: pointer;
}
.widget-title {
font-weight: bold;
color: var(--theme-primary);
font-size: 0.9rem;
}
.collapse-btn {
background: none;
border: none;
color: var(--theme-primary);
font-size: 1.2rem;
cursor: pointer;
transition: transform 0.3s ease;
}
.collapse-btn.collapsed {
transform: rotate(180deg);
}
.widget-content {
transition: opacity 0.3s ease;
}
.floating-user-widget.collapsed .widget-content {
opacity: 0;
}
.widget-user-info {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
}
.widget-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
border: 2px solid var(--theme-primary);
}
.widget-user-details h4 {
margin: 0;
color: var(--theme-text-primary);
font-size: 0.9rem;
}
.widget-user-details p {
margin: 2px 0;
color: var(--theme-text-secondary);
font-size: 0.8rem;
}
.widget-rank {
background: rgba(0, 188, 212, 0.1);
border: 1px solid var(--theme-primary);
border-radius: 6px;
padding: 8px;
text-align: center;
margin-bottom: 10px;
}
.rank-title {
font-size: 0.8rem;
color: var(--theme-text-secondary);
margin-bottom: 4px;
}
.rank-value {
font-size: 1rem;
font-weight: bold;
color: var(--theme-primary);
}
/* Added theme selector styles to sidebar */
.theme-selector {
background: linear-gradient(135deg, var(--theme-bg-tertiary) 0%, var(--theme-bg-secondary) 100%);
border: 1px solid var(--theme-primary);
border-radius: 10px;
padding: 15px;
margin-bottom: 15px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
}
.theme-selector h3 {
font-size: 1rem;
color: var(--theme-primary);
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 6px;
}
.theme-buttons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
.theme-btn {
padding: 8px 12px;
border: 2px solid transparent;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
font-size: 0.8rem;
transition: all 0.3s ease;
text-align: center;
}
.theme-btn.current {
border-color: var(--theme-primary);
box-shadow: 0 0 10px rgba(0, 188, 212, 0.4);
}
.theme-btn:hover {
transform: translateY(-1px);
}
.theme-btn.default {
background: linear-gradient(45deg, #00bcd4, #87ceeb);
color: #0a0a0a;
}
.theme-btn.red {
background: linear-gradient(45deg, #ff4444, #ff6b6b);
color: white;
}
.theme-btn.black {
background: linear-gradient(45deg, #333, #666);
color: white;
}
.theme-btn.yellow {
background: linear-gradient(45deg, #ffd700, #ffeb3b);
color: #000;
}
/* Enhanced loading animations */
.loading-enhanced {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 15px;
padding: 40px 20px;
color: var(--theme-text-secondary);
}
/* Spinner Loader */
.loading-spinner {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 0;
}
.spinner {
width: 50px;
height: 50px;
border: 6px solid rgba(255, 255, 255, 0.2);
border-top-color: var(--theme-primary, #00bcd4);
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 15px;
}
.loading-text {
font-size: 1rem;
color: var(--theme-text-primary, #ffffff);
text-align: center;
font-weight: 600;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.loading-pulse {
width: 60px;
height: 60px;
border: 3px solid var(--theme-primary);
border-radius: 50%;
position: relative;
animation: pulse 2s infinite;
}
.loading-pulse::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 30px;
height: 30px;
background: var(--theme-primary);
border-radius: 50%;
animation: innerPulse 2s infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.1); opacity: 0.7; }
}
@keyframes innerPulse {
0%, 100% { transform: translate(-50%, -50%) scale(1); }
50% { transform: translate(-50%, -50%) scale(0.8); }
}
.loading-text {
font-size: 1.1rem;
font-weight: bold;
text-align: center;
}
.loading-subtext {
font-size: 0.9rem;
opacity: 0.8;
text-align: center;
}
/* Enhanced NFT card styles */
.nft-card {
position: relative;
overflow: hidden;
}
.nft-card::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg, transparent, var(--theme-primary), transparent);
border-radius: 12px;
z-index: -1;
opacity: 0;
transition: opacity 0.3s ease;
}
.nft-card:hover::before {
opacity: 0.3;
}
.nft-card.legendary::before {
background: linear-gradient(45deg, #ffd700, #ffeb3b, #ff6f00, #ffd700);
background-size: 400% 400%;
animation: legendaryGlow 2s ease-in-out infinite;
opacity: 0.6;
}
/* Mobile responsive updates for floating widget */
@media (max-width: 768px) {
.floating-user-widget {
width: calc(100vw - 40px);
right: 20px;
left: 20px;
bottom: 10px;
}
}
</style>
<div class="theme-loading" id="theme-loading">
<div class="loading-enhanced">
<div class="loading-pulse"></div>
<div class="loading-text">Loading Theme</div>
<div class="loading-subtext">Fetching your preferred style...</div>
</div>
</div>
</head>
<body>
<div class="header">
<div class="page-title">FINRAL - PROFILE</div>
<div class="creator">Owner : Saul | Reiker</div>
<div class="page-subtitle">"t.me/finralxbot"</div>
</div>
<button class="sidebar-toggle" id="sidebarToggle">🔍</button>
<div class="main-layout">
<div class="sidebar" id="sidebar">
<!-- Search section first -->
<div class="search-section">
<h3>🔍 Search User</h3>
<input type="text" id="searchInput" class="search-input" placeholder="Enter Chat/User ID">
<button id="searchBtn" class="search-btn">
<span class="btn-text">Search User</span>
<div class="loading-dots" style="display: none;">
<div class="loading-dot"></div>
<div class="loading-dot"></div>
<div class="loading-dot"></div>
</div>
</button>
<div id="searchResult" class="search-result" style="display:none;"></div>
</div>
<!-- Theme selector below search -->
<div class="theme-selector">
<h3>🎨 Theme</h3>
<div class="theme-buttons">
<button class="theme-btn default current" onclick="changeTheme('default')">Default</button>
<button class="theme-btn red" onclick="changeTheme('red')">Red</button>
<button class="theme-btn black" onclick="changeTheme('black')">Black</button>
<button class="theme-btn yellow" onclick="changeTheme('yellow')">Yellow</button>
<button class="theme-btn green" onclick="changeTheme('green')">Green</button>
<button class="theme-btn pink" onclick="changeTheme('pink')">Pink</button>
<button class="theme-btn purple" onclick="changeTheme('purple')">Purple</button>
<button class="theme-btn brown" onclick="changeTheme('brown')">Brown</button>
<button class="theme-btn cyan" onclick="changeTheme('cyan')">Cyan</button>
<button class="theme-btn coral" onclick="changeTheme('coral')">Coral</button>
<button class="theme-btn magenta" onclick="changeTheme('magenta')">Magenta</button>
<button class="theme-btn violet" onclick="changeTheme('violet')">Violet</button>
<button class="theme-btn teal" onclick="changeTheme('teal')">Teal</button>
<button class="theme-btn orange" onclick="changeTheme('orange')">Orange</button>
<button class="theme-btn olive" onclick="changeTheme('olive')">Olive</button>
<button class="theme-btn white" onclick="changeTheme('white')">White</button>
<button class="theme-btn splash" onclick="changeTheme('splash')">Splash</button>
<button class="theme-btn gold" onclick="changeTheme('gold')">Gold</button>
</div>
</div>
</div>
<div class="content">
<div class="top-section">
<div class="banner-profile-container" id="bannerContainer" style="display:none;">
<img id="banner" src="/placeholder.svg" alt="User Banner">
<div class="banner-overlay"></div>
<div class="profile-glow"></div>
<img id="pfp" src="/placeholder.svg" alt="Profile Picture">
</div>
<div class="user-info-card">
<div class="welcome-title" id="welcomeTitle">Welcome to Finral</div>
<!-- Added user name display -->
<div id="userName" class="chat-id" style="display:none; margin-bottom: 8px; background: rgba(135, 206, 235, 0.1); border-color: rgba(135, 206, 235, 0.3);"></div>
<div id="chatId" class="chat-id">
<div class="loading">
<div class="loading-spinner"></div>
Loading...
</div>
</div>
</div>
</div>
<div class="stats-grid" id="statsGrid" style="display:none;">
<div class="stats-section">
<h3>🎀 Basic Stats</h3>
<div class="basic-stats-grid">
<div class="stat-item">
<strong>Level</strong>
<div class="stat-value" id="totalLevel">-</div>
</div>
<div class="stat-item">
<strong>Total XP</strong>
<div class="stat-value" id="totalXP">-</div>
</div>
<div class="stat-item">
<strong>Royalties</strong>
<div class="stat-value" id="totalRoyalties">-</div>
</div>
<div class="stat-item">
<strong>Daily Msgs</strong>
<div class="stat-value" id="totalDailyMessages">-</div>
</div>
<div class="stat-item">
<strong>Full Name</strong>
<div class="stat-value" id="fullName">-</div>
</div>
<div class="stat-item">
<strong>Username</strong>
<div class="stat-value" id="username">-</div>
</div>
<div class="stat-item">
<strong>Groups</strong>
<div class="stat-value" id="groupCount">-</div>
</div>
<div class="stat-item">
<strong>Status</strong>
<div class="stat-value">Active</div>
</div>
</div>
</div>
</div>
<!-- Enhanced loading for NFT section -->
<div class="nfts-section" id="nftsSection" style="display:none;">
<h3>🎨 NFT Collection</h3>
<div class="nft-stats" id="nftStats" style="display:none;">
<div>
<div class="nft-stat">
<span class="nft-stat-value" id="totalNfts">0</span>
<span class="nft-stat-label">Total NFTs</span>
</div>
<div class="nft-stat">
<span class="nft-stat-value" id="avgQuality">0</span>
<span class="nft-stat-label">Avg Quality</span>
</div>
</div>
<div>
<div class="nft-stat">
<span class="nft-stat-value" id="rarestHolders">0</span>
<span class="nft-stat-label">Rarest (Holders)</span>
</div>
<div class="nft-stat">
<span class="nft-stat-value" id="highestQuality">0</span>
<span class="nft-stat-label">Highest Quality</span>
</div>
</div>
</div>
<!-- Spinner Loader -->
<div id="nftsContainer">
<div class="loading-spinner">
<div class="spinner"></div>
<div class="loading-text">Loading NFT Collection</div>
</div>
</div>
<button id="showAllNftsBtn" class="show-all-btn" style="display:none;">
Show All NFTs (<span id="remainingCount">0</span> more)
</button>
</div>
<!-- Enhanced loading for groups section -->
<div class="stats-section" id="groupsSection" style="display:none;">
<h3>👥 Group Memberships</h3>
<div class="groups-container" id="groupsContainer">
<div class="loading-enhanced">
<div class="loading-pulse"></div>
<div class="loading-text">Loading Group Data</div>
<div class="loading-subtext">Gathering your community connections...</div>
</div>
</div>
</div>
</div>
</div>
<!-- Added floating user widget -->
<div class="floating-user-widget" id="floatingWidget" style="display:none;">
<div class="widget-header" onclick="toggleWidget()">
<div class="widget-title">User Info</div>
<button class="collapse-btn" id="collapseBtn"></button>
</div>
<div class="widget-content">
<div class="widget-user-info">
<img id="widgetAvatar" class="widget-avatar" src="/placeholder.svg" alt="Avatar">
<div class="widget-user-details">
<h4 id="widgetName">Loading...</h4>
<p id="widgetId">ID: Loading...</p>
</div>
</div>
<div class="widget-rank">
<div class="rank-title">Global Rank</div>
<div class="rank-value" id="widgetRank">🥉 Bronze</div>
</div>
</div>
</div>
<script src="utils/xp-calculations.js"></script>
<script>
async function loadUserTheme() {
const themeLoadingIndicator = document.getElementById('theme-loading');
if (themeLoadingIndicator) {
themeLoadingIndicator.style.display = 'block';
}
try {
// ✅ Figure out userId dynamically
let userId;
const initData = Telegram.WebApp.initDataUnsafe;
const startParam = initData.start_param;
if (startParam) {
userId = startParam; // viewing someone else
} else if (initData.user && initData.user.id) {
userId = initData.user.id; // current user
} else {
console.error("❌ Unable to fetch userId");
return;
}
// ✅ Use the dynamic userId in API call
const response = await fetch(`https://reaperxxxx-testldb.hf.space/user/${userId}/theme`);
const data = await response.json();
if (data.status && data.theme) {
console.log('[v0] Theme loaded from API:', data.theme);
changeTheme(data.theme);
return;
}
} catch (error) {
console.log('[v0] API theme fetch failed, using default:', error);
changeTheme('default');
} finally {
if (themeLoadingIndicator) {
themeLoadingIndicator.remove();
}
}
}
// ✅ Run after DOM is ready
window.addEventListener('DOMContentLoaded', loadUserTheme);
</script>
<script>
// Sidebar toggle functionality
const sidebarToggle = document.getElementById('sidebarToggle');
const sidebar = document.getElementById('sidebar');
sidebarToggle.addEventListener('click', () => {
sidebar.classList.toggle('open');
sidebarToggle.textContent = sidebar.classList.contains('open') ? '✕' : '🔍';
});
// Close sidebar when clicking outside on mobile
document.addEventListener('click', (e) => {
if (window.innerWidth <= 768 &&
!sidebar.contains(e.target) &&
!sidebarToggle.contains(e.target) &&
sidebar.classList.contains('open')) {
sidebar.classList.remove('open');
sidebarToggle.textContent = '🔍';
}
});
// Function to search user by chat ID
async function searchUser(chatId) {
const searchBtn = document.getElementById('searchBtn');
const searchResult = document.getElementById('searchResult');
const btnText = searchBtn.querySelector('.btn-text');
const loadingDots = searchBtn.querySelector('.loading-dots');
searchBtn.disabled = true;
btnText.style.display = 'none';
loadingDots.style.display = 'flex';
searchResult.style.display = 'none';
try {
const response = await fetch(`https://reaperxxxx-testldb.hf.space/user/${chatId}/info`);
const data = await response.json();
if (data.status && data.groups && data.groups.length > 0) {
const userInfo = data.groups[0];
searchResult.innerHTML = `
<p><strong>✅ Found User:</strong></p>
<p><strong>Name:</strong> ${userInfo.fullName || 'N/A'}</p>
<p><strong>Username:</strong> ${userInfo.username || 'N/A'}</p>
<p><strong>ID:</strong> ${chatId}</p>
<button class="view-profile-btn" onclick="window.open('https://t.me/finralxbot/info?startapp=${chatId}', '_blank')">
View Full Profile
</button>
`;
searchResult.style.display = 'block';
} else {
searchResult.innerHTML = '<p class="error">❌ User not found or no data available.</p>';
searchResult.style.display = 'block';
}
} catch (error) {
searchResult.innerHTML = '<p class="error">⚠️ Error searching for user. Please try again.</p>';
searchResult.style.display = 'block';
}
searchBtn.disabled = false;
btnText.style.display = 'block';
loadingDots.style.display = 'none';
}
function changeTheme(theme) {
const body = document.body;
body.className = body.className.replace(/theme-\w+/g, '');
if (theme !== 'default') {
body.classList.add(`theme-${theme}`);
}
// Update active theme button
document.querySelectorAll('.theme-btn').forEach(btn => {
btn.classList.remove('current');
});
document.querySelector(`.theme-btn.${theme}`).classList.add('current');
// Save theme preference
localStorage.setItem('selectedTheme', theme);
}
function toggleWidget() {
const widget = document.getElementById('floatingWidget');
const btn = document.getElementById('collapseBtn');
widget.classList.toggle('collapsed');
btn.classList.toggle('collapsed');
btn.textContent = widget.classList.contains('collapsed') ? '▲' : '▼';
}
function updateGlobalRank(totalLevel) {
const rank = getGlobalRank(totalLevel);
const widgetRank = document.getElementById('widgetRank');
if (widgetRank) {
widgetRank.textContent = `${rank.emoji} ${rank.rank}`;
}
}
window.addEventListener('DOMContentLoaded', async () => {
const savedTheme = localStorage.getItem('xselectedTheme') || 'default';
changeTheme(savedTheme);
// Set up search functionality
const searchBtn = document.getElementById('searchBtn');
const searchInput = document.getElementById('searchInput');
searchBtn.addEventListener('click', () => {
const chatId = searchInput.value.trim();
if (chatId) {
searchUser(chatId);
}
});
searchInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
const chatId = searchInput.value.trim();
if (chatId) {
searchUser(chatId);
}
}
});
// Get userId from Telegram WebApp start parameter or current user
let userId;
let isViewingOther = false;
const initData = Telegram.WebApp.initDataUnsafe;
const startParam = initData.start_param;
if (startParam) {
userId = startParam;
isViewingOther = true;
document.getElementById('welcomeTitle').textContent = `Viewing Profile`;
} else {
const user = initData.user;
if (user && user.id) {
userId = user.id;
document.getElementById('welcomeTitle').textContent = `Welcome to Finral`;
} else {
document.getElementById('chatId').innerHTML = '<div class="error">❌ Unable to fetch chat ID</div>';
return;
}
}
document.getElementById('chatId').textContent = userId;
try {
// Fetch user banner with fallback
try {
const bannerRes = await fetch(`https://reaperxxxx-testldb.hf.space/user/${userId}/banner`);
const bannerData = await bannerRes.json();
const bannerEl = document.getElementById('banner');
if (bannerData.status && bannerData.catboxUrl) {
bannerEl.src = bannerData.catboxUrl;
} else {
bannerEl.src = 'https://files.catbox.moe/pdt55w.jpg';
}
document.getElementById('bannerContainer').style.display = 'block';
} catch (err) {
const bannerEl = document.getElementById('banner');
bannerEl.src = 'https://files.catbox.moe/pdt55w.jpg';
document.getElementById('bannerContainer').style.display = 'block';
}
// Fetch user PFP
const pfpRes = await fetch(`https://reaperxxxx-testldb.hf.space/user/${userId}/pfp`);
const pfpData = await pfpRes.json();
const imgEl = document.getElementById('pfp');
if (pfpData.status && pfpData.catboxUrl) {
imgEl.src = pfpData.catboxUrl;
} else {
imgEl.src = 'https://uploadnx.zone.id/w63l4b.jpeg';
}
// Fetch user info
const infoRes = await fetch(`https://reaperxxxx-testldb.hf.space/user/${userId}/info`);
const infoData = await infoRes.json();
if (infoData.status) {
const userInfo = infoData.groups[0] || {};
const fullName = userInfo.fullName || 'N/A';
const username = userInfo.username || 'N/A';
const iconURL = (await (async () => { try { const res = await fetch(`https://reaperxxxx-testldb.hf.space/user/${userId}/mark`); const data = await res.json(); return data.status && data.url ? data.url : 'https://files.catbox.moe/t8x1r8.png'; } catch { return 'https://files.catbox.moe/t8x1r8.png'; } })());
// iconURL is already set above
if (fullName !== 'N/A') {
const userNameEl = document.getElementById('userName');
userNameEl.innerHTML = ''; // clear previous content
// Create username text first
const nameText = document.createElement('span');
nameText.textContent = fullName;
// Create image element
const img = document.createElement('img');
img.src = iconURL;
img.alt = 'icon';
img.className = 'username-icon';
img.style.width = '20px';
img.style.height = '20px';
img.style.objectFit = 'contain';
// Append username first, then image (so image is on the right)
userNameEl.appendChild(nameText);
userNameEl.appendChild(img);
// Flex container to center content
userNameEl.style.display = 'inline-flex';
userNameEl.style.alignItems = 'center';
userNameEl.style.justifyContent = 'center'; // center horizontally
userNameEl.style.gap = '6px';
}
// Update floating widget
document.getElementById('widgetName').textContent = fullName;
document.getElementById('widgetId').textContent = `ID: ${userId}`;
document.getElementById('widgetAvatar').src = document.getElementById('pfp').src;
updateGlobalRank(infoData.totalLevel);
document.getElementById('floatingWidget').style.display = 'block';
// Display basic stats
document.getElementById('fullName').textContent = fullName;
document.getElementById('username').textContent = username;
document.getElementById('totalXP').textContent = infoData.totalXP.toLocaleString();
document.getElementById('totalLevel').textContent = infoData.totalLevel;
document.getElementById('totalRoyalties').textContent = infoData.totalRoyalties.toLocaleString();
document.getElementById('totalDailyMessages').textContent = infoData.totalDailyMessages;
document.getElementById('groupCount').textContent = infoData.groups.length;
// Show stats grid
document.getElementById('statsGrid').style.display = 'grid';
// Group unique groups by groupId
const uniqueGroups = {};
for (const group of infoData.groups) {
const groupId = group.groupId || group.id;
if (!uniqueGroups[groupId]) {
uniqueGroups[groupId] = {
groupId: groupId,
fullName: group.fullName,
username: group.username,
totalLevel: 0,
totalXP: 0,
totalRoyalties: 0,
totalDailyMessages: 0,
entries: []
};
}
uniqueGroups[groupId].totalLevel += group.level || 0;
uniqueGroups[groupId].totalXP += group.xp || 0;
uniqueGroups[groupId].totalRoyalties += group.royalties || 0;
uniqueGroups[groupId].totalDailyMessages += group.dailyMessages || 0;
uniqueGroups[groupId].entries.push({
level: group.level,
xp: group.xp,
royalties: group.royalties,
dailyMessages: group.dailyMessages
});
}
document.getElementById('groupsContainer').innerHTML = '';
// Display group stats
const groupsContainer = document.getElementById('groupsContainer');
for (const groupId in uniqueGroups) {
const group = uniqueGroups[groupId];
let groupMeta = null;
let metaError = null;
try {
const groupMetaRes = await fetch(`https://reaperxxxx-testldb.hf.space/group/${groupId}/meta`);
if (groupMetaRes.ok) {
groupMeta = await groupMetaRes.json();
} else {
const errorText = await groupMetaRes.text();
metaError = `API Error: ${groupMetaRes.status}`;
}
} catch (err) {
metaError = `Fetch Error: ${err.message}`;
}
const div = document.createElement('div');
div.className = 'group-box';
const displayName = (groupMeta && groupMeta.status && groupMeta.groupName)
? groupMeta.groupName
: group.fullName || 'Unknown Group';
const groupPic = (groupMeta && groupMeta.status && groupMeta.groupPic)
? groupMeta.groupPic
: null;
const admins = (groupMeta && groupMeta.status && groupMeta.admins)
? groupMeta.admins
: null;
div.innerHTML = `
<div class="group-header">
${groupPic ? `<img class="group-pic" src="${groupPic}" alt="Group Picture">` : `<div class="group-pic" style="background: linear-gradient(45deg, var(--theme-primary), var(--theme-secondary)); display: flex; align-items: center; justify-content: center; color: #0a0a0a; font-weight: bold;">👥</div>`}
<div class="group-info">
<div class="group-name">${displayName}</div>
<div class="group-id">ID: ${groupId}</div>
</div>
</div>
<div class="group-stats">
<div class="group-stat-item">
<span class="group-stat-value">${group.totalLevel}</span>
<span class="group-stat-label">Level</span>
</div>
<div class="group-stat-item">
<span class="group-stat-value">${group.totalXP.toLocaleString()}</span>
<span class="group-stat-label">XP</span>
</div>
<div class="group-stat-item">
<span class="group-stat-value">${group.totalRoyalties.toLocaleString()}</span>
<span class="group-stat-label">Royalties</span>
</div>
<div class="group-stat-item">
<span class="group-stat-value">${group.totalDailyMessages}</span>
<span class="group-stat-label">Daily</span>
</div>
</div>
${metaError ? `<div class="error">⚠️ ${metaError}</div>` : ''}
${admins && admins.length > 0 ? `
<div class="group-admins">
<details>
<summary>👑 Admins (${admins.length})</summary>
<div class="admin-list">
${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('')}
${admins.length > 5 ? `<span class="admin-tag">+${admins.length - 5} more</span>` : ''}
</div>
</details>
</div>` : ''}
`;
groupsContainer.appendChild(div);
}
document.getElementById('groupsSection').style.display = 'block';
}
const nftsContainer = document.getElementById('nftsContainer');
const showAllBtn = document.getElementById('showAllNftsBtn');
const remainingCount = document.getElementById('remainingCount');
const nftStats = document.getElementById('nftStats');
// Show loading spinner while fetching
nftsContainer.innerHTML = `
<div class="nft-loader" id="nftLoading">
<div class="spinner"></div>
</div>
`;
try {
const nftsRes = await fetch(`https://reaperxxxx-testldb.hf.space/user/${userId}/nfts`);
const nftsData = await nftsRes.json();
// Hide loading spinner
const nftLoading = document.getElementById('nftLoading');
if (nftLoading) nftLoading.style.display = 'none';
if (nftsData.status && nftsData.nfts && nftsData.nfts.length > 0) {
// Sort NFTs by holders (ascending)
const sortedNfts = nftsData.nfts.sort((a, b) => a.holders - b.holders);
// NFT stats
const totalNfts = sortedNfts.length;
const avgQuality = Math.round(sortedNfts.reduce((sum, nft) => sum + nft.nftquality, 0) / totalNfts);
const rarestHolders = Math.min(...sortedNfts.map(nft => nft.holders));
const highestQuality = Math.max(...sortedNfts.map(nft => nft.nftquality));
document.getElementById('totalNfts').textContent = totalNfts;
document.getElementById('avgQuality').textContent = avgQuality;
document.getElementById('rarestHolders').textContent = rarestHolders;
document.getElementById('highestQuality').textContent = highestQuality;
nftStats.style.display = 'block';
function getQualityClass(quality) {
if (quality >= 81) return 'legendary';
if (quality >= 61) return 'way-better';
if (quality >= 41) return 'even-better';
if (quality >= 21) return 'better';
return 'basic';
}
function getQualityBadgeClass(quality) {
if (quality >= 81) return 'quality-legendary';
if (quality >= 61) return 'quality-way-better';
if (quality >= 41) return 'quality-even-better';
if (quality >= 21) return 'quality-better';
return 'quality-basic';
}
function getRarityClass(rarity) {
const rarityLower = rarity.toLowerCase();
if (rarityLower.includes('mythic')) return 'rarity-mythic';
if (rarityLower.includes('legendary')) return 'rarity-legendary';
if (rarityLower.includes('epic')) return 'rarity-epic';
if (rarityLower.includes('rare')) return 'rarity-rare';
if (rarityLower.includes('uncommon')) return 'rarity-uncommon';
return 'rarity-common';
}
function formatDateTime(dateString) {
const date = new Date(dateString);
return date.toLocaleString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
function createNftCard(nft) {
const qualityClass = getQualityClass(nft.nftquality);
const qualityBadgeClass = getQualityBadgeClass(nft.nftquality);
const rarityClass = getRarityClass(nft.rarity);
const uniqueId = `details-${nft.nftid}`;
return `
<div class="nft-card ${qualityClass}" style="animation: fadeInUp 0.6s ease forwards; opacity: 0;">
<div class="quality-badge ${qualityBadgeClass}">${nft.nftquality}</div>
<img src="${nft.nftimage}" alt="${nft.name}" class="nft-image" loading="lazy">
<div class="nft-info">
<div class="nft-header">
<div class="nft-name" title="${nft.name}">${nft.name}</div>
<div class="nft-id">#${nft.nftid}</div>
</div>
<div class="nft-rarity ${rarityClass}">${nft.rarity}</div>
<button class="toggle-details" onclick="toggleDetails('${uniqueId}', this)">▼ Show Details</button>
<div class="nft-details-wrapper" id="${uniqueId}" style="display: none;">
<div class="nft-details">
<div class="nft-detail">
<span class="nft-detail-label">Quality</span>
<span class="nft-detail-value">${nft.nftquality}/100</span>
</div>
<div class="nft-detail">
<span class="nft-detail-label">Holders</span>
<span class="nft-detail-value">${nft.holders}</span>
</div>
</div>
<div class="nft-obtained">
<span class="nft-obtained-label">Obtained On</span>
<span class="nft-obtained-value">${formatDateTime(nft.gotten_on)}</span>
</div>
</div>
</div>
</div>
`;
}
// Show first 5 NFTs initially
const initialNfts = sortedNfts.slice(0, 5);
const remainingNfts = sortedNfts.slice(5);
nftsContainer.innerHTML = `
<div class="nfts-grid">
${initialNfts.map(nft => createNftCard(nft)).join('')}
</div>
`;
if (remainingNfts.length > 0) {
remainingCount.textContent = remainingNfts.length;
showAllBtn.style.display = 'block';
let allShown = false;
showAllBtn.addEventListener('click', () => {
const nftsGrid = nftsContainer.querySelector('.nfts-grid');
if (!allShown) {
nftsGrid.innerHTML += remainingNfts.map(nft => createNftCard(nft)).join('');
showAllBtn.textContent = 'Show Less';
allShown = true;
} else {
nftsGrid.innerHTML = initialNfts.map(nft => createNftCard(nft)).join('');
showAllBtn.innerHTML = `Show All NFTs (<span id="remainingCount">${remainingNfts.length}</span> more)`;
allShown = false;
}
});
}
setTimeout(() => {
const nftCards = document.querySelectorAll('.nft-card');
nftCards.forEach((card, index) => {
setTimeout(() => { card.style.opacity = '1'; }, index * 100);
});
}, 100);
document.getElementById('nftsSection').style.display = 'block';
} else {
// No NFTs found
nftsContainer.innerHTML = `
<div class="no-nfts">
<div class="no-nfts-icon">🎨</div>
<h4>No NFTs Found</h4>
<p>This user hasn't collected any NFTs yet.</p>
<p>Start your digital art journey today!</p>
</div>
`;
document.getElementById('nftsSection').style.display = 'block';
}
} catch (err) {
console.error('Error fetching NFTs:', err);
nftsContainer.innerHTML = `
<div class="no-nfts">
<div class="no-nfts-icon">⚠️</div>
<h4>Failed to Load NFTs</h4>
<p>Unable to fetch NFT collection data.</p>
<p>Please try again later.</p>
</div>
`;
document.getElementById('nftsSection').style.display = 'block';
}
} catch (err) {
console.error('Error fetching user data:', err);
document.getElementById('chatId').innerHTML = '<div class="error">❌ Failed to load user info</div>';
}
});
function toggleDetails(id, button) {
const details = document.getElementById(id);
const isVisible = details.style.display === 'block';
details.style.display = isVisible ? 'none' : 'block';
button.textContent = isVisible ? '▼ Show Details' : '▲ Hide Details';
}
</script>
<!-- Added fadeInUp animation -->
<style>
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
</body>
</html>