Files
portal.tootaio.com/index.html
xiaomai fb1116ab45 feat(ui): overhaul landing page with modern card-based design
This commit introduces a complete redesign of the main landing page, replacing the old two-column layout with a modern, responsive, card-based UI. The goal is to improve user experience, visual appeal, and
content organization. Key changes include a new visual identity with an updated color palette, unified 'Services' and 'Other Links' sections using a card grid, refactored front-end code (HTML, CSS, JS) for
better maintainability, and an updated `siteConfig.json` to support the new design with icons and clearer names. The search functionality has also been improved with real-time filtering.
2025-09-11 16:13:58 +08:00

535 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tootaio Studio - 游戏开发与工具服务</title>
<meta name="description" content="Tootaio工作室专注于游戏开发与工具服务提供多种在线工具和资源">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:wght@600;700&display=swap"
rel="stylesheet">
<style>
:root {
--bg-primary: #0a0a12;
--bg-secondary: #151521;
--bg-card: #1c1c2d;
--bg-card-hover: #23233a;
--accent-primary: #ff9e44;
--accent-secondary: #ff6b6b;
--text-primary: #ffffff;
--text-secondary: #b8b8d0;
--text-muted: #7a7a9d;
--border-color: rgba(255, 255, 255, 0.08);
--gradient: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
--shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
--radius: 16px;
--transition: all 0.3s ease;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
background: var(--bg-primary);
color: var(--text-primary);
line-height: 1.6;
padding: 0;
overflow-x: hidden;
}
.container {
max-width: 1280px;
margin: 0 auto;
padding: 0 24px;
}
/* Header Styles */
header {
padding: 40px 0;
text-align: center;
background: linear-gradient(to bottom, var(--bg-primary), var(--bg-secondary));
border-bottom: 1px solid var(--border-color);
}
.logo {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100px;
height: 100px;
border-radius: 50%;
background: var(--gradient);
margin-bottom: 20px;
box-shadow: var(--shadow);
transition: var(--transition);
}
.logo:hover {
transform: scale(1.05) rotate(5deg);
}
.logo-text {
font-family: 'Playfair Display', serif;
font-weight: 700;
font-size: 28px;
color: #fff;
}
h1 {
font-family: 'Playfair Display', serif;
font-size: 48px;
margin-bottom: 12px;
background: linear-gradient(to right, var(--accent-primary), var(--accent-secondary));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.tagline {
font-size: 18px;
color: var(--text-secondary);
max-width: 600px;
margin: 0 auto 30px;
}
.search-container {
max-width: 500px;
margin: 0 auto;
position: relative;
}
.search-box {
width: 100%;
padding: 16px 20px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border-color);
border-radius: 50px;
color: var(--text-primary);
font-size: 16px;
padding-left: 50px;
transition: var(--transition);
}
.search-box:focus {
outline: none;
border-color: var(--accent-primary);
box-shadow: 0 0 0 3px rgba(255, 158, 68, 0.2);
}
.search-icon {
position: absolute;
left: 20px;
top: 50%;
transform: translateY(-50%);
color: var(--text-muted);
}
/* Main Content */
main {
padding: 60px 0;
}
.section-title {
font-size: 28px;
margin-bottom: 40px;
text-align: center;
position: relative;
display: inline-block;
left: 50%;
transform: translateX(-50%);
}
.section-title::after {
content: '';
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
width: 60px;
height: 4px;
background: var(--gradient);
border-radius: 2px;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 24px;
margin-bottom: 60px;
}
.card {
background: var(--bg-card);
border-radius: var(--radius);
overflow: hidden;
transition: var(--transition);
border: 1px solid var(--border-color);
box-shadow: var(--shadow);
display: flex;
flex-direction: column;
height: 100%;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
border-color: rgba(255, 158, 68, 0.2);
}
.card-header {
padding: 20px;
position: relative;
border-bottom: 1px solid var(--border-color);
}
.card-icon {
width: 50px;
height: 50px;
border-radius: 12px;
background: var(--gradient);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16px;
font-size: 20px;
}
.card-title {
font-size: 20px;
font-weight: 600;
margin-bottom: 8px;
}
.card-url {
color: var(--accent-primary);
font-size: 14px;
display: block;
margin-bottom: 12px;
}
.card-body {
padding: 20px;
flex-grow: 1;
}
.card-description {
color: var(--text-secondary);
margin-bottom: 20px;
}
.card-footer {
padding: 0 20px 20px;
}
.card-link {
display: inline-flex;
align-items: center;
padding: 10px 20px;
background: rgba(255, 158, 68, 0.1);
color: var(--accent-primary);
border-radius: 50px;
text-decoration: none;
font-weight: 500;
transition: var(--transition);
}
.card-link:hover {
background: rgba(255, 158, 68, 0.2);
transform: translateX(5px);
}
.card-link i {
margin-left: 8px;
font-size: 14px;
}
/* Footer */
footer {
background: var(--bg-secondary);
padding: 40px 0;
border-top: 1px solid var(--border-color);
}
.footer-content {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 20px;
}
.footer-logo {
font-family: 'Playfair Display', serif;
font-weight: 700;
font-size: 24px;
}
.footer-links {
display: flex;
gap: 20px;
}
.footer-link {
color: var(--text-secondary);
text-decoration: none;
transition: var(--transition);
}
.footer-link:hover {
color: var(--accent-primary);
}
.copyright {
color: var(--text-muted);
font-size: 14px;
margin-top: 20px;
width: 100%;
text-align: center;
}
/* Responsive */
@media (max-width: 768px) {
h1 {
font-size: 36px;
}
.grid {
grid-template-columns: 1fr;
}
.footer-content {
flex-direction: column;
text-align: center;
}
.footer-links {
justify-content: center;
}
}
/* Animation */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.card {
animation: fadeIn 0.5s ease-out;
}
/* Language Toggle */
.lang-toggle {
position: absolute;
top: 20px;
right: 20px;
}
.lang-btn {
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border-color);
color: var(--text-secondary);
padding: 8px 16px;
border-radius: 50px;
cursor: pointer;
transition: var(--transition);
}
.lang-btn:hover {
background: rgba(255, 255, 255, 0.1);
}
</style>
</head>
<body>
<div class="lang-toggle">
<button class="lang-btn" id="langToggle">EN</button>
</div>
<header>
<div class="container">
<div class="logo">
<span class="logo-text">T</span>
</div>
<h1>Tootaio Studio</h1>
<p class="tagline">专注于游戏开发与创新工具服务的创意工作室</p>
<div class="search-container">
<i class="fas fa-search search-icon"></i>
<input type="text" class="search-box" placeholder="搜索服务或工具..." id="searchInput">
</div>
</div>
</header>
<main class="container">
<h2 class="section-title">我们的服务</h2>
<div class="grid" id="servicesGrid">
<!-- 服务卡片将通过JavaScript动态生成 -->
</div>
<h2 class="section-title">其他链接</h2>
<div class="grid" id="linksGrid">
<!-- 链接卡片将通过JavaScript动态生成 -->
</div>
</main>
<footer>
<div class="container">
<div class="footer-content">
<div class="footer-logo">Tootaio</div>
<div class="footer-links">
<a href="#" class="footer-link">关于我们</a>
<a href="#" class="footer-link">联系方式</a>
<a href="#" class="footer-link">使用条款</a>
</div>
</div>
<div class="copyright">
&copy; <span id="currentYear"></span> Tootaio Studio. 保留所有权利。
</div>
</div>
</footer>
<script>
// 配置数据
async function loadConfig() {
try {
const res = await fetch('./siteConfig.json', { cache: 'no-store' });
if (!res.ok) throw new Error('no siteConfig.json');
const cfg = await res.json();
return cfg;
} catch (e) {
console.warn('siteConfig.json not found, using default config.');
return defaultSiteConfig;
}
}
// 当前语言设置
let currentLang = 'zh';
// 初始化页面
document.addEventListener('DOMContentLoaded', function () {
// 设置当前年份
document.getElementById('currentYear').textContent = new Date().getFullYear();
// 渲染内容
renderContent();
// 添加搜索功能
document.getElementById('searchInput').addEventListener('input', function (e) {
filterContent(e.target.value);
});
// 添加语言切换功能
document.getElementById('langToggle').addEventListener('click', function () {
currentLang = currentLang === 'zh' ? 'en' : 'zh';
this.textContent = currentLang === 'zh' ? 'EN' : '中文';
renderContent();
});
});
// 渲染内容
async function renderContent() {
const siteConfig = await loadConfig();
renderServices(siteConfig);
renderLinks(siteConfig);
}
// 渲染服务卡片
function renderServices(siteConfig) {
const grid = document.getElementById('servicesGrid');
grid.innerHTML = '';
siteConfig.services.forEach(service => {
const card = document.createElement('div');
card.className = 'card';
card.innerHTML = `
<div class="card-header">
<div class="card-icon">
<i class="fas fa-${service.icon || 'link'}"></i>
</div>
<h3 class="card-title">${service.name}</h3>
<span class="card-url">${service.url.replace('https://', '')}</span>
</div>
<div class="card-body">
<p class="card-description">${currentLang === 'zh' ? service.description_zh : service.description_en}</p>
</div>
<div class="card-footer">
<a href="${service.url}" target="_blank" class="card-link">
${currentLang === 'zh' ? '访问服务' : 'Visit Service'}
<i class="fas fa-arrow-right"></i>
</a>
</div>
`;
grid.appendChild(card);
});
}
// 渲染链接卡片
function renderLinks(siteConfig) {
const grid = document.getElementById('linksGrid');
grid.innerHTML = '';
siteConfig.otherLinks.forEach(link => {
const card = document.createElement('div');
card.className = 'card';
card.innerHTML = `
<div class="card-header">
<div class="card-icon">
<i class="fab fa-${link.icon || 'link'}"></i>
</div>
<h3 class="card-title">${currentLang === 'zh' ? link.name_zh : link.name_en}</h3>
<span class="card-url">${link.url.replace('https://', '')}</span>
</div>
<div class="card-footer">
<a href="${link.url}" target="_blank" class="card-link">
${currentLang === 'zh' ? '访问链接' : 'Visit Link'}
<i class="fas fa-arrow-right"></i>
</a>
</div>
`;
grid.appendChild(card);
});
}
// 过滤内容
function filterContent(searchTerm) {
const services = document.querySelectorAll('#servicesGrid .card');
const links = document.querySelectorAll('#linksGrid .card');
const allItems = [...services, ...links];
const term = searchTerm.toLowerCase();
if (term === '') {
allItems.forEach(item => item.style.display = 'flex');
return;
}
allItems.forEach(item => {
const title = item.querySelector('.card-title').textContent.toLowerCase();
const description = item.querySelector('.card-description')?.textContent.toLowerCase() || '';
const url = item.querySelector('.card-url').textContent.toLowerCase();
if (title.includes(term) || description.includes(term) || url.includes(term)) {
item.style.display = 'flex';
} else {
item.style.display = 'none';
}
});
}
</script>
</body>
</html>