feat: Add crowdfunding and sponsor management features

- Introduced fund_progress.txt to track server upgrade funding and vehicle replacement costs.
- Created sponsors.txt to log sponsorship contributions with details including name, project, amount, and date.
- Developed components.js for reusable UI components including navbar and footer.
- Implemented data_utils.js for parsing sponsor data and calculating totals.
- Added script.js for managing server status, crowdfunding display, and sponsor data fetching.
- Created sponsor_script.js for detailed sponsor data management, filtering, and UI interactions.
- Developed stats_script.js for player statistics display, including leaderboards and detailed player stats in a modal.
This commit is contained in:
zhangyuheng
2026-03-02 11:29:02 +08:00
parent d475d329e9
commit 47ef36f600
16 changed files with 1239 additions and 1020 deletions

599
css/pages/sponsor.css Normal file
View File

@@ -0,0 +1,599 @@
.sponsor-hero {
padding: 140px 20px 50px;
text-align: center;
background: radial-gradient(circle at center, rgba(0,113,227,0.08) 0%, rgba(255,255,255,0) 70%);
position: relative;
overflow: hidden;
}
.sponsor-hero h1 {
font-size: 56px;
font-weight: 800;
margin-bottom: 24px;
background: linear-gradient(135deg, #1d1d1f 0%, #434344 100%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
letter-spacing: -0.02em;
}
.hero-subtitle {
font-size: 18px;
color: var(--text-secondary);
margin-top: 16px;
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.total-donations {
display: inline-flex;
flex-direction: column;
align-items: center;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(20px);
padding: 20px 40px;
border-radius: var(--radius-large);
box-shadow: 0 10px 40px rgba(0,0,0,0.06);
border: 1px solid rgba(255,255,255,0.6);
transform: translateY(0);
transition: transform 0.3s ease;
}
.total-donations:hover {
transform: translateY(-5px);
}
.counter-label {
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-secondary);
margin-bottom: 8px;
font-weight: 600;
}
.counter-value {
font-size: 42px;
font-weight: 800;
color: var(--brand-green);
font-feature-settings: "tnum";
font-variant-numeric: tabular-nums;
}
.sponsor-container {
max-width: 1100px;
margin: 0 auto;
padding: 40px 20px;
}
.section-title {
font-size: 28px;
font-weight: 700;
margin-bottom: 30px;
text-align: center;
}
.sponsor-list-title {
margin-bottom: 10px;
}
/* Top Donors Podium */
.top-donors-section {
margin-bottom: 60px;
}
.podium-container {
display: flex;
justify-content: center;
align-items: flex-end;
gap: 20px;
padding: 40px 0;
min-height: 300px;
}
.podium-spot {
background: white;
border-radius: var(--radius-medium);
padding: 20px;
width: 220px;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 4px 20px rgba(0,0,0,0.06);
position: relative;
transition: transform 0.3s ease;
text-align: center;
}
.podium-spot:hover {
transform: translateY(-10px);
z-index: 2;
}
.podium-rank {
width: 40px;
height: 40px;
background: #f0f0f0;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 800;
margin-bottom: 12px;
position: absolute;
top: -20px;
border: 4px solid var(--bg-color);
}
/* Gold */
.podium-spot.rank-1 {
height: 260px;
border: 2px solid rgba(255, 215, 0, 0.3);
background: linear-gradient(180deg, rgba(255,215,0,0.05) 0%, rgba(255,255,255,1) 100%);
order: 2;
}
.podium-spot.rank-1 .podium-rank {
background: #FFD700;
color: #fff;
box-shadow: 0 4px 10px rgba(255, 215, 0, 0.4);
}
.podium-spot.rank-1 .donor-avatar {
border-color: #FFD700;
width: 80px;
height: 80px;
}
/* Silver */
.podium-spot.rank-2 {
height: 220px;
border: 2px solid rgba(192, 192, 192, 0.3);
order: 1;
}
.podium-spot.rank-2 .podium-rank {
background: #C0C0C0;
color: #fff;
}
/* Bronze */
.podium-spot.rank-3 {
height: 200px;
border: 2px solid rgba(205, 127, 50, 0.3);
order: 3;
}
.podium-spot.rank-3 .podium-rank {
background: #CD7F32;
color: #fff;
}
.donor-avatar {
width: 64px;
height: 64px;
border-radius: 50%;
border: 3px solid transparent;
margin-bottom: 12px;
background-color: #f0f0f0;
object-fit: cover;
}
.podium-name {
font-weight: 700;
font-size: 18px;
margin-bottom: 4px;
word-break: break-all;
}
.podium-total {
color: var(--brand-green);
font-weight: 600;
font-size: 16px;
}
/* Controls */
.controls-section {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
margin-bottom: 40px;
max-width: 800px;
margin-left: auto;
margin-right: auto;
}
.controls-header {
display: flex;
width: 100%;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 24px;
}
/* Mobile adjustment for header */
@media (max-width: 600px) {
.controls-header {
flex-direction: column;
}
}
.cta-button {
height: 48px;
padding: 0 24px;
background-color: var(--text-primary);
color: white;
border-radius: 99px;
text-decoration: none;
font-weight: 600;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 8px;
transition: all 0.2s;
cursor: pointer;
border: 1px solid transparent;
white-space: nowrap;
box-sizing: border-box;
}
.cta-button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.cta-button.outline {
background-color: transparent;
color: var(--text-primary);
border: 1px solid rgba(0,0,0,0.1);
}
.cta-button.outline:hover {
border-color: var(--text-primary);
background-color: white;
}
/* Modal Styles */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
backdrop-filter: blur(5px);
opacity: 0;
transition: opacity 0.3s ease;
}
.modal.show {
display: flex;
opacity: 1;
align-items: center;
justify-content: center;
}
.modal-content {
background-color: white;
margin: auto;
padding: 40px;
border-radius: 24px;
width: 90%;
max-width: 400px;
position: relative;
box-shadow: 0 20px 60px rgba(0,0,0,0.2);
transform: scale(0.9);
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
text-align: center;
}
.modal.show .modal-content {
transform: scale(1);
}
.close-modal {
position: absolute;
top: 20px;
right: 20px;
color: #aaa;
font-size: 24px;
cursor: pointer;
width: 32px;
height: 32px;
background: #f5f5f7;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
}
.close-modal:hover {
color: #000;
background: #e5e5e7;
}
.modal-title {
font-size: 24px;
font-weight: 700;
margin-bottom: 8px;
}
.modal-gift-icon {
width: 50px;
height: 50px;
background: rgba(52, 199, 89, 0.1);
border-radius: 50%;
color: var(--brand-green);
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
margin: 0 auto 20px;
}
.modal-subtitle {
color: var(--text-secondary);
font-size: 14px;
margin-bottom: 30px;
line-height: 1.5;
}
.qr-placeholder {
background: #f9f9f9;
padding: 20px;
border-radius: 16px;
display: inline-block;
margin-bottom: 20px;
}
.qr-img {
width: 180px;
height: 180px;
display: block;
}
.desktop-qr-hint {
font-size: 13px;
color: #999;
}
.alipay-btn {
background: #1677FF;
color: white;
display: inline-block;
width: 100%;
padding: 14px;
border-radius: 12px;
font-weight: 600;
text-decoration: none;
margin-top: 10px;
}
#mobile-btn-view {
display: none;
}
.mobile-pay-hint {
font-size: 12px;
color: #999;
margin-top: 16px;
}
.search-box {
position: relative;
flex-grow: 0;
width: 100%;
max-width: 320px;
}
.search-box input {
width: 100%;
height: 48px;
padding: 0 20px 0 44px;
border-radius: 99px;
border: 1px solid rgba(0,0,0,0.1);
background: white;
font-size: 15px;
outline: none;
transition: all 0.2s;
}
.search-box input:focus {
border-color: var(--accent-color);
box-shadow: 0 0 0 3px rgba(0,113,227,0.1);
}
.search-box i {
position: absolute;
left: 16px;
top: 50%;
transform: translateY(-50%);
color: var(--text-secondary);
}
.filter-tags {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 10px;
}
.filter-tag {
padding: 8px 16px;
border-radius: 99px;
border: none;
background: white;
color: var(--text-secondary);
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
box-shadow: 0 2px 8px rgba(0,0,0,0.03);
}
.filter-tag:hover {
transform: translateY(-1px);
background: #fafafa;
}
.filter-tag.active {
background: var(--text-primary);
color: white;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.donation-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
}
.no-results-message {
text-align: center;
color: var(--text-secondary);
padding: 40px;
}
.sponsor-load-error {
text-align: center;
padding: 40px;
color: var(--text-secondary);
grid-column: 1 / -1;
}
.donation-card-body {
flex-grow: 1;
display: flex;
flex-direction: column;
}
.donation-date-icon {
margin-right: 4px;
}
.is-hidden {
display: none;
}
.donation-card {
background: white;
padding: 24px;
border-radius: var(--radius-medium);
transition: var(--transition);
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
overflow: hidden;
border: 1px solid rgba(0,0,0,0.03);
animation: fadeInUp 0.5s ease backwards;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.donation-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0,0,0,0.08);
border-color: transparent;
}
.donation-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 16px;
}
.donor-info {
display: flex;
align-items: center;
gap: 12px;
}
.mini-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: #f0f0f0;
}
.donor-name {
font-weight: 700;
font-size: 16px;
line-height: 1.2;
}
.donation-amount {
color: var(--brand-green);
font-weight: 800;
font-size: 18px;
background: rgba(52, 199, 89, 0.1);
padding: 4px 10px;
border-radius: 8px;
}
.donation-purpose {
font-size: 13px;
color: var(--text-primary);
background: var(--bg-color);
padding: 6px 12px;
border-radius: 6px;
display: inline-block;
margin-bottom: 12px;
align-self: flex-start;
}
.donation-date {
font-size: 12px;
color: #999;
text-align: right;
margin-top: auto;
border-top: 1px solid rgba(0,0,0,0.05);
padding-top: 12px;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.sponsor-hero h1 {
font-size: 32px;
}
.counter-value {
font-size: 32px;
}
.podium-container {
flex-direction: column;
align-items: center;
gap: 30px;
}
.podium-spot {
width: 100%;
max-width: 300px;
order: initial !important;
height: auto !important;
}
.podium-rank {
position: relative;
top: 0;
margin-top: -30px;
}
}

