DocuHubAI / index.html
sky-meilin's picture
Upload folder using huggingface_hub
da8a140 verified
Raw
History Blame Contribute Delete
25.8 kB
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>AI Dokumenten Hub</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@300;400;500;600;700&display=swap" rel="stylesheet">
<!-- Phosphor Icons für moderne Icons -->
<script src="https://unpkg.com/@phosphor-icons/web"></script>
<style>
:root {
/* Farbpalette - Modern & Professional */
--primary: #6366f1;
--primary-dark: #4f46e5;
--secondary: #ec4899;
--bg-dark: #0f172a;
--bg-card: #1e293b;
--bg-hover: #334155;
--text-main: #f8fafc;
--text-muted: #94a3b8;
--border: #334155;
--success: #10b981;
--glass: rgba(30, 41, 59, 0.7);
/* Layout */
--nav-height: 70px;
--header-height: 60px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
-webkit-tap-highlight-color: transparent;
}
body {
font-family: 'Inter', sans-serif;
background-color: var(--bg-dark);
color: var(--text-main);
height: 100vh;
overflow: hidden; /* App-like feel */
display: flex;
flex-direction: column;
}
/* --- Header --- */
header {
height: var(--header-height);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
background: rgba(15, 23, 42, 0.95);
border-bottom: 1px solid var(--border);
z-index: 100;
}
.brand {
font-weight: 700;
font-size: 1.2rem;
display: flex;
align-items: center;
gap: 10px;
}
.brand i {
color: var(--primary);
font-size: 1.5rem;
}
.built-with {
font-size: 0.75rem;
color: var(--text-muted);
text-decoration: none;
opacity: 0.7;
transition: opacity 0.2s;
}
.built-with:hover {
opacity: 1;
color: var(--primary);
}
/* --- Main Layout --- */
main {
flex: 1;
position: relative;
overflow: hidden;
}
.view-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow-y: auto;
padding: 20px;
padding-bottom: 100px; /* Space for FAB and Nav */
opacity: 0;
pointer-events: none;
transform: translateY(20px);
transition: opacity 0.3s ease, transform 0.3s ease;
display: none; /* Helper to ensure visibility */
}
.view-container.active {
opacity: 1;
pointer-events: all;
transform: translateY(0);
display: block;
}
h2 {
font-size: 1.5rem;
margin-bottom: 20px;
font-weight: 600;
}
/* --- Upload Area (Drag & Drop) --- */
.upload-zone {
border: 2px dashed var(--border);
border-radius: 16px;
padding: 40px 20px;
text-align: center;
background: rgba(255, 255, 255, 0.02);
transition: all 0.3s ease;
cursor: pointer;
margin-bottom: 20px;
}
.upload-zone.drag-over {
border-color: var(--primary);
background: rgba(99, 102, 241, 0.1);
}
.upload-icon {
font-size: 3rem;
color: var(--text-muted);
margin-bottom: 15px;
}
.upload-text {
color: var(--text-main);
font-weight: 500;
}
.upload-subtext {
color: var(--text-muted);
font-size: 0.9rem;
margin-top: 5px;
}
#fileInput {
display: none;
}
/* --- Document List --- */
.doc-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
gap: 15px;
}
.doc-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 15px;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
transition: transform 0.2s, box-shadow 0.2s;
position: relative;
}
.doc-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
border-color: var(--primary);
}
.doc-icon {
font-size: 2rem;
margin-bottom: 10px;
color: var(--primary);
}
.doc-name {
font-size: 0.9rem;
font-weight: 500;
margin-bottom: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
}
.doc-meta {
font-size: 0.75rem;
color: var(--text-muted);
}
.doc-actions {
position: absolute;
top: 5px;
right: 5px;
opacity: 0;
transition: opacity 0.2s;
}
.doc-card:hover .doc-actions {
opacity: 1;
}
.btn-icon {
background: var(--bg-hover);
border: none;
color: var(--text-main);
border-radius: 50%;
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.btn-icon:hover {
background: var(--secondary);
}
/* --- AI Integration Hub --- */
.ai-grid {
display: grid;
grid-template-columns: 1fr;
gap: 15px;
}
.ai-card {
background: linear-gradient(135deg, var(--bg-card), rgba(30, 41, 59, 0.5));
border: 1px solid var(--border);
border-radius: 16px;
padding: 20px;
display: flex;
align-items: center;
gap: 15px;
transition: transform 0.2s;
}
.ai-card:active {
transform: scale(0.98);
}
.ai-avatar {
width: 50px;
height: 50px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
color: white;
}
.ai-info {
flex: 1;
}
.ai-name {
font-weight: 600;
margin-bottom: 2px;
}
.ai-status {
font-size: 0.8rem;
display: flex;
align-items: center;
gap: 5px;
}
.status-dot {
width: 8px;
height: 8px;
background-color: var(--success);
border-radius: 50%;
box-shadow: 0 0 8px var(--success);
}
.btn-primary {
background: var(--primary);
color: white;
border: none;
padding: 10px 20px;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
display: flex;
align-items: center;
gap: 8px;
}
.btn-primary:hover {
background: var(--primary-dark);
}
/* --- Floating Action Button (FAB) --- */
.fab {
position: fixed;
bottom: calc(var(--nav-height) + 20px);
right: 20px;
width: 56px;
height: 56px;
border-radius: 50%;
background: var(--primary);
color: white;
border: none;
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
cursor: pointer;
z-index: 90;
transition: transform 0.2s, background 0.2s;
}
.fab:hover {
transform: scale(1.1);
background: var(--primary-dark);
}
/* --- Bottom Navigation --- */
.bottom-nav {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: var(--nav-height);
background: var(--bg-card);
border-top: 1px solid var(--border);
display: flex;
justify-content: space-around;
align-items: center;
z-index: 100;
}
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: var(--text-muted);
text-decoration: none;
font-size: 0.75rem;
gap: 4px;
padding: 10px 20px;
transition: color 0.2s;
background: none;
border: none;
cursor: pointer;
width: 100%;
}
.nav-item i {
font-size: 1.5rem;
}
.nav-item.active {
color: var(--primary);
}
/* --- Toast Notification --- */
.toast-container {
position: fixed;
top: 80px;
right: 20px;
z-index: 1000;
display: flex;
flex-direction: column;
gap: 10px;
}
.toast {
background: var(--bg-card);
border-left: 4px solid var(--primary);
padding: 15px 20px;
border-radius: 4px;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
display: flex;
align-items: center;
gap: 10px;
animation: slideIn 0.3s ease;
min-width: 250px;
}
@keyframes slideIn {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
/* --- Modal --- */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(5px);
z-index: 200;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
}
.modal-overlay.open {
opacity: 1;
pointer-events: all;
}
.modal {
background: var(--bg-card);
width: 90%;
max-width: 400px;
border-radius: 16px;
padding: 25px;
border: 1px solid var(--border);
transform: scale(0.9);
transition: transform 0.3s;
}
.modal-overlay.open .modal {
transform: scale(1);
}
.modal h3 {
margin-bottom: 15px;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
color: var(--text-muted);
font-size: 0.9rem;
}
.form-group input, .form-group select, .form-group textarea {
width: 100%;
background: var(--bg-dark);
border: 1px solid var(--border);
padding: 12px;
border-radius: 8px;
color: var(--text-main);
font-family: inherit;
}
.modal-actions {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 20px;
}
.btn-secondary {
background: transparent;
border: 1px solid var(--border);
color: var(--text-main);
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
}
/* --- Responsive Tweaks --- */
@media (min-width: 768px) {
.doc-grid {
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
}
.fab {
width: 60px;
height: 60px;
}
}
</style>
</head>
<body>
<!-- Header -->
<header>
<div class="brand">
<i class="ph ph-files"></i>
<span>DocuHub AI</span>
</div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="built-with">
Built with anycoder
</a>
</header>
<!-- Main Content Area -->
<main>
<!-- View 1: Document Storage -->
<section id="view-storage" class="view-container active">
<h2>Meine Dokumente</h2>
<div class="upload-zone" id="dropZone">
<i class="ph ph-cloud-arrow-up upload-icon"></i>
<div class="upload-text">Hierher ziehen oder tippen</div>
<div class="upload-subtext">PDF, JPG, PNG, TXT</div>
<input type="file" id="fileInput" multiple>
</div>
<div class="doc-grid" id="docGrid">
<!-- Documents will be injected here via JS -->
</div>
</section>
<!-- View 2: AI Integration Hub -->
<section id="view-ai" class="view-container">
<h2>AI Integration Hub</h2>
<p style="color: var(--text-muted); margin-bottom: 20px;">
Verbinden Sie KI-Modelle für automatisierte Analyse und Zusammenfassung.
</p>
<div class="ai-grid" id="aiGrid">
<!-- AI Cards will be injected here via JS -->
</div>
</section>
<!-- View 3: Settings -->
<section id="view-settings" class="view-container">
<h2>Einstellungen</h2>
<div class="ai-card" style="cursor: default;">
<div class="ai-avatar" style="background: var(--bg-hover);">
<i class="ph ph-gear"></i>
</div>
<div class="ai-info">
<div class="ai-name">App Version</div>
<div class="ai-status">v1.0.0 (Stable)</div>
</div>
</div>
<div class="ai-card" style="cursor: default;">
<div class="ai-avatar" style="background: var(--bg-hover);">
<i class="ph ph-database"></i>
</div>
<div class="ai-info">
<div class="ai-name">Speicherstatus</div>
<div class="ai-status">45% verbraucht</div>
</div>
</div>
</section>
</main>
<!-- Floating Action Button (Add Document) -->
<button class="fab" id="fabAdd" onclick="triggerFileUpload()">
<i class="ph ph-plus"></i>
</button>
<!-- Bottom Navigation -->
<nav class="bottom-nav">
<button class="nav-item active" onclick="switchView('view-storage', this)">
<i class="ph ph-files"></i>
<span>Dokumente</span>
</button>
<button class="nav-item" onclick="switchView('view-ai', this)">
<i class="ph ph-robot"></i>
<span>AI Hub</span>
</button>
<button class="nav-item" onclick="switchView('view-settings', this)">
<i class="ph ph-gear"></i>
<span>Einstellungen</span>
</button>
</nav>
<!-- Modal for Adding AI Connection -->
<div class="modal-overlay" id="aiModal">
<div class="modal">
<h3>Neue KI-Verbindung</h3>
<div class="form-group">
<label>Name des Assistenten</label>
<input type="text" id="aiName" placeholder="z.B. Analyse-Bot">
</div>
<div class="form-group">
<label>API Endpoint / Model</label>
<select id="aiModel">
<option value="openai">OpenAI GPT-4</option>
<option value="anthropic">Claude 3</option>
<option value="local">Lokales Model (Ollama)</option>
</select>
</div>
<div class="modal-actions">
<button class="btn-secondary" onclick="closeModal()">Abbrechen</button>
<button class="btn-primary" onclick="saveAIConnection()">Verbinden</button>
</div>
</div>
</div>
<!-- Toast Container -->
<div class="toast-container" id="toastContainer"></div>
<script>
// --- State Management ---
let documents = [
{ id: 1, name: "Projekt_Plan.pdf", type: "pdf", date: "Heute" },
{ id: 2, name: "Rechnung_123.jpg", type: "image", date: "Gestern" },
{ id: 3, name: "Meeting_Notizen.txt", type: "text", date: "01.10.2023" }
];
let aiConnections = [
{ id: 1, name: "ChatGPT", model: "GPT-4", active: true },
{ id: 2, name: "Claude", model: "Claude 3 Opus", active: false }
];
// --- DOM Elements ---
const dropZone = document.getElementById('dropZone');
const fileInput = document.getElementById('fileInput');
const docGrid = document.getElementById('docGrid');
const aiGrid = document.getElementById('aiGrid');
const aiModal = document.getElementById('aiModal');
// --- Initialization ---
document.addEventListener('DOMContentLoaded', () => {
renderDocuments();
renderAIConnections();
setupDragAndDrop();
});
// --- Navigation Logic ---
function switchView(viewId, navBtn) {
// Hide all views
document.querySelectorAll('.view-container').forEach(el => {
el.classList.remove('active');
});
// Show target view
document.getElementById(viewId).classList.add('active');
// Update Nav Icons
document.querySelectorAll('.nav-item').forEach(el => {
el.classList.remove('active');
});
if(navBtn) navBtn.classList.add('active');
}
// --- File Upload Logic ---
function triggerFileUpload() {
fileInput.click();
}
function setupDragAndDrop() {
// Prevent default browser behavior
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, preventDefaults, false);
document.body.addEventListener(eventName, preventDefaults, false);
});
// Highlight drop zone
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, () => dropZone.classList.add('drag-over'), false);
});
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, () => dropZone.classList.remove('drag-over'), false);
});
// Handle Drop
dropZone.addEventListener('drop', handleDrop, false);
// Handle Click to Upload
dropZone.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', (e) => handleFiles(e.target.files));
}
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
handleFiles(files);
}
function handleFiles(files) {
([...files]).forEach(file => {
// Check if it's a file type we care about
if(file.type) {
const type = file.type.split('/')[0];
const newDoc = {
id: Date.now(),
name: file.name,
type: type === 'image' ? 'image' : 'file',
date: "Gerade eben"
};
documents.unshift(newDoc); // Add to top
showToast(`Dokument "${file.name}" hochgeladen`);
}
});
renderDocuments();
}
// --- Rendering Logic ---
function renderDocuments() {
docGrid.innerHTML = '';
documents.forEach(doc => {
let iconClass = 'ph-file';
let color = 'var(--text-muted)';
if(doc.type === 'pdf') { iconClass = 'ph-file-pdf'; color = '#ef4444'; }
if(doc.type === 'image') { iconClass = 'ph-image'; color = '#ec4899'; }
const card = document.createElement('div');
card.className = 'doc-card';
card.innerHTML = `
<div class="doc-actions">
<button class="btn-icon" onclick="deleteDoc(${doc.id})">
<i class="ph ph-trash"></i>
</button>
</div>
<i class="ph ${iconClass} doc-icon" style="color: ${color}"></i>
<div class="doc-name" title="${doc.name}">${doc.name}</div>
<div class="doc-meta">${doc.date}</div>
`;
docGrid.appendChild(card);
});
}
function deleteDoc(id) {
documents = documents.filter(d => d.id !== id);
renderDocuments();
showToast('Dokument gelöscht');
}
function renderAIConnections() {
aiGrid.innerHTML = '';
aiConnections.forEach(ai => {
const card = document.createElement('div');
card.className = 'ai-card';
// Determine Icon based on provider
let icon = 'ph-robot';
let bg = 'var(--primary)';
if(ai.model.includes('Claude')) { icon = 'ph-brain'; bg = '#d97706'; }
if(ai.model.includes('Lokal')) { icon = 'ph-cpu'; bg = '#059669'; }
card.innerHTML = `
<div class="ai-avatar" style="background: ${bg}">
<i class="ph ${icon}"></i>
</div>
<div class="ai-info">
<div class="ai-name">${ai.name}</div>
<div class="ai-status">
<div class="status-dot"></div>
${ai.active ? 'Aktiv' : 'Inaktiv'}
</div>
</div>
<button class="btn-icon" onclick="toggleAI(${ai.id})">
<i class="ph ${ai.active ? 'ph-power' : 'ph-power'}"></i>
</button>
<button class="btn-icon" style="background:transparent; opacity:0.5; pointer-events:none">
<i class="ph ph-dots-three-vertical"></i>
</button>
`;
aiGrid.appendChild(card);
});
}
// --- AI Connection Logic ---
function openModal() {
aiModal.classList.add('open');
}
function closeModal() {
aiModal.classList.remove('open');
}
function saveAIConnection() {
const name = document.getElementById('aiName').value;
const model = document.getElementById('aiModel').value;
if(!name) {
showToast('Bitte geben Sie einen Namen ein');
return;
}
aiConnections.push({
id: Date.now(),
name: name,
model: model,
active: true
});
renderAIConnections();
closeModal();
showToast(`KI-Verbindung "${name}" erstellt`);
}
function toggleAI(id) {
const ai = aiConnections.find(a => a.id === id);
if(ai) {
ai.active = !ai.active;
renderAIConnections();
showToast(`KI "${ai.name}" ${ai.active ? 'aktiviert' : 'deaktiviert'}`);
}
}
// --- Utilities ---
function showToast(message) {
const container = document.getElementById('toastContainer');
const toast = document.createElement('div');
toast.className = 'toast';
toast.innerHTML = `<i class="ph ph-check-circle" style="color: var(--success); font-size: 1.2rem;"></i> ${message}`;
container.appendChild(toast);
// Remove after 3 seconds
setTimeout(() => {
toast.style.opacity = '0';
toast.style.transform = 'translateX(100%)';
setTimeout(() => toast.remove(), 300);
}, 3000);
}
</script>
</body>
</html>