Files
html-tools/index.html
T
chao5 91323b0c99 Add 9 new tools across multiple categories
Text Processing:
- Word Counter: Character/word/line counting with reading time
- Text Diff: Compare two texts with inline/side-by-side view
- Markdown to HTML: Real-time Markdown to HTML converter

Developer Tools:
- UUID Generator: Generate UUID v4/v1 with batch support
- JWT Decoder: Decode and verify JSON Web Tokens

Converter Tools:
- Unix Timestamp Converter: Convert between timestamp and datetime
- Base Converter: Convert between binary/octal/decimal/hexadecimal
- XML to JSON: Bidirectional XML and JSON converter

Image Tools:
- Image to Base64: Convert images to Base64 encoded strings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-23 02:15:35 +08:00

723 lines
22 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JustHTMLs - 开源 HTML 工具集</title>
<meta name="description" content="JustHTMLs 是一个开源的 HTML 工具集平台,汇集各种轻量级的在线工具,无需安装,即开即用。">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style>
:root {
--primary: #6366f1;
--primary-dark: #4f46e5;
--secondary: #8b5cf6;
--bg: #0f172a;
--bg-card: #1e293b;
--bg-hover: #334155;
--text: #f1f5f9;
--text-muted: #94a3b8;
--border: #334155;
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* Header */
header {
background: var(--bg-card);
border-bottom: 1px solid var(--border);
padding: 20px 0;
position: sticky;
top: 0;
z-index: 100;
}
.header-content {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 20px;
}
.logo {
display: flex;
align-items: center;
gap: 12px;
text-decoration: none;
color: var(--text);
}
.logo-icon {
width: 40px;
height: 40px;
background: linear-gradient(135deg, var(--primary), var(--secondary));
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
}
.logo-text {
font-size: 24px;
font-weight: 700;
background: linear-gradient(135deg, var(--primary), var(--secondary));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.logo-tagline {
font-size: 12px;
color: var(--text-muted);
margin-left: 8px;
}
.header-actions {
display: flex;
gap: 12px;
}
.btn {
padding: 10px 20px;
border-radius: 8px;
border: none;
cursor: pointer;
font-size: 14px;
font-weight: 500;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 8px;
transition: all 0.2s;
}
.btn-primary {
background: linear-gradient(135deg, var(--primary), var(--secondary));
color: white;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4);
}
.btn-secondary {
background: var(--bg-hover);
color: var(--text);
}
.btn-secondary:hover {
background: #475569;
}
/* Hero */
.hero {
padding: 60px 0 40px;
text-align: center;
}
.hero h1 {
font-size: 42px;
font-weight: 800;
margin-bottom: 16px;
background: linear-gradient(135deg, var(--primary), var(--secondary), #ec4899);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero p {
font-size: 18px;
color: var(--text-muted);
max-width: 600px;
margin: 0 auto 40px;
}
.stats {
display: flex;
justify-content: center;
gap: 40px;
margin-top: 30px;
}
.stat-item {
text-align: center;
}
.stat-value {
font-size: 28px;
font-weight: 700;
color: var(--primary);
}
.stat-label {
font-size: 14px;
color: var(--text-muted);
}
/* Search & Filter */
.search-section {
padding: 30px 0;
}
.search-box {
display: flex;
gap: 12px;
margin-bottom: 20px;
}
.search-input-wrapper {
flex: 1;
position: relative;
}
.search-icon {
position: absolute;
left: 16px;
top: 50%;
transform: translateY(-50%);
color: var(--text-muted);
}
.search-input {
width: 100%;
padding: 14px 16px 14px 44px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 12px;
color: var(--text);
font-size: 16px;
transition: all 0.2s;
}
.search-input:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
}
.category-tabs {
display: flex;
gap: 8px;
flex-wrap: wrap;
justify-content: center;
}
.category-tab {
padding: 8px 16px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 20px;
color: var(--text-muted);
cursor: pointer;
transition: all 0.2s;
font-size: 14px;
}
.category-tab:hover {
background: var(--bg-hover);
}
.category-tab.active {
background: linear-gradient(135deg, var(--primary), var(--secondary));
border-color: transparent;
color: white;
}
/* Tools Grid */
.tools-section {
padding: 40px 0 80px;
}
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24px;
}
.section-title {
font-size: 24px;
font-weight: 700;
}
.tools-count {
color: var(--text-muted);
font-size: 14px;
}
.tools-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.tool-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 16px;
padding: 24px;
cursor: pointer;
transition: all 0.3s;
text-decoration: none;
color: inherit;
display: block;
}
.tool-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-lg);
border-color: var(--primary);
}
.tool-header {
display: flex;
align-items: flex-start;
gap: 16px;
margin-bottom: 16px;
}
.tool-icon {
width: 56px;
height: 56px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
flex-shrink: 0;
}
.tool-info {
flex: 1;
min-width: 0;
}
.tool-title {
font-size: 18px;
font-weight: 600;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.tool-category {
font-size: 12px;
color: var(--text-muted);
display: flex;
align-items: center;
gap: 4px;
}
.tool-description {
color: var(--text-muted);
font-size: 14px;
line-height: 1.5;
margin-bottom: 16px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.tool-footer {
display: flex;
align-items: center;
justify-content: space-between;
}
.tool-tags {
display: flex;
gap: 6px;
flex-wrap: wrap;
}
.tool-tag {
font-size: 11px;
padding: 4px 8px;
background: var(--bg-hover);
border-radius: 4px;
color: var(--text-muted);
}
.tool-arrow {
color: var(--primary);
opacity: 0;
transition: opacity 0.2s;
}
.tool-card:hover .tool-arrow {
opacity: 1;
}
/* Featured Badge */
.featured-badge {
position: absolute;
top: 12px;
right: 12px;
background: linear-gradient(135deg, #f59e0b, #ef4444);
color: white;
font-size: 10px;
font-weight: 600;
padding: 4px 8px;
border-radius: 12px;
}
.tool-card {
position: relative;
}
/* Empty State */
.empty-state {
text-align: center;
padding: 60px 20px;
color: var(--text-muted);
}
.empty-icon {
font-size: 64px;
margin-bottom: 20px;
opacity: 0.5;
}
/* Footer */
footer {
background: var(--bg-card);
border-top: 1px solid var(--border);
padding: 40px 0;
margin-top: 60px;
}
.footer-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 40px;
}
.footer-section h3 {
font-size: 16px;
font-weight: 600;
margin-bottom: 16px;
}
.footer-section p {
color: var(--text-muted);
font-size: 14px;
line-height: 1.6;
}
.footer-links {
list-style: none;
}
.footer-links li {
margin-bottom: 8px;
}
.footer-links a {
color: var(--text-muted);
text-decoration: none;
font-size: 14px;
transition: color 0.2s;
}
.footer-links a:hover {
color: var(--primary);
}
.footer-bottom {
text-align: center;
padding-top: 30px;
margin-top: 30px;
border-top: 1px solid var(--border);
color: var(--text-muted);
font-size: 14px;
}
/* Loading */
.loading {
text-align: center;
padding: 40px;
color: var(--text-muted);
}
@media (max-width: 768px) {
.hero h1 {
font-size: 32px;
}
.tools-grid {
grid-template-columns: 1fr;
}
.stats {
gap: 20px;
}
}
</style>
</head>
<body>
<header>
<div class="container">
<div class="header-content">
<a href="/" class="logo">
<div class="logo-icon"></div>
<div>
<div class="logo-text">JustHTMLs</div>
<div class="logo-tagline">开源 HTML 工具集</div>
</div>
</a>
<div class="header-actions">
<a href="https://github.com/justhtmls/html-tools/issues/new?template=tool-request.md" target="_blank" class="btn btn-secondary">
<i class="fas fa-lightbulb"></i> 提交需求
</a>
<a href="https://github.com/justhtmls/html-tools" target="_blank" class="btn btn-secondary">
<i class="fab fa-github"></i> GitHub
</a>
<a href="https://github.com/justhtmls/html-tools/issues/new?template=tool-submission.md" target="_blank" class="btn btn-primary">
<i class="fas fa-plus"></i> 贡献工具
</a>
</div>
</div>
</div>
</header>
<main>
<section class="hero">
<div class="container">
<h1>轻量级 HTML 工具集合</h1>
<p>所有工具均为单文件 HTML,无需安装,打开即用。保护隐私,数据本地处理。</p>
<div class="stats">
<div class="stat-item">
<div class="stat-value" id="tools-count">-</div>
<div class="stat-label">工具数量</div>
</div>
<div class="stat-item">
<div class="stat-value" id="categories-count">-</div>
<div class="stat-label">分类数量</div>
</div>
<div class="stat-item">
<div class="stat-value">100%</div>
<div class="stat-label">开源免费</div>
</div>
</div>
</div>
</section>
<section class="search-section">
<div class="container">
<div class="search-box">
<div class="search-input-wrapper">
<i class="fas fa-search search-icon"></i>
<input type="text" class="search-input" id="search-input" placeholder="搜索工具名称、描述或标签...">
</div>
</div>
<div class="category-tabs" id="category-tabs">
<button class="category-tab active" data-category="all">
<i class="fas fa-th-large"></i> 全部
</button>
</div>
</div>
</section>
<section class="tools-section">
<div class="container">
<div class="section-header">
<h2 class="section-title">工具列表</h2>
<span class="tools-count" id="tools-count-label">加载中...</span>
</div>
<div class="tools-grid" id="tools-grid">
<div class="loading">
<i class="fas fa-spinner fa-spin"></i> 加载工具列表...
</div>
</div>
</div>
</section>
<section class="container" style="padding: 60px 20px;">
<div style="background: linear-gradient(135deg, var(--bg-card), var(--bg-hover)); border-radius: 20px; padding: 40px; text-align: center; border: 1px solid var(--border);">
<h2 style="font-size: 28px; margin-bottom: 16px;">🚀 贡献你的工具</h2>
<p style="color: var(--text-muted); max-width: 500px; margin: 0 auto 24px;">
JustHTMLs 欢迎社区贡献!创建一个新的 HTML 工具,通过 GitHub Issues 提交,让我们一起构建最完整的工具集合。
</p>
<a href="https://github.com/justhtmls/html-tools/issues/new?template=tool-submission.md" target="_blank" class="btn btn-primary" style="font-size: 16px; padding: 12px 24px;">
<i class="fas fa-plus"></i> 提交新工具
</a>
</div>
</section>
</main>
<footer>
<div class="container">
<div class="footer-content">
<div class="footer-section">
<h3>关于 JustHTMLs</h3>
<p>JustHTMLs 是一个开源的 HTML 工具集平台,所有工具均为单文件 HTML,无需构建步骤,可直接在浏览器中运行。</p>
</div>
<div class="footer-section">
<h3>快速链接</h3>
<ul class="footer-links">
<li><a href="https://github.com/justhtmls" target="_blank"><i class="fab fa-github"></i> GitHub 组织</a></li>
<li><a href="https://github.com/justhtmls/html-tools" target="_blank"><i class="fas fa-globe"></i> 网站仓库</a></li>
<li><a href="https://github.com/justhtmls/html-tools/issues" target="_blank"><i class="fas fa-bug"></i> 报告问题</a></li>
<li><a href="CONTRIBUTING.html">贡献指南</a></li>
</ul>
</div>
<div class="footer-section">
<h3>设计理念</h3>
<ul class="footer-links">
<li><a href="reference.md">设计文档</a></li>
<li>单文件 HTML,内联 CSS/JS</li>
<li>无需构建,复制即用</li>
<li>数据本地处理,保护隐私</li>
</ul>
</div>
</div>
<div class="footer-bottom">
<p>&copy; 2025 JustHTMLs. 基于 MIT 许可证开源。</p>
</div>
</div>
</footer>
<script>
let toolsData = null;
let currentCategory = 'all';
let searchQuery = '';
async function loadTools() {
try {
const response = await fetch('index.json');
const data = await response.json();
toolsData = data;
renderCategories();
renderTools();
updateStats();
} catch (error) {
console.error('Failed to load tools:', error);
document.getElementById('tools-grid').innerHTML = `
<div class="empty-state">
<div class="empty-icon">⚠️</div>
<p>加载工具列表失败,请刷新页面重试。</p>
</div>
`;
}
}
function updateStats() {
document.getElementById('tools-count').textContent = toolsData.tools.length;
document.getElementById('categories-count').textContent = toolsData.categories.length;
}
function renderCategories() {
const container = document.getElementById('category-tabs');
container.innerHTML = `
<button class="category-tab ${currentCategory === 'all' ? 'active' : ''}" data-category="all">
<i class="fas fa-th-large"></i> 全部
</button>
`;
toolsData.categories.forEach(cat => {
const btn = document.createElement('button');
btn.className = `category-tab ${currentCategory === cat.id ? 'active' : ''}`;
btn.dataset.category = cat.id;
btn.innerHTML = `${cat.icon} ${cat.name}`;
btn.addEventListener('click', () => selectCategory(cat.id));
container.appendChild(btn);
});
}
function selectCategory(category) {
currentCategory = category;
document.querySelectorAll('.category-tab').forEach(tab => {
tab.classList.toggle('active', tab.dataset.category === category);
});
renderTools();
}
function filterTools() {
return toolsData.tools.filter(tool => {
const matchesCategory = currentCategory === 'all' || tool.category === currentCategory;
const matchesSearch = !searchQuery ||
tool.name.toLowerCase().includes(searchQuery) ||
tool.description.toLowerCase().includes(searchQuery) ||
tool.tags.some(tag => tag.toLowerCase().includes(searchQuery));
return matchesCategory && matchesSearch;
});
}
function renderTools() {
const container = document.getElementById('tools-grid');
const filteredTools = filterTools();
document.getElementById('tools-count-label').textContent = `共 ${filteredTools.length} 个工具`;
if (filteredTools.length === 0) {
container.innerHTML = `
<div class="empty-state">
<div class="empty-icon">🔍</div>
<p>未找到匹配的工具</p>
</div>
`;
return;
}
container.innerHTML = filteredTools.map(tool => {
const category = toolsData.categories.find(c => c.id === tool.category);
return `
<a href="${tool.detail}" class="tool-card" style="--tool-color: ${tool.color}">
${tool.featured ? '<span class="featured-badge">精选</span>' : ''}
<div class="tool-header">
<div class="tool-icon" style="background: ${tool.color}20; color: ${tool.color};">
${tool.icon}
</div>
<div class="tool-info">
<div class="tool-title">${tool.name}</div>
<div class="tool-category">${category?.icon || ''} ${category?.name || '未分类'}</div>
</div>
</div>
<div class="tool-description">${tool.description}</div>
<div class="tool-footer">
<div class="tool-tags">
${tool.tags.slice(0, 3).map(tag => `<span class="tool-tag">${tag}</span>`).join('')}
</div>
<i class="fas fa-arrow-right tool-arrow"></i>
</div>
</a>
`;
}).join('');
}
// Search functionality
document.getElementById('search-input').addEventListener('input', (e) => {
searchQuery = e.target.value.toLowerCase();
renderTools();
});
// Initialize
loadTools();
</script>
</body>
</html>