sciencesproject / test.html
ssbagpcm's picture
Upload folder using huggingface_hub
960bb66 verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>#⨜.৻.Ι.Ξ.Π.৻.Ξ.⨜</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<style>
body, html {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
overflow: hidden;
font-family: Arial, sans-serif;
background-color: #000000;
color: #ffffff;
cursor: url('./image/cursor.png'), auto;
}
#container {
display: flex;
width: 300vw;
height: 100vh;
transition: transform 1s ease;
}
.main-section {
width: 100vw;
height: 100vh;
flex-shrink: 0;
transition: opacity 1s ease, transform 1s ease, filter 1s ease;
opacity: 0;
transform: scale(0.8) rotateY(10deg);
filter: brightness(70%) blur(10px);
overflow: hidden;
}
#left-section {
position: relative;
overflow: hidden;
}
#vertical-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 300vh;
transition: transform 1s ease;
}
.vertical-section {
width: 100%;
height: 100vh;
transition: opacity 1s ease, transform 1s ease, filter 1s ease;
opacity: 0;
transform: scale(0.8) rotateX(10deg);
filter: brightness(70%) blur(10px);
}
.grid-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
linear-gradient(to right, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
background-size: 50px 50px;
pointer-events: none;
z-index: -1;
animation: gridPulse 10s infinite alternate;
}
@keyframes gridPulse {
0% { opacity: 0.5; }
100% { opacity: 1; }
}
</style>
</head>
<body>
<div id="container">
<div id="left-section" class="main-section">
<div id="vertical-container">
<div class="vertical-section">
<!-- solarsystem.html content -->
<div id="solar-system-content">
<style>
body { overflow: hidden; margin: 0; cursor: none; }
</style>
<script src="./js/solarSystem.js" type="module"></script>
<script>
document.addEventListener('keydown', (event) => {
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
event.preventDefault();
window.parent.postMessage({ key: event.key }, '*');
}
});
</script>
</div>
</div>
<div class="vertical-section">
<!-- 1.html content -->
<div id="model-viewer-1">
<style>
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background-color: black;
overflow: hidden;
}
model-viewer {
width: 100%;
height: 100%;
}
</style>
<model-viewer src="3D-models/iss.glb" alt="A 3D model" auto-rotate camera-controls></model-viewer>
<script>
document.addEventListener('keydown', (event) => {
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
event.preventDefault();
window.parent.postMessage({ key: event.key }, '*');
}
});
</script>
</div>
</div>
<div class="vertical-section">
<!-- 2.html content -->
<div id="model-viewer-2">
<style>
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background-color: black;
overflow: hidden;
}
model-viewer {
width: 100%;
height: 100%;
}
</style>
<model-viewer src="3D-models/apatite.glb" alt="A 3D model" auto-rotate camera-controls></model-viewer>
<script>
document.addEventListener('keydown', (event) => {
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
event.preventDefault();
window.parent.postMessage({ key: event.key }, '*');
}
});
</script>
</div>
</div>
</div>
</div>
<div id="middle-section" class="main-section">
<!-- presentation.html content -->
<div id="presentation-content">
<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto+Condensed:ital,wght@0,100..900;1,100..900&display=swap');
html, body {
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
cursor: url('./image/cursor.png'), auto !important;
user-select: none;
}
body {
font-family: 'Poppins', sans-serif;
background-color: #000000;
color: #ffffff;
display: flex;
flex-direction: column;
min-height: 100vh;
}
.content-wrapper {
flex: 1;
overflow-y: auto;
scrollbar-width: none;
-ms-overflow-style: none;
}
.content-wrapper::-webkit-scrollbar {
display: none;
}
.top-bar {
width: 100%;
background-color: #000000;
padding: 20px 0;
position: sticky;
top: 0;
z-index: 100;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 2px 10px rgba(255,255,255,0.1);
}
.search-container {
width: 80%;
max-width: 600px;
display: flex;
align-items: center;
background-color: #000000;
border-radius: 30px;
padding: 5px 15px;
border: 1px solid #333;
transition: all 0.3s ease;
}
.search-container:focus-within {
border-color: #555;
box-shadow: 0 0 10px rgba(255,255,255,0.1);
}
input[type="text"] {
flex-grow: 1;
background-color: transparent;
border: none;
color: #ffffff;
font-family: 'Roboto Condensed', sans-serif;
font-size: 18px;
padding: 12px;
outline: none;
cursor: url('./image/cursor.png'), text !important;
}
input[type="text"]::placeholder {
color: #555;
}
.search-icon {
width: 24px;
height: 24px;
fill: #555;
opacity: 0.8;
transition: opacity 0.3s ease, transform 0.3s ease;
}
.search-icon:hover {
opacity: 1;
cursor: url('./image/cursor.png'), pointer !important;
transform: scale(1.1);
}
.content {
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
padding: 40px 20px;
}
h1 {
font-weight: 300;
text-align: center;
font-size: 3.5em;
margin: 0 0 20px 0;
letter-spacing: 3px;
text-transform: uppercase;
}
.image-gallery {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
max-width: 1200px;
margin: 0 auto;
}
.image-container {
position: relative;
width: calc(33.33% - 20px);
aspect-ratio: 1 / 1;
overflow: hidden;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0,255,255,0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.image-container:hover {
transform: scale(1.05);
box-shadow: 0 6px 15px rgba(0,255,255,0.2);
}
.image-container img {
width: 100%;
height: 100%;
object-fit: cover;
transition: opacity 0.3s ease;
pointer-events: none;
}
.image-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.2));
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
transition: opacity 0.3s ease;
}
.image-container:hover .image-overlay {
opacity: 1;
}
.image-title {
color: #ffffff;
font-size: 1.2em;
text-align: center;
padding: 10px;
background-color: rgba(0,0,0,0.7);
border-radius: 5px;
}
#search-results {
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
width: 80%;
max-width: 600px;
background-color: #000000;
border: 1px solid #333;
border-top: none;
border-radius: 0 0 15px 15px;
max-height: 0;
overflow: hidden;
z-index: 1000;
transition: max-height 0.3s ease-out, opacity 0.3s ease-out;
opacity: 0;
}
#search-results.active {
max-height: 300px;
opacity: 1;
overflow-y: auto;
}
#search-results::-webkit-scrollbar {
display: none;
}
#search-results div {
padding: 10px;
cursor: pointer;
transition: background-color 0.3s ease;
}
#search-results div:hover {
background-color: #333;
}
.popup {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.8);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
opacity: 0;
transition: opacity 0.3s ease;
}
.popup.show {
opacity: 1;
}
.popup-content {
background-color: black;
color: #fff;
font-family: 'Poppins', sans-serif;
padding: 30px;
border-radius: 5px;
width: 90%;
height: 90%;
overflow: hidden;
position: relative;
transform: scale(0.7);
transition: transform 0.3s ease;
background-image:
linear-gradient(to right, rgba(128, 128, 128, 0.1) 1px, transparent 1px),
linear-gradient(to bottom, rgba(128, 128, 128, 0.1) 1px, transparent 1px);
background-size: 50px 50px;
}
.popup.show .popup-content {
transform: scale(1);
}
.popup-content .markdown-content {
font-family: 'Poppins', sans-serif;
white-space: pre-wrap;
word-wrap: break-word;
max-height: 100%;
overflow-y: auto;
scrollbar-width: none;
-ms-overflow-style: none;
font-size: 16px;
line-height: 1.6;
}
.popup-content .markdown-content::-webkit-scrollbar {
display: none;
}
.close-button {
position: absolute;
top: 10px;
right: 10px;
background: none;
border: none;
color: #fff;
font-size: 24px;
cursor: pointer;
}
::selection {
background-color: #98FF98;
color: #000;
}
* {
cursor: url('./image/cursor.png'), auto !important;
user-select: none;
}
input[type="text"], textarea {
cursor: url('./image/cursor.png'), text !important;
}
input[type="text"], textarea {
caret-color: transparent;
}
input[type="text"]::after, textarea::after {
content: '|';
position: absolute;
color: #ffffff;
animation: blink 1s step-end infinite;
}
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
input[type="text"]::selection {
background-color: #98FF98;
color: #000000;
}
</style>
<div class="content-wrapper">
<div class="top-bar">
<div class="search-container">
<input type="text" id="search-input" placeholder="" spellcheck="false" autocomplete="off">
<svg class="search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
</svg>
</div>
<div id="search-results"></div>
</div>
<div class="content">
<h1>#⨜.৻.Ι.Ξ.Π.৻.Ξ.⨜</h1>
<div class="image-gallery">
<div class="image-container">
<img src="./image/europeanforest.webp" alt="Galaxie bleue et verte dans l'espace">
<div class="image-overlay">
<div class="image-title">European Forest</div>
</div>
</div>
<div class="image-container">
<img src="./image/planet extra.jpeg" alt="Grande planète vue de l'espace">
<div class="image-overlay">
<div class="image-title">Extra-terrestrial planet</div>
</div>
</div>
<div class="image-container">
<img src="./image/graphicalpaint.webp" alt="Forêt bleue et verte vue du dessus">
<div class="image-overlay">
<div class="image-title">Graphical draw</div>
</div>
</div>
<div class="image-container">
<img src="./image/blueneb.webp" alt="Nébuleuse cosmique bleue">
<div class="image-overlay">
<div class="image-title">Nebula</div>
</div>
</div>
<div class="image-container">
<img src="./image/aurore.webp" alt="Aurores boréales">
<div class="image-overlay">
<div class="image-title">Northern Lights</div>
</div>
</div>
<div class="image-container">
<img src="./image/Brazil.webp" alt="Forêt tropicale vue du ciel">
<div class="image-overlay">
<div class="image-title">Amazonia</div>
</div>
</div>
<div class="image-container">
<img src="./image/milky way.webp" alt="Voie lactée dans le ciel">
<div class="image-overlay">
<div class="image-title">Milky Way</div>
</div>
</div>
<div class="image-container">
<img src="./image/atmosphere.webp" alt="Atmosphère terrestre vue de l'espace" width="800" height="800">
<div class="image-overlay">
<div class="image-title">Atmosphere</div>
</div>
</div>
<div class="image-container">
<img src="./image/sequoiaforest.jpeg" alt="Forêt de séquoias" width="800" height="800">
<div class="image-overlay">
<div class="image-title">Sequoia forest</div>
</div>
</div>
<div class="image-container">
<img src="./image/blackhole.webp" alt="Poussière cosmique dans l'espace" width="800" height="800">
<div class="image-overlay">
<div class="image-title">Blackhole</div>
</div>
</div>
<div class="image-container">
<img src="./image/saturn.webp" alt="Planète avec anneaux" width="800" height="800">
<div class="image-overlay">
<div class="image-title">Saturn</div>
</div>
</div>
<div class="image-container">
<img src="./image/mangrove.jpg" alt="Forêt de mangroves" width="800" height="800">
<div class="image-overlay">
<div class="image-title">Mangrove</div>
</div>
</div>
<div class="image-container">
<img src="./image/stars.webp" alt="Amas d'étoiles" width="800" height="800">
<div class="image-overlay">
<div class="image-title">Star cluster</div>
</div>
</div>
<div class="image-container">
<img src="./image/pinforests.webp" alt="Comète dans l'espace" width="800" height="800">
<div class="image-overlay">
<div class="image-title">Pine forest</div>
</div>
</div>
<div class="image-container">
<img src="./image/blueneb.webp" alt="Forêt de bambous" width="800" height="800">
<div class="image-overlay">
<div class="image-title">Stardust</div>
</div>
</div>
</div>
</div>
</div>
<script>
let allFiles = [];
async function loadFileNames() {
const response = await fetch('/api/files');
allFiles = await response.json();
}
function displaySearchResults(searchTerm) {
const resultsDiv = document.getElementById('search-results');
resultsDiv.innerHTML = '';
const matchingFiles = allFiles.filter(file =>
file.toLowerCase().includes(searchTerm.toLowerCase())
);
matchingFiles.forEach(file => {
const div = document.createElement('div');
div.textContent = file;
div.addEventListener('click', () => showFileContent(file));
resultsDiv.appendChild(div);
});
resultsDiv.classList.add('active');
}
function hideSearchResults() {
const resultsDiv = document.getElementById('search-results');
resultsDiv.classList.remove('active');
}
async function showFileContent(fileName) {
const response = await fetch(`/api/file/${fileName}`);
const content = await response.text();
const popup = document.createElement('div');
popup.className = 'popup';
popup.innerHTML = `
<div class="popup-content">
<button class="close-button" onclick="closePopup(this)">×</button>
<div class="markdown-content"></div>
</div>
`;
document.body.appendChild(popup);
// Use marked.js to render Markdown
const markdownContent = popup.querySelector('.markdown-content');
markdownContent.innerHTML = marked(content);
// Trigger reflow before adding 'show' class for animation
popup.offsetWidth;
popup.classList.add('show');
popup.addEventListener('click', (e) => {
if (e.target === popup) {
closePopup(popup);
}
});
}
function closePopup(element) {
const popup = element.closest('.popup');
popup.classList.remove('show');
setTimeout(() => popup.remove(), 300); // Remove after animation
}
window.addEventListener('load', async () => {
await loadFileNames();
const searchInput = document.getElementById('search-input');
const searchResults = document.getElementById('search-results');
searchInput.addEventListener('input', (e) => {
displaySearchResults(e.target.value);
});
searchInput.addEventListener('focus', () => {
if (searchInput.value) {
displaySearchResults(searchInput.value);
}
});
document.addEventListener('click', (e) => {
if (!searchInput.contains(e.target) && !searchResults.contains(e.target)) {
hideSearchResults();
}
});
});
document.addEventListener('keydown', (event) => {
if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
event.preventDefault();
window.parent.postMessage({ key: event.key }, '*');
}
});
</script>
</div>
</div>
<div id="right-section" class="main-section">
<!-- chatgpt.html content -->
<div id="chatgpt-content">
<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto+Condensed:ital,wght@0,100..900;1,100..900&display=swap');
:root {
--bg-color: #000000;
--text-color: #ffffff;
--border-color: #222222;
--input-bg: #0a0a0a;
--accent-color: #111111;
--menu-bg: #050505;
--hover-color: #1a1a1a;
--popup-bg: rgba(10, 10, 10, 0.95);
--mint-green: #98FB98;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
cursor: url('cursor.png'), auto !important;
}
body, html {
height: 100%;
font-family: 'Poppins', Arial, sans-serif;
background-color: var(--bg-color);
color: var(--text-color);
overflow: hidden;
user-select: none;
}
.chat-container {
display: flex;
flex-direction: column;
height: 100vh;
width: 100vw;
position: relative;
overflow: hidden;
}
.chat-messages {
flex-grow: 1;
overflow-y: auto;
padding: 1.5rem;
display: flex;
flex-direction: column;
scrollbar-width: thin;
scrollbar-color: var(--accent-color) var(--bg-color);
}
.chat-messages::-webkit-scrollbar {
width: 6px;
}
.chat-messages::-webkit-scrollbar-track {
background: var(--bg-color);
}
.chat-messages::-webkit-scrollbar-thumb {
background-color: var(--accent-color);
border-radius: 6px;
}
.message {
max-width: 80%;
margin-bottom: 1.5rem;
padding: 1rem;
border-radius: 0.8rem;
line-height: 1.4;
position: relative;
word-wrap: break-word;
font-size: 0.9rem;
transition: all 0.3s ease;
border: 1px solid var(--border-color);
}
.user-message {
align-self: flex-end;
background-color: var(--accent-color);
color: var(--text-color);
}
.ai-message {
align-self: flex-start;
background-color: var(--input-bg);
color: var(--text-color);
user-select: text;
}
.ai-message *::selection {
background-color: #98FB98;
color: #000000;
}
.chat-input {
display: flex;
justify-content: center;
padding: 1.2rem;
background-color: var(--bg-color);
border-top: 1px solid var(--border-color);
position: sticky;
bottom: 0;
}
.chat-input-wrapper {
display: flex;
width: 50%;
background-color: var(--input-bg);
border-radius: 1.5rem;
overflow: hidden;
transition: all 0.3s ease;
}
.chat-input textarea {
flex-grow: 1;
padding: 0.8rem 1.2rem;
border: none;
font-size: 0.9rem;
font-family: 'Poppins', Arial, sans-serif;
background-color: transparent;
color: var(--text-color);
resize: none;
min-height: 20px;
max-height: 150px;
transition: all 0.3s ease;
}
.chat-input textarea:focus {
outline: none;
}
.chat-input textarea::selection {
background-color: var(--mint-green);
color: #000000;
}
.send-btn {
background-color: var(--accent-color);
border: none;
color: var(--text-color);
font-size: 1rem;
padding: 0.6rem 1.2rem;
transition: all 0.3s ease;
border-radius: 0 1.5rem 1.5rem 0;
}
.send-btn:hover {
background-color: var(--hover-color);
}
.menu-btn {
position: fixed;
top: 1rem;
left: 1rem;
background: none;
border: none;
z-index: 1000;
transition: all 0.3s ease;
}
.menu-btn:hover {
transform: scale(1.1);
}
.menu-btn svg {
width: 20px;
height: 20px;
fill: var(--text-color);
}
.conversation-menu {
position: fixed;
top: 0;
left: 0;
width: 280px;
height: 100%;
background-color: var(--menu-bg);
transition: transform 0.3s ease;
overflow-y: auto;
padding: 1.5rem;
box-shadow: 2px 0 15px rgba(0,0,0,0.3);
z-index: 999;
transform: translateX(-100%);
}
.conversation-menu.open {
transform: translateX(0);
}
.conversation-list {
list-style-type: none;
margin-top: 1.5rem;
user-select: none;
}
.conversation-item {
padding: 0.8rem;
margin-bottom: 0.4rem;
background-color: var(--input-bg);
border-radius: 0.4rem;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
font-size: 0.9rem;
}
.conversation-item:hover {
background-color: var(--hover-color);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(255, 255, 255, 0.1);
}
.menu-header {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 1.5rem;
}
.menu-title {
font-size: 1.2rem;
font-weight: bold;
color: var(--text-color);
}
.menu-actions {
display: flex;
justify-content: center;
margin-bottom: 1rem;
}
.menu-btn-action {
background-color: var(--accent-color);
border: none;
color: var(--text-color);
padding: 0.6rem 1rem;
border-radius: 1.5rem;
transition: all 0.3s ease;
font-size: 0.8rem;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.menu-btn-action:hover {
background-color: var(--hover-color);
transform: translateY(-2px);
box-shadow: 0 4px 6px rgba(255, 255, 255, 0.1);
}
.context-menu {
position: fixed;
background-color: var(--popup-bg);
border: 1px solid var(--border-color);
border-radius: 0.4rem;
padding: 0.5rem 0;
z-index: 1000;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
}
.context-menu-item {
padding: 0.5rem 1rem;
transition: background-color 0.2s ease;
}
.context-menu-item:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.popup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0.9);
background-color: var(--popup-bg);
border: 1px solid var(--border-color);
border-radius: 0.8rem;
padding: 1.5rem;
z-index: 1001;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
max-width: 90%;
width: 300px;
backdrop-filter: blur(15px);
transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
opacity: 0;
visibility: hidden;
}
.popup.active {
transform: translate(-50%, -50%) scale(1);
opacity: 1;
visibility: visible;
}
.popup-title {
font-size: 1.2rem;
margin-bottom: 1rem;
text-align: center;
color: var(--text-color);
}
.popup-input {
width: 100%;
padding: 0.5rem;
margin-bottom: 1rem;
background-color: rgba(255, 255, 255, 0.1);
border: 1px solid var(--border-color);
color: var(--text-color);
border-radius: 0.3rem;
transition: all 0.3s ease;
}
.popup-input:focus {
outline: none;
background-color: rgba(255, 255, 255, 0.2);
border-color: var(--text-color);
}
.popup-input::selection {
background-color: var(--mint-green);
color: #000000;
}
.popup-actions {
display: flex;
justify-content: flex-end;
}
.popup-btn {
padding: 0.5rem 1rem;
margin-left: 0.5rem;
border: none;
border-radius: 0.3rem;
transition: all 0.3s ease;
font-weight: bold;
}
.popup-btn-cancel {
background-color: rgba(255, 255, 255, 0.1);
color: var(--text-color);
}
.popup-btn-confirm {
background-color: var(--accent-color);
color: var(--text-color);
}
.popup-btn:hover {
transform: translateY(-2px);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
.overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.7);
z-index: 1000;
backdrop-filter: blur(5px);
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.overlay.active {
opacity: 1;
visibility: visible;
}
@media (max-width: 768px) {
.chat-messages {
padding: 1rem;
}
.message {
max-width: 90%;
font-size: 0.85rem;
}
.chat-input {
padding: 0.8rem;
}
.chat-input-wrapper {
width: 90%;
}
.conversation-menu {
width: 100%;
}
}
* {
cursor: url('./image/cursor.png'), auto !important;
}
input[type="text"], textarea {
cursor: url('cursor.png'), text !important;
}
input[type="text"], textarea {
caret-color: transparent;
}
input[type="text"]::after, textarea::after {
content: '|';
position: absolute;
color: var(--text-color);
animation: blink 1s step-end infinite;
}
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
.message pre {
background-color: #1e1e1e;
border-radius: 4px;
padding: 10px;
overflow-x: auto;
}
.message code {
font-family: 'Courier New', Courier, monospace;
font-size: 0.9em;
}
.message ul, .message ol {
margin-left: 20px;
}
.message p {
margin-bottom: 10px;
}
textarea {
cursor: url('./image/cursor.png'), text !important;
}
</style>
<div class="chat-container">
<button class="menu-btn" id="menuBtn" aria-label="Open conversation menu">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/>
</svg>
</button>
<div class="chat-messages" id="chatMessages"></div>
<form id="chatForm" class="chat-input">
<div class="chat-input-wrapper">
<textarea id="userInput" placeholder="" spellcheck="false" autocomplete="off" aria-label="Chat input" required></textarea>
<button type="submit" class="send-btn">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 21L23 12L2 3V10L17 12L2 14V21Z" fill="currentColor"/>
</svg>
</button>
</div>
</form>
</div>
<div class="conversation-menu" id="conversationMenu">
<div class="menu-header">
<h2 class="menu-title">CONVERSATIONS</h2>
</div>
<div class="menu-actions">
<button class="menu-btn-action" id="newConversationBtn">New Conversation</button>
</div>
<ul class="conversation-list" id="conversationList">
<!-- Conversation items will be dynamically added here -->
</ul>
</div>
<div id="contextMenu" class="context-menu" style="display: none;">
<div class="context-menu-item" id="renameConversation">Rename</div>
<div class="context-menu-item" id="deleteConversation">Delete</div>
</div>
<div id="overlay" class="overlay"></div>
<div id="renamePopup" class="popup">
<h3 class="popup-title">Rename Conversation</h3>
<input type="text" id="renameInput" class="popup-input" placeholder="New name" spellcheck="false" autocomplete="off">
<div class="popup-actions">
<button id="cancelRename" class="popup-btn popup-btn-cancel">Cancel</button>
<button id="confirmRename" class="popup-btn popup-btn-confirm">Rename</button>
</div>
</div>
<div id="deletePopup" class="popup">
<h3 class="popup-title">Delete Conversation</h3>
<div class="popup-actions">
<button id="cancelDelete" class="popup-btn popup-btn-cancel">Cancel</button>
<button id="confirmDelete" class="popup-btn popup-btn-confirm">Delete</button>
</div>
</div>
<script>
// Sélection des éléments du DOM
const chatMessages = document.getElementById('chatMessages');
const chatForm = document.getElementById('chatForm');
const userInput = document.getElementById('userInput');
const menuBtn = document.getElementById('menuBtn');
const conversationMenu = document.getElementById('conversationMenu');
const conversationList = document.getElementById('conversationList');
const newConversationBtn = document.getElementById('newConversationBtn');
const contextMenu = document.getElementById('contextMenu');
const renameConversationBtn = document.getElementById('renameConversation');
const deleteConversationBtn = document.getElementById('deleteConversation');
const renamePopup = document.getElementById('renamePopup');
const deletePopup = document.getElementById('deletePopup');
const renameInput = document.getElementById('renameInput');
const confirmRenameBtn = document.getElementById('confirmRename');
const cancelRenameBtn = document.getElementById('cancelRename');
const confirmDeleteBtn = document.getElementById('confirmDelete');
const cancelDeleteBtn = document.getElementById('cancelDelete');
const overlay = document.getElementById('overlay');
let conversations = [];
let currentConversation = null;
let selectedConversation = null;
function loadConversations() {
const savedConversations = localStorage.getItem('conversations');
if (savedConversations) {
conversations = JSON.parse(savedConversations);
updateConversationList();
}
}
loadConversations();
function saveConversations() {
localStorage.setItem('conversations', JSON.stringify(conversations));
}
function addMessage(content, isUser = false) {
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', isUser ? 'user-message' : 'ai-message');
const renderedContent = marked.parse(content);
messageDiv.innerHTML = renderedContent;
chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
if (typeof hljs !== 'undefined') {
messageDiv.querySelectorAll('pre code').forEach((block) => {
hljs.highlightElement(block);
});
}
}
async function getAIResponse(userMessage) {
const response = await fetch('/chat?source=chatgpt', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message: userMessage })
}).then(response => response.json());
console.log(response.response);
return response.response;
}
chatForm.addEventListener('submit', async (e) => {
e.preventDefault();
const message = userInput.value.trim();
if (message) {
addMessage(message, true);
userInput.value = '';
userInput.style.height = 'auto';
userInput.focus();
const response = await getAIResponse(message);
addMessage(response, false);
if (currentConversation) {
currentConversation.messages.push({ user: message, ai: response });
} else {
currentConversation = {
id: Date.now(),
name: `Conversation ${conversations.length + 1}`,
messages: [{ user: message, ai: response }]
};
conversations.unshift(currentConversation);
}
updateConversationList();
saveConversations();
}
});
userInput.addEventListener('input', function() {
this.style.height = 'auto';
this.style.height = `${this.scrollHeight}px`;
});
function toggleMenu() {
conversationMenu.classList.toggle('open');
}
function updateConversationList() {
conversationList.innerHTML = '';
conversations.forEach(conv => {
const li = document.createElement('li');
li.classList.add('conversation-item');
li.innerHTML = `<div>${conv.name}</div>`;
li.dataset.id = conv.id;
li.addEventListener('click', () => loadConversation(conv));
li.addEventListener('contextmenu', e => showContextMenu(e, conv));
conversationList.appendChild(li);
});
saveConversations();
}
function loadConversation(conversation) {
currentConversation = conversation;
chatMessages.innerHTML = '';
conversation.messages.forEach(msg => {
addMessage(msg.user, true);
addMessage(msg.ai, false);
});
toggleMenu();
}
function showContextMenu(e, conversation) {
e.preventDefault();
selectedConversation = conversation;
contextMenu.style.display = 'block';
contextMenu.style.left = `${e.pageX}px`;
contextMenu.style.top = `${e.pageY}px`;
}
function hideContextMenu() {
contextMenu.style.display = 'none';
}
function showPopup(popup) {
overlay.classList.add('active');
popup.classList.add('active');
}
function hidePopup(popup) {
overlay.classList.remove('active');
popup.classList.remove('active');
}
menuBtn.addEventListener('click', toggleMenu);
newConversationBtn.addEventListener('click', () => {
currentConversation = {
id: Date.now(),
name: `Conversation ${conversations.length + 1}`,
messages: []
};
conversations.unshift(currentConversation);
updateConversationList();
chatMessages.innerHTML = '';
toggleMenu();
});
renameConversationBtn.addEventListener('click', () => {
hideContextMenu();
renameInput.value = selectedConversation.name;
showPopup(renamePopup);
});
deleteConversationBtn.addEventListener('click', () => {
hideContextMenu();
showPopup(deletePopup);
});
confirmRenameBtn.addEventListener('click', () => {
const newName = renameInput.value.trim();
if (newName) {
selectedConversation.name = newName;
updateConversationList();
}
hidePopup(renamePopup);
});
cancelRenameBtn.addEventListener('click', () => hidePopup(renamePopup));
confirmDeleteBtn.addEventListener('click', () => {
conversations = conversations.filter(conv => conv.id !== selectedConversation.id);
if (currentConversation && currentConversation.id === selectedConversation.id) {
currentConversation = null;
chatMessages.innerHTML = '';
}
updateConversationList();
hidePopup(deletePopup);
});
cancelDeleteBtn.addEventListener('click', () => hidePopup(deletePopup));
document.addEventListener('click', e => {
if (!contextMenu.contains(e.target)) {
hideContextMenu();
}
});
document.addEventListener('keydown', (event) => {
if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
event.preventDefault();
window.parent.postMessage({ key: event.key }, '*');
}
});
</script>
</div>
</div>
</div>
<div class="grid-background"></div>
<audio id="backgroundAudio" loop preload="auto">
<source src="song/ground-music.mp3" type="audio/mpeg">
Votre navigateur ne supporte pas l'élément audio.
</audio>
<script>
document.addEventListener('DOMContentLoaded', () => {
const container = document.getElementById('container');
const mainSections = document.querySelectorAll('.main-section');
const verticalContainer = document.getElementById('vertical-container');
const verticalSections = document.querySelectorAll('.vertical-section');
let currentMainIndex = 1;
let currentVerticalIndex = 0;
const audio = document.getElementById('backgroundAudio');
function attemptPlayAudio() {
audio.play().catch(() => {
setTimeout(attemptPlayAudio, 1000);
});
}
attemptPlayAudio();
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
audio.pause();
} else {
attemptPlayAudio();
}
});
function updateMainSection() {
mainSections.forEach((section, index) => {
if (index === currentMainIndex) {
section.style.opacity = 1;
section.style.transform = 'scale(1) rotateY(0deg)';
section.style.filter = 'brightness(100%) blur(0)';
} else {
section.style.opacity = 0;
section.style.transform = 'scale(0.8) rotateY(10deg)';
section.style.filter = 'brightness(70%) blur(10px)';
}
});
container.style.transform = `translateX(-${currentMainIndex * 100}vw)`;
}
function updateVerticalSection() {
verticalSections.forEach((section, index) => {
if (index === currentVerticalIndex) {
section.style.opacity = 1;
section.style.transform = 'scale(1) rotateX(0deg)';
section.style.filter = 'brightness(100%) blur(0)';
} else {
section.style.opacity = 0;
section.style.transform = 'scale(0.8) rotateX(10deg)';
section.style.filter = 'brightness(70%) blur(10px)';
}
});
verticalContainer.style.transform = `translateY(-${currentVerticalIndex * 100}vh)`;
}
updateMainSection();
updateVerticalSection();
function handleKeyNavigation(key) {
if (key === 'ArrowLeft') {
if (currentMainIndex > 0) {
currentMainIndex--;
updateMainSection();
}
} else if (key === 'ArrowRight') {
if (currentMainIndex < mainSections.length - 1) {
currentMainIndex++;
updateMainSection();
}
} else if (key === 'ArrowUp') {
if (currentMainIndex === 0 && currentVerticalIndex > 0) {
currentVerticalIndex--;
updateVerticalSection();
}
} else if (key === 'ArrowDown') {
if (currentMainIndex === 0 && currentVerticalIndex < verticalSections.length - 1) {
currentVerticalIndex++;
updateVerticalSection();
}
}
}
document.addEventListener('keydown', (event) => {
handleKeyNavigation(event.key);
});
window.addEventListener('message', (event) => {
if (event.data.key) {
handleKeyNavigation(event.data.key);
}
});
});
</script>
</body>
</html>