456
css/pages/stats.css Normal file
View File

@@ -0,0 +1,456 @@
/* Specific styles for stats page override/additions */
.stats-hero {
height: 40vh;
min-height: 300px;
}
.stats-hero-bg {
background-image: url('https://img.lunadeer.cn/i/2025/11/26/69267755e14e3.png');
}
.stats-main-section {
background: var(--bg-color);
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
margin-top: 30px;
}
.player-card {
background: var(--card-bg);
border-radius: var(--radius-medium);
padding: 20px;
text-align: center;
transition: var(--transition);
cursor: pointer;
box-shadow: 0 4px 6px rgba(0,0,0,0.02);
position: relative;
overflow: hidden;
}
.player-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.05);
}
.player-card img {
width: 80px;
height: 80px;
border-radius: 10px;
margin-bottom: 15px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.player-card h3 {
font-size: 16px;
margin-bottom: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.player-card .p-uuid {
font-size: 12px;
color: var(--text-secondary);
margin-bottom: 10px;
font-family: monospace;
}
/* Leaderboard Cards */
.leaderboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 60px;
}
.lb-card {
background: white;
border-radius: var(--radius-medium);
padding: 25px;
box-shadow: 0 4px 20px rgba(0,0,0,0.05);
position: relative;
overflow: hidden;
}
.lb-card.gold {
border-top: 4px solid #FFD700;
}
.lb-card.silver {
border-top: 4px solid #C0C0C0;
}
.lb-card.bronze {
border-top: 4px solid #CD7F32;
}
.lb-card.red {
border-top: 4px solid #ff3b30;
}
.lb-card.purple {
border-top: 4px solid #9b59b6;
}
.lb-card.kill-red {
border-top: 4px solid #e74c3c;
}
.lb-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 20px;
}
.lb-icon {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
background: var(--bg-color);
color: var(--text-primary);
font-size: 20px;
}
.lb-title {
font-weight: 600;
font-size: 18px;
}
.lb-top-player {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 1px solid #f0f0f0;
}
.lb-top-player img {
width: 64px;
height: 64px;
border-radius: 8px;
margin-bottom: 10px;
}
.lb-top-data {
font-size: 24px;
font-weight: 700;
color: var(--accent-color);
}
.lb-top-name {
font-weight: 700;
margin-bottom: 4px;
}
.lb-list {
list-style: none;
}
.lb-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
font-size: 14px;
border-bottom: 1px dashed #eee;
}
.lb-item-main {
display: flex;
align-items: center;
}
.lb-item-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100px;
}
.lb-item:last-child {
border-bottom: none;
}
.lb-rank {
width: 24px;
height: 24px;
background: #eee;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 700;
margin-right: 8px;
}
/* Search Box */
.search-container {
max-width: 600px;
margin: 0 auto 40px;
position: relative;
}
.search-input {
width: 100%;
padding: 15px 20px 15px 45px;
border: 1px solid rgba(0,0,0,0.1);
border-radius: 15px;
font-size: 16px;
outline: none;
transition: var(--transition);
background: white;
}
.search-input:focus {
border-color: var(--accent-color);
box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.1);
}
.search-icon {
position: absolute;
left: 15px;
top: 50%;
transform: translateY(-50%);
color: #ccc;
}
/* Stats Modal Override */
.stat-row {
display: flex;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.stat-label {
color: var(--text-secondary);
}
.stat-value {
font-weight: 600;
}
.loading-text {
text-align: center;
padding: 40px;
color: var(--text-secondary);
font-size: 18px;
}
.loading-details-text {
text-align: center;
padding: 20px;
color: #888;
}
.load-more-container {
text-align: center;
margin-top: 40px;
}
.load-more-btn {
background: white;
border: 1px solid #ddd;
padding: 12px 30px;
border-radius: 20px;
cursor: pointer;
font-weight: 600;
transition: var(--transition);
}
.load-more-btn:hover {
background: #f9f9f9;
transform: translateY(-2px);
}
/* Modal Redesign */
.modal-content.expanded-modal {
max-width: 800px;
width: 90%;
display: flex;
flex-direction: column;
max-height: 90vh;
overflow-y: auto;
}
/* Custom Scrollbar for Modal */
.modal-content.expanded-modal::-webkit-scrollbar {
width: 6px;
}
.modal-content.expanded-modal::-webkit-scrollbar-track {
background: transparent;
margin: 10px 0;
}
.modal-content.expanded-modal::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.15);
border-radius: 10px;
}
.modal-content.expanded-modal::-webkit-scrollbar-thumb:hover {
background: rgba(0, 0, 0, 0.25);
}
.modal-top-section {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-bottom: 20px;
}
.modal-identity {
flex: 1;
min-width: 200px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
}
.modal-identity img {
width: 100px;
height: 100px;
border-radius: 12px;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
margin-bottom: 15px;
}
#modal-name {
margin: 5px 0;
font-size: 24px;
}
#modal-uuid {
font-size: 12px;
color: #999;
font-family: monospace;
word-break: break-all;
}
.stats-list-container.compact-stats {
flex: 1;
min-width: 250px;
display: flex;
flex-direction: column;
justify-content: center;
background: #f9f9f9;
padding: 15px;
border-radius: 12px;
}
.modal-divider {
border: 0;
border-top: 1px solid #eee;
margin: 10px 0 20px;
}
/* Accordion Styles */
.accordion {
display: flex;
flex-direction: column;
gap: 10px;
}
.accordion-item {
border: 1px solid #eee;
border-radius: 8px;
overflow: hidden;
}
.accordion-header {
background: #fdfdfd;
padding: 12px 15px;
cursor: pointer;
font-weight: 600;
display: flex;
justify-content: space-between;
align-items: center;
transition: background 0.2s;
}
.accordion-header:hover {
background: #f0f0f0;
}
.accordion-header .icon {
margin-right: 8px;
width: 20px;
text-align: center;
color: var(--text-secondary);
}
.accordion-header .arrow {
transition: transform 0.3s;
}
.accordion-header.active .arrow {
transform: rotate(180deg);
}
.accordion-header.active {
background: #f0f0f0;
color: var(--accent-color);
}
.accordion-content {
display: none;
padding: 15px;
background: white;
border-top: 1px solid #eee;
}
.accordion-content.show {
display: block;
}
/* Grid for stats inside accordion */
.detail-stats-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 10px;
}
.detail-stat-item {
display: flex;
justify-content: space-between;
font-size: 13px;
padding: 4px 0;
border-bottom: 1px dashed #f5f5f5;
}
.detail-stat-label {
color: #666;
margin-right: 10px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.detail-stat-value {
font-weight: 600;
font-family: monospace;
}
/* Mobile Adjustments */
@media (max-width: 600px) {
.modal-top-section {
flex-direction: column;
}
.modal-identity,
.stats-list-container.compact-stats {
width: 100%;
}
}

View File

@@ -23,6 +23,17 @@ body {
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
} }
.skip-to-main {
position: absolute;
left: -9999px;
top: 0;
z-index: 999;
}
.home-hidden {
display: none;
}
/* Navbar */ /* Navbar */
.navbar { .navbar {
position: fixed; position: fixed;
@@ -114,6 +125,10 @@ body {
color: white; color: white;
} }
.home-hero {
background-image: url('https://img.lunadeer.cn/i/2025/11/26/69267755e14e3.png');
}
.hero-overlay { .hero-overlay {
position: absolute; position: absolute;
top: 0; top: 0;
@@ -287,6 +302,20 @@ body {
gap: 8px; gap: 8px;
} }
.player-item-center {
justify-content: center;
}
.player-item-muted {
justify-content: center;
color: #86868b;
}
.player-item-error {
justify-content: center;
color: #ff3b30;
}
.player-item:last-child { .player-item:last-child {
border-bottom: none; border-bottom: none;
} }
@@ -379,6 +408,42 @@ body {
grid-row: span 1; grid-row: span 1;
} }
.feature-pure {
background-image: url('https://img.lunadeer.cn/i/2024/02/21/65d592eb4afad.jpg');
}
.feature-dev {
background-image: url('https://img.lunadeer.cn/i/2025/11/26/6926982718ba8.png');
}
.feature-params {
background-image: url('https://img.lunadeer.cn/i/2025/11/26/6926775006dea.jpg');
}
.feature-land {
background-image: url('https://img.lunadeer.cn/i/2024/02/21/65d592ea6faa1.jpg');
}
.feature-bedrock {
background-image: url('https://img.lunadeer.cn/i/2025/11/26/692677560db46.png');
}
.feature-hardware {
background-image: url('https://img.lunadeer.cn/i/2024/02/21/65d592e248066.jpg');
}
.feature-fun {
background-image: url('https://img.lunadeer.cn/i/2025/11/26/692677566b07b.png');
}
.feature-update {
background-image: url('https://img.lunadeer.cn/i/2025/11/26/692697b71431b.png');
}
.feature-guide {
background-image: url('https://img.lunadeer.cn/i/2025/11/26/692697b7376c7.png');
}
/* Hardware Card (No Image) */ /* Hardware Card (No Image) */
.hardware-card { .hardware-card {
background: linear-gradient(135deg, #2c3e50 0%, #000000 100%); background: linear-gradient(135deg, #2c3e50 0%, #000000 100%);

View File

@@ -6,7 +6,7 @@
<title>文档 - 白鹿原 Minecraft 服务器</title> <title>文档 - 白鹿原 Minecraft 服务器</title>
<meta name="description" content="白鹿原服务器文档中心"> <meta name="description" content="白鹿原服务器文档中心">
<link rel="icon" href="favicon.ico" type="image/x-icon"> <link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="css/style.css">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&family=Inter:wght@400;600;800&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style> <style>
@@ -36,6 +36,6 @@
<div class="iframe-container"> <div class="iframe-container">
<iframe src="https://outline.lunadeer.cn/s/447e5db6-8af4-468e-b7c5-cdb7b48aa439" title="文档"></iframe> <iframe src="https://outline.lunadeer.cn/s/447e5db6-8af4-468e-b7c5-cdb7b48aa439" title="文档"></iframe>
</div> </div>
<script src="components.js"></script> <script src="js/components.js"></script>
</body> </body>
</html> </html>

View File

@@ -33,7 +33,7 @@
<meta property="twitter:image" content="https://img.lunadeer.cn/i/2024/04/22/6625ce6c8ddc1.png"> <meta property="twitter:image" content="https://img.lunadeer.cn/i/2024/04/22/6625ce6c8ddc1.png">
<link rel="icon" href="favicon.ico" type="image/x-icon"> <link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="css/style.css">
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preconnect" href="https://img.lunadeer.cn"> <link rel="preconnect" href="https://img.lunadeer.cn">
@@ -74,13 +74,13 @@
</head> </head>
<body> <body>
<!-- Skip to main content for accessibility --> <!-- Skip to main content for accessibility -->
<a href="#main-content" class="skip-to-main" style="position:absolute;left:-9999px;top:0;z-index:999;">跳转到主内容</a> <a href="#main-content" class="skip-to-main">跳转到主内容</a>
<!-- Navbar Component --> <!-- Navbar Component -->
<div id="navbar-component"></div> <div id="navbar-component"></div>
<!-- Hero Section --> <!-- Hero Section -->
<header id="main-content" class="hero" style="background-image: url('https://img.lunadeer.cn/i/2025/11/26/69267755e14e3.png');" role="banner"> <header id="main-content" class="hero home-hero" role="banner">
<div class="hero-overlay"></div> <div class="hero-overlay"></div>
<div class="hero-content"> <div class="hero-content">
<h1 class="hero-title">白鹿原 Minecraft</h1> <h1 class="hero-title">白鹿原 Minecraft</h1>
@@ -105,7 +105,7 @@
<span id="online-count">正在获取状态...</span> <span id="online-count">正在获取状态...</span>
</div> </div>
<div class="players-tooltip" id="players-list"> <div class="players-tooltip" id="players-list">
<div class="player-item" style="justify-content: center;">加载中...</div> <div class="player-item player-item-center">加载中...</div>
</div> </div>
</div> </div>
</div> </div>
@@ -119,7 +119,7 @@
<div class="bento-grid"> <div class="bento-grid">
<!-- Large Feature: Pure --> <!-- Large Feature: Pure -->
<div class="bento-item large-item feature-pure" style="background-image: url('https://img.lunadeer.cn/i/2024/02/21/65d592eb4afad.jpg');" role="article" aria-label="纯净原版特性"> <div class="bento-item large-item feature-pure" role="article" aria-label="纯净原版特性">
<div class="bento-overlay"></div> <div class="bento-overlay"></div>
<div class="bento-content"> <div class="bento-content">
<i class="fas fa-leaf icon"></i> <i class="fas fa-leaf icon"></i>
@@ -129,7 +129,7 @@
</div> </div>
<!-- Medium Feature: Self-developed --> <!-- Medium Feature: Self-developed -->
<div class="bento-item medium-item feature-dev" style="background-image: url('https://img.lunadeer.cn/i/2025/11/26/6926982718ba8.png');" role="article" aria-label="深度自研特性"> <div class="bento-item medium-item feature-dev" role="article" aria-label="深度自研特性">
<div class="bento-overlay"></div> <div class="bento-overlay"></div>
<div class="bento-content"> <div class="bento-content">
<i class="fas fa-code icon"></i> <i class="fas fa-code icon"></i>
@@ -139,7 +139,7 @@
</div> </div>
<!-- Medium Feature: No Params Modified --> <!-- Medium Feature: No Params Modified -->
<div class="bento-item medium-item feature-params" style="background-image: url('https://img.lunadeer.cn/i/2025/11/26/6926775006dea.jpg');" role="article" aria-label="原汁原味特性"> <div class="bento-item medium-item feature-params" role="article" aria-label="原汁原味特性">
<div class="bento-overlay"></div> <div class="bento-overlay"></div>
<div class="bento-content"> <div class="bento-content">
<i class="fas fa-sliders-h icon"></i> <i class="fas fa-sliders-h icon"></i>
@@ -149,7 +149,7 @@
</div> </div>
<!-- Small Features Grid --> <!-- Small Features Grid -->
<div class="bento-item small-item" style="background-image: url('https://img.lunadeer.cn/i/2024/02/21/65d592ea6faa1.jpg');"> <div class="bento-item small-item feature-land">
<div class="bento-overlay"></div> <div class="bento-overlay"></div>
<div class="bento-content"> <div class="bento-content">
<i class="fas fa-home icon"></i> <i class="fas fa-home icon"></i>
@@ -157,7 +157,7 @@
<p>2048*2048 超大领地</p> <p>2048*2048 超大领地</p>
</div> </div>
</div> </div>
<div class="bento-item small-item" style="background-image: url('https://img.lunadeer.cn/i/2025/11/26/692677560db46.png');"> <div class="bento-item small-item feature-bedrock">
<div class="bento-overlay"></div> <div class="bento-overlay"></div>
<div class="bento-content"> <div class="bento-content">
<i class="fas fa-mobile-alt icon"></i> <i class="fas fa-mobile-alt icon"></i>
@@ -165,7 +165,7 @@
<p>手机电脑随时畅玩</p> <p>手机电脑随时畅玩</p>
</div> </div>
</div> </div>
<div class="bento-item small-item" style="background-image: url('https://img.lunadeer.cn/i/2024/02/21/65d592e248066.jpg');"> <div class="bento-item small-item feature-hardware">
<div class="bento-overlay"></div> <div class="bento-overlay"></div>
<div class="bento-content"> <div class="bento-content">
<i class="fas fa-server icon"></i> <i class="fas fa-server icon"></i>
@@ -173,7 +173,7 @@
<p>物理工作站,永不跑路</p> <p>物理工作站,永不跑路</p>
</div> </div>
</div> </div>
<div class="bento-item small-item" style="background-image: url('https://img.lunadeer.cn/i/2025/11/26/692677566b07b.png');"> <div class="bento-item small-item feature-fun">
<div class="bento-overlay"></div> <div class="bento-overlay"></div>
<div class="bento-content"> <div class="bento-content">
<i class="fas fa-gamepad icon"></i> <i class="fas fa-gamepad icon"></i>
@@ -183,7 +183,7 @@
</div> </div>
<!-- Medium Feature: Update --> <!-- Medium Feature: Update -->
<div class="bento-item medium-item" style="background-image: url('https://img.lunadeer.cn/i/2025/11/26/692697b71431b.png');"> <div class="bento-item medium-item feature-update">
<div class="bento-content"> <div class="bento-content">
<i class="fas fa-sync-alt icon"></i> <i class="fas fa-sync-alt icon"></i>
<h3>紧跟新版</h3> <h3>紧跟新版</h3>
@@ -192,7 +192,7 @@
</div> </div>
<!-- Medium Feature: Guide --> <!-- Medium Feature: Guide -->
<div class="bento-item medium-item" style="background-image: url('https://img.lunadeer.cn/i/2025/11/26/692697b7376c7.png');"> <div class="bento-item medium-item feature-guide">
<div class="bento-content"> <div class="bento-content">
<i class="fas fa-book-open icon"></i> <i class="fas fa-book-open icon"></i>
<h3>新手指南</h3> <h3>新手指南</h3>
@@ -217,7 +217,7 @@
</section> </section>
<!-- Crowdfunding Section --> <!-- Crowdfunding Section -->
<section id="crowdfunding-section" class="crowdfunding-section" style="display: none;"> <section id="crowdfunding-section" class="crowdfunding-section home-hidden">
<div class="container"> <div class="container">
<h2 class="section-header">众筹进度</h2> <h2 class="section-header">众筹进度</h2>
<div id="crowdfunding-grid" class="crowdfunding-grid"> <div id="crowdfunding-grid" class="crowdfunding-grid">
@@ -228,7 +228,8 @@
<div id="footer-component"></div> <div id="footer-component"></div>
<script src="components.js"></script> <script src="js/components.js"></script>
<script src="script.js"></script> <script src="js/data_utils.js"></script>
<script src="js/script.js"></script>
</body> </body>
</html> </html>

42
js/data_utils.js Normal file
View File

@@ -0,0 +1,42 @@
const DataUtils = {
parseSponsorsText: function(text) {
const sponsors = [];
if (!text) {
return sponsors;
}
const lines = text.trim().split('\n');
lines.forEach(line => {
const parts = line.split(',');
if (parts.length < 3) {
return;
}
const name = parts[0].trim();
const project = parts[1].trim();
const amountStr = parts[2].trim().replace('¥', '');
const amount = parseFloat(amountStr);
const date = parts[3] ? parts[3].trim() : '';
if (!isNaN(amount)) {
sponsors.push({ name, project, amount, date });
}
});
return sponsors;
},
buildSponsorTotals: function(sponsors) {
const totals = {};
sponsors.forEach(item => {
if (!totals[item.name]) {
totals[item.name] = 0;
}
totals[item.name] += item.amount;
});
return totals;
}
};

View File

@@ -81,27 +81,27 @@ async function fetchServerStatus() {
</div> </div>
`).join(''); `).join('');
} else { } else {
listElement.innerHTML = '<div class="player-item" style="justify-content: center; color: #86868b;">暂无玩家在线</div>'; listElement.innerHTML = '<div class="player-item player-item-muted">暂无玩家在线</div>';
} }
} else { } else {
countElement.innerText = '服务器离线'; countElement.innerText = '服务器离线';
dotElement.classList.add('offline'); dotElement.classList.add('offline');
listElement.innerHTML = '<div class="player-item" style="justify-content: center; color: #ff3b30;">服务器离线</div>'; listElement.innerHTML = '<div class="player-item player-item-error">服务器离线</div>';
} }
} catch (error) { } catch (error) {
console.error('Error fetching server status:', error); console.error('Error fetching server status:', error);
countElement.innerText = '无法获取状态'; countElement.innerText = '无法获取状态';
dotElement.classList.add('offline'); dotElement.classList.add('offline');
listElement.innerHTML = '<div class="player-item" style="justify-content: center; color: #ff3b30;">获取失败</div>'; listElement.innerHTML = '<div class="player-item player-item-error">获取失败</div>';
} }
} }
async function fetchCrowdfunding() { async function fetchCrowdfunding() {
try { try {
console.log('Fetching crowdfunding data...'); console.log('Fetching crowdfunding data...');
const response = await fetch('fund_progress.txt'); const response = await fetch('data/fund_progress.txt');
if (!response.ok) { if (!response.ok) {
console.error('Failed to fetch fund_progress.txt:', response.status, response.statusText); console.error('Failed to fetch data/fund_progress.txt:', response.status, response.statusText);
return; return;
} }
@@ -158,43 +158,25 @@ function renderCrowdfunding(funds) {
</div> </div>
</div> </div>
<div class="progress-bar-bg"> <div class="progress-bar-bg">
<div class="progress-bar-fill" style="width: ${percentage}%"></div> <div class="progress-bar-fill" data-percentage="${percentage}"></div>
</div> </div>
<div class="fund-percentage">${percentage.toFixed(1)}%</div> <div class="fund-percentage">${percentage.toFixed(1)}%</div>
</div> </div>
`; `;
}).join(''); }).join('');
container.querySelectorAll('.progress-bar-fill').forEach(bar => {
const percentage = bar.dataset.percentage || '0';
bar.style.width = `${percentage}%`;
});
} }
async function fetchSponsors() { async function fetchSponsors() {
try { try {
const response = await fetch('sponsors.txt'); const response = await fetch('data/sponsors.txt');
const text = await response.text(); const text = await response.text();
const lines = text.trim().split('\n'); const sponsors = DataUtils.parseSponsorsText(text);
const userTotals = DataUtils.buildSponsorTotals(sponsors);
const sponsors = [];
const userTotals = {};
lines.forEach(line => {
const parts = line.split(',');
if (parts.length >= 3) {
const name = parts[0].trim();
const project = parts[1].trim();
const amountStr = parts[2].trim().replace('¥', '');
const amount = parseFloat(amountStr);
const date = parts[3] ? parts[3].trim() : '';
if (!isNaN(amount)) {
sponsors.push({ name, project, amount, date });
if (userTotals[name]) {
userTotals[name] += amount;
} else {
userTotals[name] = amount;
}
}
}
});
// Sort users by total amount for Top 3 // Sort users by total amount for Top 3
const sortedUsers = Object.keys(userTotals).map(name => ({ const sortedUsers = Object.keys(userTotals).map(name => ({

View File

@@ -93,39 +93,18 @@ function setupListeners() {
async function fetchSponsorsData() { async function fetchSponsorsData() {
try { try {
const response = await fetch('sponsors.txt'); const response = await fetch('data/sponsors.txt');
if (!response.ok) { if (!response.ok) {
throw new Error('Failed to fetch sponsors.txt'); throw new Error('Failed to fetch data/sponsors.txt');
} }
const text = await response.text(); const text = await response.text();
const lines = text.trim().split('\n'); const sponsors = DataUtils.parseSponsorsText(text);
const sponsors = [];
const userTotals = {};
const projects = new Set(); const projects = new Set();
grandTotal = 0; grandTotal = 0;
lines.forEach(line => { sponsors.forEach(item => {
const parts = line.split(','); grandTotal += item.amount;
if (parts.length >= 3) { projects.add(item.project);
const name = parts[0].trim();
const project = parts[1].trim();
const amountStr = parts[2].trim().replace('¥', '');
const amount = parseFloat(amountStr);
const date = parts[3] ? parts[3].trim() : '';
if (!isNaN(amount)) {
sponsors.push({ name, project, amount, date });
grandTotal += amount;
projects.add(project);
if (userTotals[name]) {
userTotals[name] += amount;
} else {
userTotals[name] = amount;
}
}
}
}); });
allSponsors = [...sponsors].reverse(); // Start with newest allSponsors = [...sponsors].reverse(); // Start with newest
@@ -140,7 +119,7 @@ async function fetchSponsorsData() {
} catch (error) { } catch (error) {
console.error('Error loading sponsors:', error); console.error('Error loading sponsors:', error);
const grid = document.getElementById('donation-list'); const grid = document.getElementById('donation-list');
if(grid) grid.innerHTML = '<div style="text-align:center; padding: 40px; color: var(--text-secondary); grid-column: 1/-1;">加载数据失败,请刷新重试</div>'; if(grid) grid.innerHTML = '<div class="sponsor-load-error">加载数据失败,请刷新重试</div>';
} }
} }
@@ -231,10 +210,10 @@ function applyFilters() {
<div class="donation-amount">¥${item.amount}</div> <div class="donation-amount">¥${item.amount}</div>
</div> </div>
<div style="flex-grow: 1; display: flex; flex-direction: column;"> <div class="donation-card-body">
<div class="donation-purpose">${item.project}</div> <div class="donation-purpose">${item.project}</div>
<div class="donation-date"> <div class="donation-date">
<i class="far fa-clock" style="margin-right: 4px;"></i>${item.date} <i class="far fa-clock donation-date-icon"></i>${item.date}
</div> </div>
</div> </div>
`; `;

View File

@@ -68,7 +68,7 @@ function renderLeaderboards() {
let html = ` let html = `
<div class="lb-top-player"> <div class="lb-top-player">
<img src="${top1.avatar}" onerror="this.src='https://crafatar.com/avatars/${top1.uuid}?size=64&overlay'"> <img src="${top1.avatar}" onerror="this.src='https://crafatar.com/avatars/${top1.uuid}?size=64&overlay'">
<div style="font-weight:700; margin-bottom:4px;">${top1.name}</div> <div class="lb-top-name">${top1.name}</div>
<div class="lb-top-data">${valueFormatter(top1)}</div> <div class="lb-top-data">${valueFormatter(top1)}</div>
</div> </div>
<div class="lb-list"> <div class="lb-list">
@@ -78,9 +78,9 @@ function renderLeaderboards() {
const p = players[i]; const p = players[i];
html += ` html += `
<div class="lb-item"> <div class="lb-item">
<div style="display:flex; alignItems:center;"> <div class="lb-item-main">
<span class="lb-rank">${i+1}</span> <span class="lb-rank">${i+1}</span>
<span style="overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:100px;">${p.name}</span> <span class="lb-item-name">${p.name}</span>
</div> </div>
<span>${valueFormatter(p)}</span> <span>${valueFormatter(p)}</span>
</div> </div>

View File

@@ -6,7 +6,7 @@
<title>地图 - 白鹿原 Minecraft 服务器</title> <title>地图 - 白鹿原 Minecraft 服务器</title>
<meta name="description" content="白鹿原服务器在线地图"> <meta name="description" content="白鹿原服务器在线地图">
<link rel="icon" href="favicon.ico" type="image/x-icon"> <link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="css/style.css">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&family=Inter:wght@400;600;800&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style> <style>
@@ -36,6 +36,6 @@
<div class="iframe-container"> <div class="iframe-container">
<iframe src="https://mcmap.lunadeer.cn/" title="在线地图"></iframe> <iframe src="https://mcmap.lunadeer.cn/" title="在线地图"></iframe>
</div> </div>
<script src="components.js"></script> <script src="js/components.js"></script>
</body> </body>
</html> </html>

View File

@@ -6,7 +6,7 @@
<title>相册 - 白鹿原 Minecraft 服务器</title> <title>相册 - 白鹿原 Minecraft 服务器</title>
<meta name="description" content="白鹿原服务器相册"> <meta name="description" content="白鹿原服务器相册">
<link rel="icon" href="favicon.ico" type="image/x-icon"> <link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="css/style.css">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&family=Inter:wght@400;600;800&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style> <style>
@@ -36,6 +36,6 @@
<div class="iframe-container"> <div class="iframe-container">
<iframe src="https://mcphoto.lunadeer.cn/" title="相册"></iframe> <iframe src="https://mcphoto.lunadeer.cn/" title="相册"></iframe>
</div> </div>
<script src="components.js"></script> <script src="js/components.js"></script>
</body> </body>
</html> </html>

View File

@@ -5,520 +5,12 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>赞助榜 - 白鹿原 Minecraft 服务器</title> <title>赞助榜 - 白鹿原 Minecraft 服务器</title>
<link rel="icon" href="favicon.ico" type="image/x-icon"> <link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="css/style.css">
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&family=Inter:wght@400;600;800&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style> <link rel="stylesheet" href="css/pages/sponsor.css">
.sponsor-hero {
padding: 140px 20px 50px;
text-align: center;
background: radial-gradient(circle at center, rgba(0,113,227,0.08) 0%, rgba(255,255,255,0) 70%);
position: relative;
overflow: hidden;
}
.sponsor-hero h1 {
font-size: 56px;
font-weight: 800;
margin-bottom: 24px;
background: linear-gradient(135deg, #1d1d1f 0%, #434344 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
letter-spacing: -0.02em;
}
.hero-subtitle {
font-size: 18px;
color: var(--text-secondary);
margin-top: 16px;
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.total-donations {
display: inline-flex;
flex-direction: column;
align-items: center;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(20px);
padding: 20px 40px;
border-radius: var(--radius-large);
box-shadow: 0 10px 40px rgba(0,0,0,0.06);
border: 1px solid rgba(255,255,255,0.6);
transform: translateY(0);
transition: transform 0.3s ease;
}
.total-donations:hover {
transform: translateY(-5px);
}
.counter-label {
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-secondary);
margin-bottom: 8px;
font-weight: 600;
}
.counter-value {
font-size: 42px;
font-weight: 800;
color: var(--brand-green);
font-feature-settings: "tnum";
font-variant-numeric: tabular-nums;
}
.sponsor-container {
max-width: 1100px;
margin: 0 auto;
padding: 40px 20px;
}
.section-title {
font-size: 28px;
font-weight: 700;
margin-bottom: 30px;
text-align: center;
}
/* Top Donors Podium */
.top-donors-section {
margin-bottom: 60px;
}
.podium-container {
display: flex;
justify-content: center;
align-items: flex-end;
gap: 20px;
padding: 40px 0;
min-height: 300px;
}
.podium-spot {
background: white;
border-radius: var(--radius-medium);
padding: 20px;
width: 220px;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 4px 20px rgba(0,0,0,0.06);
position: relative;
transition: transform 0.3s ease;
text-align: center;
}
.podium-spot:hover {
transform: translateY(-10px);
z-index: 2;
}
.podium-rank {
width: 40px;
height: 40px;
background: #f0f0f0;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 800;
margin-bottom: 12px;
position: absolute;
top: -20px;
border: 4px solid var(--bg-color);
}
/* Gold */
.podium-spot.rank-1 {
height: 260px;
border: 2px solid rgba(255, 215, 0, 0.3);
background: linear-gradient(180deg, rgba(255,215,0,0.05) 0%, rgba(255,255,255,1) 100%);
order: 2; /* Center */
}
.podium-spot.rank-1 .podium-rank { background: #FFD700; color: #fff; box-shadow: 0 4px 10px rgba(255, 215, 0, 0.4); }
.podium-spot.rank-1 .donor-avatar { border-color: #FFD700; width: 80px; height: 80px; }
/* Silver */
.podium-spot.rank-2 {
height: 220px;
border: 2px solid rgba(192, 192, 192, 0.3);
order: 1; /* Left */
}
.podium-spot.rank-2 .podium-rank { background: #C0C0C0; color: #fff; }
/* Bronze */
.podium-spot.rank-3 {
height: 200px;
border: 2px solid rgba(205, 127, 50, 0.3);
order: 3; /* Right */
}
.podium-spot.rank-3 .podium-rank { background: #CD7F32; color: #fff; }
.donor-avatar {
width: 64px;
height: 64px;
border-radius: 50%;
border: 3px solid transparent;
margin-bottom: 12px;
background-color: #f0f0f0;
object-fit: cover;
}
.podium-name {
font-weight: 700;
font-size: 18px;
margin-bottom: 4px;
word-break: break-all;
}
.podium-total {
color: var(--brand-green);
font-weight: 600;
font-size: 16px;
}
/* Controls */
.controls-section {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
margin-bottom: 40px;
max-width: 800px;
margin-left: auto;
margin-right: auto;
}
.controls-header {
display: flex;
width: 100%;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 24px;
}
/* Mobile adjustment for header */
@media (max-width: 600px) {
.controls-header {
flex-direction: column;
}
}
.cta-button {
height: 48px; /* Match search input height */
padding: 0 24px;
background-color: var(--text-primary);
color: white;
border-radius: 99px;
text-decoration: none;
font-weight: 600;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 8px;
transition: all 0.2s;
cursor: pointer;
border: 1px solid transparent;
white-space: nowrap;
box-sizing: border-box;
}
.cta-button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.cta-button.outline {
background-color: transparent;
color: var(--text-primary);
border: 1px solid rgba(0,0,0,0.1);
}
.cta-button.outline:hover {
border-color: var(--text-primary);
background-color: white;
}
/* Modal Styles */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
backdrop-filter: blur(5px);
opacity: 0;
transition: opacity 0.3s ease;
}
.modal.show {
display: flex; /* Flex to center */
opacity: 1;
align-items: center;
justify-content: center;
}
.modal-content {
background-color: white;
margin: auto;
padding: 40px;
border-radius: 24px;
width: 90%;
max-width: 400px;
position: relative;
box-shadow: 0 20px 60px rgba(0,0,0,0.2);
transform: scale(0.9);
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
text-align: center;
}
.modal.show .modal-content {
transform: scale(1);
}
.close-modal {
position: absolute;
top: 20px;
right: 20px;
color: #aaa;
font-size: 24px;
cursor: pointer;
width: 32px;
height: 32px;
background: #f5f5f7;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
}
.close-modal:hover {
color: #000;
background: #e5e5e7;
}
.modal-title {
font-size: 24px;
font-weight: 700;
margin-bottom: 8px;
}
.modal-subtitle {
color: var(--text-secondary);
font-size: 14px;
margin-bottom: 30px;
line-height: 1.5;
}
.qr-placeholder {
background: #f9f9f9;
padding: 20px;
border-radius: 16px;
display: inline-block;
margin-bottom: 20px;
}
.qr-img {
width: 180px;
height: 180px;
display: block;
}
.alipay-btn {
background: #1677FF;
color: white;
display: inline-block;
width: 100%;
padding: 14px;
border-radius: 12px;
font-weight: 600;
text-decoration: none;
margin-top: 10px;
}
.search-box {
position: relative;
flex-grow: 0;
width: 100%;
max-width: 320px;
}
.search-box input {
width: 100%;
height: 48px; /* Fixed height to match button */
padding: 0 20px 0 44px;
border-radius: 99px;
border: 1px solid rgba(0,0,0,0.1);
background: white;
font-size: 15px;
outline: none;
transition: all 0.2s;
}
.search-box input:focus {
border-color: var(--accent-color);
box-shadow: 0 0 0 3px rgba(0,113,227,0.1);
}
.search-box i {
position: absolute;
left: 16px;
top: 50%;
transform: translateY(-50%);
color: var(--text-secondary);
}
.filter-tags {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 10px;
}
.filter-tag {
padding: 8px 16px;
border-radius: 99px;
border: none;
background: white;
color: var(--text-secondary);
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
box-shadow: 0 2px 8px rgba(0,0,0,0.03);
}
.filter-tag:hover {
transform: translateY(-1px);
background: #fafafa;
}
.filter-tag.active {
background: var(--text-primary);
color: white;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.donation-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
}
.donation-card {
background: white;
padding: 24px;
border-radius: var(--radius-medium);
transition: var(--transition);
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
overflow: hidden;
border: 1px solid rgba(0,0,0,0.03);
animation: fadeInUp 0.5s ease backwards;
}
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.donation-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0,0,0,0.08);
border-color: transparent;
}
.donation-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 16px;
}
.donor-info {
display: flex;
align-items: center;
gap: 12px;
}
.mini-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: #f0f0f0;
}
.donor-name {
font-weight: 700;
font-size: 16px;
line-height: 1.2;
}
.donation-amount {
color: var(--brand-green);
font-weight: 800;
font-size: 18px;
background: rgba(52, 199, 89, 0.1);
padding: 4px 10px;
border-radius: 8px;
}
.donation-purpose {
font-size: 13px;
color: var(--text-primary);
background: var(--bg-color);
padding: 6px 12px;
border-radius: 6px;
display: inline-block;
margin-bottom: 12px;
align-self: flex-start;
}
.donation-date {
font-size: 12px;
color: #999;
text-align: right;
margin-top: auto;
border-top: 1px solid rgba(0,0,0,0.05);
padding-top: 12px;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.sponsor-hero h1 { font-size: 32px; }
.counter-value { font-size: 32px; }
.podium-container {
flex-direction: column;
align-items: center;
gap: 30px;
}
.podium-spot {
width: 100%;
max-width: 300px;
order: initial !important; /* Reset order for mobile stack */
height: auto !important; /* Reset height */
}
.podium-rank {
position: relative;
top: 0;
margin-top: -30px;
}
}
</style>
</head> </head>
<body> <body>
@@ -537,7 +29,7 @@
<!-- Controls --> <!-- Controls -->
<div class="controls-section"> <div class="controls-section">
<h2 class="section-title" style="margin-bottom: 10px;">❤️ 赞助列表</h2> <h2 class="section-title sponsor-list-title">❤️ 赞助列表</h2>
<div class="controls-header"> <div class="controls-header">
<div class="search-box"> <div class="search-box">
@@ -561,7 +53,7 @@
<div class="donation-grid" id="donation-list"> <div class="donation-grid" id="donation-list">
<!-- JS will inject cards here --> <!-- JS will inject cards here -->
</div> </div>
<div id="no-results" style="display: none; text-align: center; color: var(--text-secondary); padding: 40px;"> <div id="no-results" class="no-results-message is-hidden">
没有找到匹配的记录 没有找到匹配的记录
</div> </div>
</div> </div>
@@ -572,7 +64,7 @@
<div id="sponsor-modal" class="modal"> <div id="sponsor-modal" class="modal">
<div class="modal-content"> <div class="modal-content">
<span class="close-modal">&times;</span> <span class="close-modal">&times;</span>
<div style="width: 50px; height: 50px; background: rgba(52, 199, 89, 0.1); border-radius: 50%; color: var(--brand-green); display: flex; align-items: center; justify-content: center; font-size: 24px; margin: 0 auto 20px;"> <div class="modal-gift-icon">
<i class="fas fa-gift"></i> <i class="fas fa-gift"></i>
</div> </div>
<h3 class="modal-title">支持白鹿原服务器</h3> <h3 class="modal-title">支持白鹿原服务器</h3>
@@ -583,21 +75,22 @@
<div class="qr-placeholder"> <div class="qr-placeholder">
<img src="https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https%3A%2F%2Fqr.alipay.com%2F2cz0344fnaulnbybhp04" alt="支付宝二维码" class="qr-img"> <img src="https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https%3A%2F%2Fqr.alipay.com%2F2cz0344fnaulnbybhp04" alt="支付宝二维码" class="qr-img">
</div> </div>
<p style="font-size: 13px; color: #999;">推荐使用支付宝扫码</p> <p class="desktop-qr-hint">推荐使用支付宝扫码</p>
</div> </div>
<!-- Mobile Button (will be shown via CSS media query logic in JS or CSS) --> <!-- Mobile Button (will be shown via CSS media query logic in JS or CSS) -->
<div class="mobile-only-block" id="mobile-btn-view" style="display: none;"> <div class="mobile-only-block" id="mobile-btn-view">
<a href="https://qr.alipay.com/2cz0344fnaulnbybhp04" class="alipay-btn" target="_blank"> <a href="https://qr.alipay.com/2cz0344fnaulnbybhp04" class="alipay-btn" target="_blank">
<i class="fab fa-alipay"></i> 打开支付宝赞助 <i class="fab fa-alipay"></i> 打开支付宝赞助
</a> </a>
<p style="font-size: 12px; color: #999; margin-top: 16px;">点击按钮将直接跳转至支付宝转账页面</p> <p class="mobile-pay-hint">点击按钮将直接跳转至支付宝转账页面</p>
</div> </div>
</div> </div>
</div> </div>
<div id="footer-component"></div> <div id="footer-component"></div>
<script src="components.js"></script> <script src="js/components.js"></script>
<script src="sponsor_script.js"></script> <script src="js/data_utils.js"></script>
<script src="js/sponsor_script.js"></script>
</body> </body>
</html> </html>

View File

@@ -26,13 +26,14 @@
<meta property="twitter:image" content="https://img.lunadeer.cn/i/2024/04/22/6625ce6c8ddc1.png"> <meta property="twitter:image" content="https://img.lunadeer.cn/i/2024/04/22/6625ce6c8ddc1.png">
<link rel="icon" href="favicon.ico" type="image/x-icon"> <link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="css/style.css">
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preconnect" href="https://img.lunadeer.cn"> <link rel="preconnect" href="https://img.lunadeer.cn">
<link rel="dns-prefetch" href="https://outline.lunadeer.cn"> <link rel="dns-prefetch" href="https://outline.lunadeer.cn">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&family=Inter:wght@400;600;800&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<link rel="stylesheet" href="css/pages/stats.css">
<!-- Structured Data --> <!-- Structured Data -->
<script type="application/ld+json"> <script type="application/ld+json">
@@ -49,412 +50,13 @@
} }
} }
</script> </script>
<style>
/* Specific styles for stats page override/additions */
.stats-hero {
height: 40vh;
min-height: 300px;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
margin-top: 30px;
}
.player-card {
background: var(--card-bg);
border-radius: var(--radius-medium);
padding: 20px;
text-align: center;
transition: var(--transition);
cursor: pointer;
box-shadow: 0 4px 6px rgba(0,0,0,0.02);
position: relative;
overflow: hidden;
}
.player-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.05);
}
.player-card img {
width: 80px;
height: 80px;
border-radius: 10px;
margin-bottom: 15px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.player-card h3 {
font-size: 16px;
margin-bottom: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.player-card .p-uuid {
font-size: 12px;
color: var(--text-secondary);
margin-bottom: 10px;
font-family: monospace;
}
/* Leaderboard Cards */
.leaderboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 60px;
}
.lb-card {
background: white;
border-radius: var(--radius-medium);
padding: 25px;
box-shadow: 0 4px 20px rgba(0,0,0,0.05);
position: relative;
overflow: hidden;
}
.lb-card.gold { border-top: 4px solid #FFD700; }
.lb-card.silver { border-top: 4px solid #C0C0C0; }
.lb-card.bronze { border-top: 4px solid #CD7F32; }
.lb-card.red { border-top: 4px solid #ff3b30; }
.lb-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 20px;
}
.lb-icon {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
background: var(--bg-color);
color: var(--text-primary);
font-size: 20px;
}
.lb-title {
font-weight: 600;
font-size: 18px;
}
.lb-top-player {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 1px solid #f0f0f0;
}
.lb-top-player img {
width: 64px;
height: 64px;
border-radius: 8px;
margin-bottom: 10px;
}
.lb-top-data {
font-size: 24px;
font-weight: 700;
color: var(--accent-color);
}
.lb-list {
list-style: none;
}
.lb-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
font-size: 14px;
border-bottom: 1px dashed #eee;
}
.lb-item:last-child { border-bottom: none; }
.lb-rank {
width: 24px;
height: 24px;
background: #eee;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 700;
margin-right: 8px;
}
/* Search Box */
.search-container {
max-width: 600px;
margin: 0 auto 40px;
position: relative;
}
.search-input {
width: 100%;
padding: 15px 20px 15px 45px;
border: 1px solid rgba(0,0,0,0.1);
border-radius: 15px;
font-size: 16px;
outline: none;
transition: var(--transition);
background: white;
}
.search-input:focus {
border-color: var(--accent-color);
box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.1);
}
.search-icon {
position: absolute;
left: 15px;
top: 50%;
transform: translateY(-50%);
color: #ccc;
}
/* Stats Modal Override */
.stat-row {
display: flex;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.stat-label { color: var(--text-secondary); }
.stat-value { font-weight: 600; }
.loading-text {
text-align: center;
padding: 40px;
color: var(--text-secondary);
font-size: 18px;
}
.load-more-container {
text-align: center;
margin-top: 40px;
}
.load-more-btn {
background: white;
border: 1px solid #ddd;
padding: 12px 30px;
border-radius: 20px;
cursor: pointer;
font-weight: 600;
transition: var(--transition);
}
.load-more-btn:hover {
background: #f9f9f9;
transform: translateY(-2px);
}
/* Modal Redesign */
.modal-content.expanded-modal {
max-width: 800px;
width: 90%;
display: flex;
flex-direction: column;
max-height: 90vh; /* Scrollable if too tall */
overflow-y: auto;
}
/* Custom Scrollbar for Modal */
.modal-content.expanded-modal::-webkit-scrollbar {
width: 6px; /* Thinner width */
}
.modal-content.expanded-modal::-webkit-scrollbar-track {
background: transparent; /* Transparent track */
margin: 10px 0; /* Add margin to top/bottom */
}
.modal-content.expanded-modal::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.15); /* Subtle color */
border-radius: 10px; /* Rounded corners */
}
.modal-content.expanded-modal::-webkit-scrollbar-thumb:hover {
background: rgba(0, 0, 0, 0.25); /* Darker on hover */
}
.modal-top-section {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-bottom: 20px;
}
.modal-identity {
flex: 1;
min-width: 200px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
}
.modal-identity img {
width: 100px;
height: 100px;
border-radius: 12px;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
margin-bottom: 15px;
}
#modal-name {
margin: 5px 0;
font-size: 24px;
}
#modal-uuid {
font-size: 12px;
color: #999;
font-family: monospace;
word-break: break-all;
}
.stats-list-container.compact-stats {
flex: 1;
min-width: 250px;
display: flex;
flex-direction: column;
justify-content: center;
background: #f9f9f9;
padding: 15px;
border-radius: 12px;
}
.modal-divider {
border: 0;
border-top: 1px solid #eee;
margin: 10px 0 20px;
}
/* Accordion Styles */
.accordion {
display: flex;
flex-direction: column;
gap: 10px;
}
.accordion-item {
border: 1px solid #eee;
border-radius: 8px;
overflow: hidden;
}
.accordion-header {
background: #fdfdfd;
padding: 12px 15px;
cursor: pointer;
font-weight: 600;
display: flex;
justify-content: space-between;
align-items: center;
transition: background 0.2s;
}
.accordion-header:hover {
background: #f0f0f0;
}
.accordion-header .icon {
margin-right: 8px;
width: 20px;
text-align: center;
color: var(--text-secondary);
}
.accordion-header .arrow {
transition: transform 0.3s;
}
.accordion-header.active .arrow {
transform: rotate(180deg);
}
.accordion-header.active {
background: #f0f0f0;
color: var(--accent-color);
}
.accordion-content {
display: none; /* Hidden by default */
padding: 15px;
background: white;
border-top: 1px solid #eee;
}
.accordion-content.show {
display: block;
}
/* Grid for stats inside accordion */
.detail-stats-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 10px;
}
.detail-stat-item {
display: flex;
justify-content: space-between;
font-size: 13px;
padding: 4px 0;
border-bottom: 1px dashed #f5f5f5;
}
.detail-stat-label {
color: #666;
margin-right: 10px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.detail-stat-value {
font-weight: 600;
font-family: monospace;
}
/* Mobile Adjustments */
@media (max-width: 600px) {
.modal-top-section {
flex-direction: column;
}
.modal-identity, .stats-list-container.compact-stats {
width: 100%;
}
}
</style>
</head> </head>
<body> <body>
<div id="navbar-component"></div> <div id="navbar-component"></div>
<!-- Hero Section --> <!-- Hero Section -->
<header class="hero stats-hero" style="background-image: url('https://img.lunadeer.cn/i/2025/11/26/69267755e14e3.png');"> <header class="hero stats-hero stats-hero-bg">
<div class="hero-overlay"></div> <div class="hero-overlay"></div>
<div class="hero-content"> <div class="hero-content">
<h1 class="hero-title">数据中心</h1> <h1 class="hero-title">数据中心</h1>
@@ -463,7 +65,7 @@
</header> </header>
<!-- Main Content --> <!-- Main Content -->
<div class="features-section" style="background: var(--bg-color);"> <div class="features-section stats-main-section">
<div class="container"> <div class="container">
<!-- Leaderboards --> <!-- Leaderboards -->
@@ -514,7 +116,7 @@
</div> </div>
<!-- 5. Play Time --> <!-- 5. Play Time -->
<div class="lb-card" style="border-top: 4px solid #9b59b6;"> <div class="lb-card purple">
<div class="lb-header"> <div class="lb-header">
<div class="lb-icon"><i class="fas fa-crown"></i></div> <div class="lb-icon"><i class="fas fa-crown"></i></div>
<div class="lb-title">尊者</div> <div class="lb-title">尊者</div>
@@ -525,7 +127,7 @@
</div> </div>
<!-- 6. Kills --> <!-- 6. Kills -->
<div class="lb-card" style="border-top: 4px solid #e74c3c;"> <div class="lb-card kill-red">
<div class="lb-header"> <div class="lb-header">
<div class="lb-icon"><i class="fas fa-crosshairs"></i></div> <div class="lb-icon"><i class="fas fa-crosshairs"></i></div>
<div class="lb-title">屠夫</div> <div class="lb-title">屠夫</div>
@@ -603,7 +205,7 @@
<!-- Bottom Section: Detailed Stats Accordion --> <!-- Bottom Section: Detailed Stats Accordion -->
<div class="modal-details-section"> <div class="modal-details-section">
<hr class="modal-divider"> <hr class="modal-divider">
<div id="loading-details" style="text-align:center; padding:20px; color:#888;">正在加载详细数据...</div> <div id="loading-details" class="loading-details-text">正在加载详细数据...</div>
<div id="stats-accordion" class="accordion"> <div id="stats-accordion" class="accordion">
<!-- Dynamic Content --> <!-- Dynamic Content -->
</div> </div>
@@ -614,7 +216,7 @@
<div id="footer-component"></div> <div id="footer-component"></div>
<script src="components.js"></script> <script src="js/components.js"></script>
<script src="stats_script.js"></script> <script src="js/stats_script.js"></script>
</body> </body>
</html> </html>