feat: 添加AI设计工具的配置文件和新的图像生成器UI原型
This commit is contained in:
398
newindex.html
Normal file
398
newindex.html
Normal file
@@ -0,0 +1,398 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>OpenRouter Image Generator</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
|
||||
<link href=".superdesign/design_iterations/clean_theme.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<!-- Header -->
|
||||
<header class="app-header">
|
||||
<div class="header-title">
|
||||
<i data-lucide="image" style="width: 24px; height: 24px;"></i>
|
||||
OpenRouter Image Generator
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button class="btn btn-secondary btn-sm" id="settingsBtn" title="设置">
|
||||
<i data-lucide="settings" style="width: 16px; height: 16px;"></i>
|
||||
</button>
|
||||
<div class="status-indicator">
|
||||
<span class="status-dot status-disconnected" id="connectionStatus"></span>
|
||||
<span id="connectionText">未连接</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<aside class="app-sidebar" id="sidebar">
|
||||
<!-- Prompt Section -->
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header">
|
||||
<i data-lucide="edit-3" style="width: 16px; height: 16px;"></i>
|
||||
生成提示
|
||||
</div>
|
||||
<div class="sidebar-section-content">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="messageInput">描述您想要生成的图像</label>
|
||||
<textarea class="form-input form-textarea" id="messageInput" placeholder="例如:一只可爱的橙色小猫坐在阳光洒满的窗台上..."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reference Images -->
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header">
|
||||
<i data-lucide="image-plus" style="width: 16px; height: 16px;"></i>
|
||||
参考图像
|
||||
</div>
|
||||
<div class="sidebar-section-content">
|
||||
<div class="upload-zone" id="dropZone" onclick="document.getElementById('imageInput').click()">
|
||||
<i data-lucide="upload" class="upload-zone-icon"></i>
|
||||
<p class="upload-zone-text">点击上传或拖拽图像到此处</p>
|
||||
<p class="upload-zone-text" style="font-size: 0.75rem; color: var(--text-muted);">支持 JPG, PNG, WebP (最多10张)</p>
|
||||
<input type="file" style="display: none;" id="imageInput" accept="image/*" multiple>
|
||||
</div>
|
||||
<div class="image-preview" id="imagePreview" style="margin-top: var(--space-md); display: none;">
|
||||
<!-- Preview items will be added here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Generation Controls -->
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header">
|
||||
<i data-lucide="sliders-horizontal" style="width: 16px; height: 16px;"></i>
|
||||
生成控制
|
||||
</div>
|
||||
<div class="sidebar-section-content">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="batchCount">生成数量</label>
|
||||
<input type="number" class="form-input" id="batchCount" min="1" max="20" value="6">
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: var(--space-sm);">
|
||||
<button class="btn btn-primary btn-full" onclick="sendMessage()">
|
||||
<i data-lucide="zap" style="width: 16px; height: 16px;"></i>
|
||||
生成图像
|
||||
</button>
|
||||
<button class="btn btn-success btn-full" onclick="sendBatchMessage()">
|
||||
<i data-lucide="layers" style="width: 16px; height: 16px;"></i>
|
||||
批量生成
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Settings Panel (Hidden by default) -->
|
||||
<div class="sidebar-section" id="settingsPanel" style="display: none;">
|
||||
<div class="sidebar-section-header">
|
||||
<i data-lucide="settings" style="width: 16px; height: 16px;"></i>
|
||||
API设置
|
||||
</div>
|
||||
<div class="sidebar-section-content">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="apiKey">API Key</label>
|
||||
<input type="password" class="form-input" id="apiKey" placeholder="输入您的OpenRouter API Key">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="baseUrl">Base URL</label>
|
||||
<input type="url" class="form-input" id="baseUrl" value="https://openrouter.ai/api/v1">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="model">模型</label>
|
||||
<select class="form-input" id="model">
|
||||
<option value="google/gemini-2.5-flash-image-preview:free">Google Gemini 2.5 Flash Image Preview (Free)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="timeout">超时时间 (秒)</label>
|
||||
<input type="number" class="form-input" id="timeout" value="600">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="proxy">代理 (可选)</label>
|
||||
<input type="url" class="form-input" id="proxy" placeholder="http://proxy:port">
|
||||
</div>
|
||||
<div style="display: flex; gap: var(--space-sm);">
|
||||
<button class="btn btn-secondary" onclick="testConnection()">
|
||||
<i data-lucide="wifi" style="width: 16px; height: 16px;"></i>
|
||||
测试连接
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="app.clearStorage()">
|
||||
<i data-lucide="trash-2" style="width: 16px; height: 16px;"></i>
|
||||
清除数据
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Chat History -->
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header">
|
||||
<i data-lucide="message-circle" style="width: 16px; height: 16px;"></i>
|
||||
对话历史
|
||||
</div>
|
||||
<div class="sidebar-section-content">
|
||||
<div id="chatHistory" style="max-height: 200px; overflow-y: auto; font-size: 0.8125rem; color: var(--text-secondary);">
|
||||
<p style="text-align: center; color: var(--text-muted); padding: var(--space-lg) 0;">暂无对话记录</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="app-main">
|
||||
<div class="main-content">
|
||||
<!-- Generation Preview Area -->
|
||||
<section class="main-section">
|
||||
<div class="generation-preview" id="generationPreview">
|
||||
<div class="generation-preview-empty" id="previewEmpty">
|
||||
<i data-lucide="image" style="width: 64px; height: 64px; color: var(--text-muted); margin-bottom: var(--space-lg);"></i>
|
||||
<h3 style="color: var(--text-secondary); font-weight: 500; margin-bottom: var(--space-md);">准备生成图像</h3>
|
||||
<p style="color: var(--text-muted); font-size: 0.875rem;">在左侧输入提示词,然后点击生成按钮开始创作</p>
|
||||
</div>
|
||||
<div class="generation-preview-loading" id="previewLoading" style="display: none;">
|
||||
<div class="spinner"></div>
|
||||
<p style="color: var(--text-secondary);">正在生成图像,请稍候...</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Generated Images Gallery -->
|
||||
<section class="main-section">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-lg);">
|
||||
<h2 class="main-section-title" style="margin: 0;">
|
||||
<i data-lucide="images" style="width: 20px; height: 20px;"></i>
|
||||
生成的图像
|
||||
</h2>
|
||||
<button class="btn btn-success btn-sm" id="downloadAllImagesBtn" style="display: none;">
|
||||
<i data-lucide="download" style="width: 16px; height: 16px;"></i>
|
||||
全部下载
|
||||
</button>
|
||||
</div>
|
||||
<div class="image-gallery" id="imageGallery">
|
||||
<!-- Images will be added here -->
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Sidebar Overlay -->
|
||||
<div class="sidebar-overlay" id="sidebarOverlay" onclick="closeMobileSidebar()"></div>
|
||||
|
||||
<!-- Image Viewer Modal -->
|
||||
<div id="imageViewerModal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.9); z-index: 1000; backdrop-filter: blur(8px);">
|
||||
<div style="position: relative; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; padding: var(--space-lg);">
|
||||
<!-- Close Button -->
|
||||
<button onclick="closeImageViewer()" style="position: absolute; top: var(--space-lg); right: var(--space-lg); background: rgba(255, 255, 255, 0.1); border: none; border-radius: 50%; width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; cursor: pointer; backdrop-filter: blur(8px);">
|
||||
<i data-lucide="x" style="width: 24px; height: 24px; color: white;"></i>
|
||||
</button>
|
||||
|
||||
<!-- Navigation -->
|
||||
<button id="prevImageBtn" style="position: absolute; left: var(--space-lg); top: 50%; transform: translateY(-50%); background: rgba(255, 255, 255, 0.1); border: none; border-radius: 50%; width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; cursor: pointer; backdrop-filter: blur(8px);">
|
||||
<i data-lucide="chevron-left" style="width: 24px; height: 24px; color: white;"></i>
|
||||
</button>
|
||||
|
||||
<button id="nextImageBtn" style="position: absolute; right: var(--space-lg); top: 50%; transform: translateY(-50%); background: rgba(255, 255, 255, 0.1); border: none; border-radius: 50%; width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; cursor: pointer; backdrop-filter: blur(8px);">
|
||||
<i data-lucide="chevron-right" style="width: 24px; height: 24px; color: white;"></i>
|
||||
</button>
|
||||
|
||||
<!-- Image -->
|
||||
<img id="viewerModalImage" src="" alt="查看图像" style="max-width: 90%; max-height: 90%; object-fit: contain; border-radius: var(--border-radius);">
|
||||
|
||||
<!-- Actions -->
|
||||
<div style="position: absolute; bottom: var(--space-lg); left: 50%; transform: translateX(-50%); display: flex; gap: var(--space-sm);">
|
||||
<button class="btn btn-secondary" id="viewerDownloadImage">
|
||||
<i data-lucide="download" style="width: 16px; height: 16px;"></i>
|
||||
下载
|
||||
</button>
|
||||
<button class="btn btn-secondary" id="viewerDeleteImage" style="background: var(--accent-danger);">
|
||||
<i data-lucide="trash-2" style="width: 16px; height: 16px;"></i>
|
||||
删除
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Initialize Lucide icons
|
||||
lucide.createIcons();
|
||||
|
||||
// UI State Management
|
||||
let settingsVisible = false;
|
||||
let currentImages = [];
|
||||
let currentImageIndex = 0;
|
||||
|
||||
// Settings toggle
|
||||
document.getElementById('settingsBtn').addEventListener('click', function() {
|
||||
const panel = document.getElementById('settingsPanel');
|
||||
settingsVisible = !settingsVisible;
|
||||
panel.style.display = settingsVisible ? 'block' : 'none';
|
||||
});
|
||||
|
||||
// File upload handling
|
||||
const dropZone = document.getElementById('dropZone');
|
||||
const imageInput = document.getElementById('imageInput');
|
||||
const imagePreview = document.getElementById('imagePreview');
|
||||
|
||||
dropZone.addEventListener('dragover', function(e) {
|
||||
e.preventDefault();
|
||||
dropZone.classList.add('drag-over');
|
||||
});
|
||||
|
||||
dropZone.addEventListener('dragleave', function(e) {
|
||||
e.preventDefault();
|
||||
dropZone.classList.remove('drag-over');
|
||||
});
|
||||
|
||||
dropZone.addEventListener('drop', function(e) {
|
||||
e.preventDefault();
|
||||
dropZone.classList.remove('drag-over');
|
||||
const files = e.dataTransfer.files;
|
||||
handleFiles(files);
|
||||
});
|
||||
|
||||
imageInput.addEventListener('change', function(e) {
|
||||
handleFiles(e.target.files);
|
||||
});
|
||||
|
||||
function handleFiles(files) {
|
||||
if (files.length === 0) return;
|
||||
|
||||
imagePreview.style.display = 'block';
|
||||
imagePreview.innerHTML = '';
|
||||
|
||||
Array.from(files).forEach((file, index) => {
|
||||
if (file.type.startsWith('image/')) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'image-preview-item';
|
||||
item.innerHTML = `
|
||||
<img src="${e.target.result}" alt="${file.name}" class="image-preview-thumb">
|
||||
<div class="image-preview-info">
|
||||
<div class="image-preview-name">${file.name}</div>
|
||||
<div class="image-preview-size">${(file.size / 1024).toFixed(1)} KB</div>
|
||||
</div>
|
||||
<button onclick="removeImage(${index})" style="background: none; border: none; color: var(--accent-danger); cursor: pointer;">
|
||||
<i data-lucide="x" style="width: 16px; height: 16px;"></i>
|
||||
</button>
|
||||
`;
|
||||
imagePreview.appendChild(item);
|
||||
lucide.createIcons();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function removeImage(index) {
|
||||
// Implementation for removing images
|
||||
console.log('Remove image:', index);
|
||||
}
|
||||
|
||||
// Loading state management
|
||||
function showLoading() {
|
||||
document.getElementById('previewEmpty').style.display = 'none';
|
||||
document.getElementById('previewLoading').style.display = 'flex';
|
||||
}
|
||||
|
||||
function hideLoading() {
|
||||
document.getElementById('previewEmpty').style.display = 'block';
|
||||
document.getElementById('previewLoading').style.display = 'none';
|
||||
}
|
||||
|
||||
// Image viewer modal
|
||||
function openImageViewer(imageSrc, index) {
|
||||
currentImageIndex = index;
|
||||
document.getElementById('viewerModalImage').src = imageSrc;
|
||||
document.getElementById('imageViewerModal').style.display = 'block';
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closeImageViewer() {
|
||||
document.getElementById('imageViewerModal').style.display = 'none';
|
||||
document.body.style.overflow = 'auto';
|
||||
}
|
||||
|
||||
// Mobile sidebar
|
||||
function openMobileSidebar() {
|
||||
document.getElementById('sidebar').classList.add('open');
|
||||
document.getElementById('sidebarOverlay').classList.add('show');
|
||||
}
|
||||
|
||||
function closeMobileSidebar() {
|
||||
document.getElementById('sidebar').classList.remove('open');
|
||||
document.getElementById('sidebarOverlay').classList.remove('show');
|
||||
}
|
||||
|
||||
// Placeholder functions for existing functionality
|
||||
function testConnection() {
|
||||
console.log('Testing connection...');
|
||||
// Update status indicator
|
||||
const statusDot = document.querySelector('#connectionStatus');
|
||||
const statusText = document.querySelector('#connectionText');
|
||||
statusDot.className = 'status-dot status-connecting';
|
||||
statusText.textContent = '连接中...';
|
||||
|
||||
// Simulate connection test
|
||||
setTimeout(() => {
|
||||
statusDot.className = 'status-dot status-connected';
|
||||
statusText.textContent = '已连接';
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function sendMessage() {
|
||||
const message = document.getElementById('messageInput').value.trim();
|
||||
if (!message) {
|
||||
alert('请输入生成提示词');
|
||||
return;
|
||||
}
|
||||
showLoading();
|
||||
console.log('Sending single message:', message);
|
||||
}
|
||||
|
||||
function sendBatchMessage() {
|
||||
const message = document.getElementById('messageInput').value.trim();
|
||||
const count = document.getElementById('batchCount').value;
|
||||
if (!message) {
|
||||
alert('请输入生成提示词');
|
||||
return;
|
||||
}
|
||||
showLoading();
|
||||
console.log('Sending batch message:', message, 'Count:', count);
|
||||
}
|
||||
|
||||
// Initialize app object for compatibility
|
||||
const app = {
|
||||
clearStorage: function() {
|
||||
if (confirm('确定要清除所有存储数据吗?')) {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
console.log('Storage cleared');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Mobile menu toggle
|
||||
if (window.innerWidth <= 768) {
|
||||
const headerTitle = document.querySelector('.header-title');
|
||||
headerTitle.style.cursor = 'pointer';
|
||||
headerTitle.addEventListener('click', openMobileSidebar);
|
||||
}
|
||||
|
||||
// Update mobile layout on resize
|
||||
window.addEventListener('resize', function() {
|
||||
if (window.innerWidth > 768) {
|
||||
closeMobileSidebar();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user