vdkch/index.html

271 lines
8.4 KiB
HTML
Raw Permalink Normal View History

2025-02-10 15:53:52 +03:00
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FutaClone</title>
<!-- Добавляем библиотеку для визуализации графа -->
<script src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<style>
/* Добавляем новые стили */
#network {
width: 100%;
height: 600px;
border: 1px solid #800;
background: white;
}
.hidden { display: none; }
#greeting { text-align: center; padding: 20px; }
#graphContainer { margin-top: 20px; }
/* Стили в духе традиционных имиджборд */
body {
background-color: #F0E0D6;
font-family: Arial, sans-serif;
margin: 20px;
max-width: 800px;
margin-left: auto;
margin-right: auto;
}
.post-form {
background: #FFF;
border: 1px solid #800;
padding: 15px;
margin-bottom: 20px;
}
.post {
background: #FFF;
border: 1px solid #800;
padding: 15px;
margin-bottom: 10px;
}
.post img {
max-width: 200px;
max-height: 200px;
margin-top: 10px;
}
input, textarea, button {
margin: 5px;
padding: 5px;
}
.hidden {
display: none;
}
.preview-image {
max-width: 150px;
margin: 10px 0;
}
</style>
</head>
<body>
<!-- Добавляем новые блоки -->
<div id="greeting" class="hidden">
<h2>Отправьте первое сообщение, чтобы начать</h2>
</div>
<div id="graphContainer" class="hidden">
<h2>Древо мыслей</h2>
<div id="network"></div>
</div>
<!-- Форма создания поста -->
<div class="post-form">
<h2>Новый пост</h2>
<form id="postForm">
<textarea id="postText" rows="4" cols="50" placeholder="Текст поста"></textarea><br>
<input type="file" id="imageInput" accept="image/*"><br>
<div id="imagePreview" class="hidden"></div>
<button type="submit">Отправить</button>
</form>
</div>
<!-- Форма поиска (только текст) -->
<div class="post-form">
<h2>Поиск</h2>
<input type="text" id="searchText" placeholder="Текст для поиска">
<button onclick="searchPosts()">Искать</button>
</div>
<!-- Список постов -->
<div id="postsContainer"></div>
<script>
// Базовый URL бэкенда
const API_URL = 'http://localhost:8000';
// Обработка отправки поста (оставляем без изменений)
document.getElementById('postForm').addEventListener('submit', async (e) => {
e.preventDefault();
const text = document.getElementById('postText').value;
const fileInput = document.getElementById('imageInput');
const formData = new FormData();
if (text) formData.append('text', text);
if (fileInput.files[0]) formData.append('image', fileInput.files[0]);
try {
const response = await fetch(`${API_URL}/posts/`, {
method: 'POST',
body: formData
});
if (response.ok) {
const postData = await response.json();
// Сохраняем вектор в localStorage
localStorage.setItem('userVector', JSON.stringify(postData.vector));
checkUserVector();
loadPosts();
document.getElementById('postForm').reset();
document.getElementById('imagePreview').classList.add('hidden');
} else {
console.error('Error:', error);
}
} catch (error) {
console.error('Error:', error);
}
});
// Превью изображения перед загрузкой
document.getElementById('imageInput').addEventListener('change', function(e) {
const preview = document.getElementById('imagePreview');
if (this.files && this.files[0]) {
const reader = new FileReader();
reader.onload = function(e) {
preview.innerHTML = `<img src="${e.target.result}" class="preview-image">`;
preview.classList.remove('hidden');
}
reader.readAsDataURL(this.files[0]);
}
});
// Загрузка и отображение постов (оставляем без изменений)
async function loadPosts() {
try {
const response = await fetch(`${API_URL}/posts/`);
const posts = await response.json();
const container = document.getElementById('postsContainer');
container.innerHTML = posts.map(post => `
<div class="post">
<div class="post-meta">#${post.id} - ${new Date(post.created_at).toLocaleString()}</div>
${post.text ? `<div class="post-text">${post.text}</div>` : ''}
${post.image ? `<img src="${API_URL}/${post.image}" />` : ''}
</div>
`).join('');
} catch (error) {
console.error('Error:', error);
}
}
// Обновлённая функция поиска, использующая GET-запрос
async function searchPosts() {
const text = document.getElementById('searchText').value;
// Формируем строку запроса, если введён текст
const query = text ? `?text=${encodeURIComponent(text)}` : '';
try {
const response = await fetch(`${API_URL}/search/${query}`, {
method: 'GET'
});
if (!response.ok) {
throw new Error('Запрос поиска завершился с ошибкой');
}
const results = await response.json();
alert('Найдено постов: ' + results.length);
// Здесь можно добавить отображение результатов поиска в интерфейсе
} catch (error) {
console.error('Error during search:', error);
}
}
// Первоначальная загрузка постов
loadPosts();
// Новая функция проверки вектора
function checkUserVector() {
const hasVector = localStorage.getItem('userVector') !== null;
document.getElementById('greeting').classList.toggle('hidden', hasVector);
document.getElementById('graphContainer').classList.toggle('hidden', !hasVector);
if (hasVector) {
loadUserTree();
} else {
loadPosts();
}
}
// Функция загрузки дерева
async function loadUserTree() {
const userVector = JSON.parse(localStorage.getItem('userVector'));
if (!userVector) return;
try {
const response = await fetch(`${API_URL}/posts/tree`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ vector: userVector }),
});
const posts = await response.json();
renderGraph(posts);
} catch (error) {
console.error('Error loading tree:', error);
}
}
// Визуализация графа
function renderGraph(posts) {
const container = document.getElementById('network');
const nodes = [];
const edges = [];
posts.forEach((post, index) => {
nodes.push({
id: post.id,
label: post.text || '[Изображение]',
image: post.image ? `${API_URL}/${post.image}` : 'https://via.placeholder.com/100',
shape: 'circularImage',
size: 25
});
if (index > 0) {
edges.push({
from: posts[index-1].id,
to: post.id,
arrows: 'to',
smooth: { type: 'curvedCW' }
});
}
});
const data = { nodes, edges };
const options = {
nodes: {
borderWidth: 2,
color: {
border: '#800',
background: '#F0E0D6'
},
font: { size: 14 }
},
edges: {
color: '#800',
width: 2
},
physics: {
stabilization: true,
barnesHut: {
gravitationalConstant: -2000,
springLength: 200
}
}
};
new vis.Network(container, data, options);
}
// Инициализация при загрузке страницы
checkUserVector();
</script>
</body>
</html>