| <!DOCTYPE html> |
| <html lang="fr"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Notorium - Bloc-notes intelligent</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <script> |
| tailwind.config = { |
| darkMode: 'class', |
| theme: { |
| extend: { |
| colors: { |
| dark: { |
| 900: '#0a0a0a', |
| 800: '#1a1a1a', |
| 700: '#2a2a2a', |
| 600: '#3a3a3a', |
| }, |
| primary: { |
| 500: '#6366f1', |
| 600: '#4f46e5', |
| } |
| } |
| } |
| } |
| } |
| </script> |
| <style> |
| .note-content { |
| min-height: 300px; |
| line-height: 1.6; |
| } |
| .suggestion-item:hover { |
| background-color: rgba(99, 102, 241, 0.2); |
| } |
| .fade-in { |
| animation: fadeIn 0.3s ease-in-out; |
| } |
| @keyframes fadeIn { |
| from { opacity: 0; transform: translateY(10px); } |
| to { opacity: 1; transform: translateY(0); } |
| } |
| .separator { |
| border-top: 1px dashed rgba(255,255,255,0.1); |
| margin: 1rem 0; |
| } |
| </style> |
| </head> |
| <body class="bg-dark-900 text-gray-200 min-h-screen"> |
| <div class="container mx-auto px-4 py-8 max-w-4xl"> |
| |
| <header class="flex justify-between items-center mb-8"> |
| <div class="flex items-center space-x-3"> |
| <i class="fas fa-book-open text-primary-500 text-2xl"></i> |
| <h1 class="text-2xl font-bold">Notorium</h1> |
| </div> |
| <div class="flex space-x-4"> |
| <button id="searchBtn" class="p-2 rounded-full hover:bg-dark-700 transition"> |
| <i class="fas fa-search"></i> |
| </button> |
| <button id="settingsBtn" class="p-2 rounded-full hover:bg-dark-700 transition"> |
| <i class="fas fa-cog"></i> |
| </button> |
| </div> |
| </header> |
|
|
| |
| <div id="searchModal" class="hidden fixed inset-0 bg-black bg-opacity-70 z-50 flex items-center justify-center p-4"> |
| <div class="bg-dark-800 rounded-lg w-full max-w-md p-6"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-lg font-semibold">Rechercher dans vos notes</h3> |
| <button id="closeSearch" class="text-gray-400 hover:text-white"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <input type="text" placeholder="Tapez pour rechercher..." class="w-full bg-dark-700 border border-dark-600 rounded-md px-4 py-2 mb-4 focus:outline-none focus:ring-2 focus:ring-primary-500"> |
| <div class="flex space-x-2 mb-4"> |
| <select class="bg-dark-700 border border-dark-600 rounded-md px-3 py-1 text-sm"> |
| <option>Toutes les dates</option> |
| <option>Aujourd'hui</option> |
| <option>Cette semaine</option> |
| <option>Ce mois</option> |
| </select> |
| <select class="bg-dark-700 border border-dark-600 rounded-md px-3 py-1 text-sm"> |
| <option>Tous les tags</option> |
| <option>Professionnel</option> |
| <option>Créatif</option> |
| <option>Personnel</option> |
| </select> |
| </div> |
| <div id="searchResults" class="max-h-60 overflow-y-auto"> |
| |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-dark-800 rounded-xl shadow-lg overflow-hidden mb-6"> |
| |
| <div class="flex items-center px-4 py-2 bg-dark-700 border-b border-dark-600"> |
| <div class="flex space-x-2"> |
| <button class="p-2 rounded hover:bg-dark-600" title="Gras" onclick="formatText('bold')"> |
| <i class="fas fa-bold"></i> |
| </button> |
| <button class="p-2 rounded hover:bg-dark-600" title="Italique" onclick="formatText('italic')"> |
| <i class="fas fa-italic"></i> |
| </button> |
| <button class="p-2 rounded hover:bg-dark-600" title="Liste à puces" onclick="formatText('insertUnorderedList')"> |
| <i class="fas fa-list-ul"></i> |
| </button> |
| </div> |
| <div class="ml-auto flex space-x-2"> |
| <button id="suggestBtn" class="px-3 py-1 bg-dark-600 hover:bg-primary-500 rounded-md text-sm flex items-center space-x-1 transition"> |
| <i class="fas fa-lightbulb"></i> |
| <span>Suggestions</span> |
| </button> |
| <button id="generateBtn" class="px-3 py-1 bg-primary-500 hover:bg-primary-600 rounded-md text-sm flex items-center space-x-1 transition"> |
| <i class="fas fa-magic"></i> |
| <span>Générer</span> |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div class="p-4"> |
| <div id="noteEditor" class="note-content outline-none" contenteditable="true" placeholder="Commencez à écrire ici..."></div> |
| </div> |
| </div> |
|
|
| |
| <div id="suggestionsPanel" class="hidden bg-dark-800 rounded-lg p-4 mb-6 fade-in"> |
| <div class="flex justify-between items-center mb-3"> |
| <h3 class="font-medium">Suggestions intelligentes</h3> |
| <button id="closeSuggestions" class="text-gray-400 hover:text-white"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <div id="suggestionsContent" class="space-y-2"> |
| |
| </div> |
| </div> |
|
|
| |
| <div id="generatedContent" class="hidden bg-dark-800 rounded-lg p-4 mb-6 fade-in"> |
| <div class="flex justify-between items-center mb-3"> |
| <h3 class="font-medium">Contenu optimisé</h3> |
| <div class="flex space-x-2"> |
| <button id="copyAll" class="px-2 py-1 bg-dark-700 hover:bg-dark-600 rounded text-xs flex items-center space-x-1"> |
| <i class="fas fa-copy"></i> |
| <span>Tout copier</span> |
| </button> |
| <button id="insertAll" class="px-2 py-1 bg-primary-500 hover:bg-primary-600 rounded text-xs flex items-center space-x-1"> |
| <i class="fas fa-plus"></i> |
| <span>Insérer</span> |
| </button> |
| </div> |
| </div> |
| <div id="generatedText" class="whitespace-pre-line"> |
| |
| </div> |
| </div> |
|
|
| |
| <div class="flex justify-between items-center text-sm text-gray-500"> |
| <div> |
| <span id="charCount">0</span> caractères |
| </div> |
| <div class="flex space-x-4"> |
| <button id="saveBtn" class="hover:text-gray-300 flex items-center space-x-1"> |
| <i class="fas fa-cloud"></i> |
| <span>Sauvegarder</span> |
| </button> |
| <button id="exportBtn" class="hover:text-gray-300 flex items-center space-x-1"> |
| <i class="fas fa-share"></i> |
| <span>Exporter</span> |
| </button> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| document.addEventListener('DOMContentLoaded', function() { |
| const noteEditor = document.getElementById('noteEditor'); |
| const charCount = document.getElementById('charCount'); |
| const suggestBtn = document.getElementById('suggestBtn'); |
| const generateBtn = document.getElementById('generateBtn'); |
| const suggestionsPanel = document.getElementById('suggestionsPanel'); |
| const generatedContent = document.getElementById('generatedContent'); |
| const generatedText = document.getElementById('generatedText'); |
| const closeSuggestions = document.getElementById('closeSuggestions'); |
| const copyAll = document.getElementById('copyAll'); |
| const insertAll = document.getElementById('insertAll'); |
| const searchBtn = document.getElementById('searchBtn'); |
| const searchModal = document.getElementById('searchModal'); |
| const closeSearch = document.getElementById('closeSearch'); |
| const saveBtn = document.getElementById('saveBtn'); |
| const exportBtn = document.getElementById('exportBtn'); |
| |
| |
| noteEditor.addEventListener('input', function() { |
| charCount.textContent = noteEditor.textContent.length; |
| }); |
| |
| |
| noteEditor.addEventListener('paste', function(e) { |
| e.preventDefault(); |
| const text = (e.clipboardData || window.clipboardData).getData('text/plain'); |
| |
| |
| setTimeout(() => { |
| processPastedContent(text); |
| }, 10); |
| }); |
| |
| function cleanText(text) { |
| |
| return text |
| .replace(/^(Titre|titre)\s*:\s*/gmi, '') |
| .replace(/^(Description|description)\s*:\s*/gmi, '') |
| .replace(/^(Hashtag|hashtag|Mots-clés|mots-clés)\s*:\s*/gmi, '') |
| .trim(); |
| } |
| |
| function processPastedContent(text) { |
| |
| text = cleanText(text); |
| |
| |
| let title = ''; |
| let description = ''; |
| let hashtags = ''; |
| |
| |
| if (text.includes('Titre:') || text.includes('titre:')) { |
| const parts = text.split(/\n\s*\n/); |
| parts.forEach(part => { |
| if (part.match(/^(Titre|titre):/i)) { |
| title = cleanText(part); |
| } else if (part.match(/^(Description|description):/i)) { |
| description = cleanText(part); |
| } else if (part.match(/^(Hashtags|hashtags|Mots-clés|mots-clés):/i)) { |
| hashtags = cleanText(part); |
| } |
| }); |
| } else { |
| |
| const parts = text.split(/\n\s*\n/); |
| if (parts.length >= 3) { |
| title = cleanText(parts[0]); |
| description = cleanText(parts[1]); |
| hashtags = cleanText(parts[2]); |
| } else if (parts.length === 2) { |
| title = cleanText(parts[0]); |
| description = cleanText(parts[1]); |
| } else if (parts.length === 1) { |
| description = cleanText(parts[0]); |
| } |
| } |
| |
| |
| let formattedContent = ''; |
| if (title) formattedContent += title + '\n\n'; |
| if (description) formattedContent += description + '\n\n'; |
| if (hashtags) { |
| |
| hashtags = hashtags.split(/\s+/).map(tag => { |
| return tag.startsWith('#') ? tag : '#' + tag; |
| }).join(' '); |
| formattedContent += hashtags; |
| } |
| |
| |
| noteEditor.innerHTML = formattedContent; |
| } |
| |
| |
| generateBtn.addEventListener('click', function() { |
| const content = noteEditor.textContent.trim(); |
| if (!content) return; |
| |
| |
| const generated = generateOptimizedContent(content); |
| generatedText.textContent = generated; |
| generatedContent.classList.remove('hidden'); |
| }); |
| |
| function generateOptimizedContent(text) { |
| |
| const sentences = text.split(/[.!?]\s+/); |
| const firstSentence = sentences[0]; |
| const keywords = extractKeywords(text); |
| |
| |
| let title = ''; |
| if (firstSentence.length < 60) { |
| title = firstSentence; |
| } else { |
| title = keywords.slice(0, 3).join(' ') + '...'; |
| } |
| |
| |
| let description = ''; |
| if (sentences.length > 1) { |
| description = sentences.slice(1).join('. ') + '.'; |
| } else { |
| description = firstSentence; |
| } |
| |
| |
| let hashtags = keywords.slice(0, 5).map(word => '#' + word.toLowerCase()).join(' '); |
| |
| |
| return `${title}\n\n${description}\n\n${hashtags}`; |
| } |
| |
| function extractKeywords(text) { |
| |
| const words = text.toLowerCase().split(/\s+/); |
| const commonWords = ['le', 'la', 'les', 'un', 'une', 'des', 'et', 'ou', 'mais', 'pour', 'dans', 'avec', 'sur', 'par']; |
| |
| const wordCount = {}; |
| words.forEach(word => { |
| word = word.replace(/[^a-zéèêëàâùûîïôöç]/g, ''); |
| if (word.length > 3 && !commonWords.includes(word)) { |
| wordCount[word] = (wordCount[word] || 0) + 1; |
| } |
| }); |
| |
| return Object.entries(wordCount) |
| .sort((a, b) => b[1] - a[1]) |
| .map(entry => entry[0]); |
| } |
| |
| |
| suggestBtn.addEventListener('click', function() { |
| const content = noteEditor.textContent.trim(); |
| if (!content) return; |
| |
| |
| const suggestions = generateSuggestions(content); |
| displaySuggestions(suggestions); |
| suggestionsPanel.classList.remove('hidden'); |
| }); |
| |
| function generateSuggestions(text) { |
| |
| const suggestions = []; |
| const keywords = extractKeywords(text); |
| |
| if (keywords.length > 0) { |
| suggestions.push({ |
| type: 'keywords', |
| content: `Mots-clés pertinents: ${keywords.slice(0, 5).join(', ')}` |
| }); |
| |
| suggestions.push({ |
| type: 'hashtags', |
| content: `Hashtags suggérés: ${keywords.slice(0, 5).map(k => '#' + k).join(' ')}` |
| }); |
| } |
| |
| if (text.length > 100) { |
| suggestions.push({ |
| type: 'summary', |
| content: `Résumé possible: ${text.substring(0, 100)}...` |
| }); |
| } |
| |
| |
| suggestions.push({ |
| type: 'question', |
| content: "Pourriez-vous développer ce point davantage ?" |
| }); |
| |
| suggestions.push({ |
| type: 'example', |
| content: "Un exemple concret pourrait renforcer votre argument." |
| }); |
| |
| return suggestions; |
| } |
| |
| function displaySuggestions(suggestions) { |
| const container = document.getElementById('suggestionsContent'); |
| container.innerHTML = ''; |
| |
| suggestions.forEach(suggestion => { |
| const item = document.createElement('div'); |
| item.className = 'suggestion-item p-3 bg-dark-700 rounded-md cursor-pointer'; |
| item.innerHTML = ` |
| <div class="flex items-start"> |
| <div class="mt-1 mr-3 text-primary-500"> |
| ${getSuggestionIcon(suggestion.type)} |
| </div> |
| <div>${suggestion.content}</div> |
| </div> |
| `; |
| item.addEventListener('click', () => { |
| applySuggestion(suggestion); |
| }); |
| container.appendChild(item); |
| }); |
| } |
| |
| function getSuggestionIcon(type) { |
| switch(type) { |
| case 'keywords': return '<i class="fas fa-tags"></i>'; |
| case 'hashtags': return '<i class="fas fa-hashtag"></i>'; |
| case 'summary': return '<i class="fas fa-align-left"></i>'; |
| case 'question': return '<i class="fas fa-question-circle"></i>'; |
| case 'example': return '<i class="fas fa-lightbulb"></i>'; |
| default: return '<i class="fas fa-comment"></i>'; |
| } |
| } |
| |
| function applySuggestion(suggestion) { |
| |
| const selection = window.getSelection(); |
| if (!selection.rangeCount) return; |
| |
| const range = selection.getRangeAt(0); |
| const node = document.createTextNode(suggestion.content + ' '); |
| range.insertNode(node); |
| |
| |
| range.setStartAfter(node); |
| range.setEndAfter(node); |
| selection.removeAllRanges(); |
| selection.addRange(range); |
| |
| suggestionsPanel.classList.add('hidden'); |
| } |
| |
| |
| closeSuggestions.addEventListener('click', function() { |
| suggestionsPanel.classList.add('hidden'); |
| }); |
| |
| |
| copyAll.addEventListener('click', function() { |
| navigator.clipboard.writeText(generatedText.textContent) |
| .then(() => { |
| const originalText = copyAll.innerHTML; |
| copyAll.innerHTML = '<i class="fas fa-check"></i> <span>Copié</span>'; |
| setTimeout(() => { |
| copyAll.innerHTML = originalText; |
| }, 2000); |
| }); |
| }); |
| |
| |
| insertAll.addEventListener('click', function() { |
| noteEditor.innerHTML = generatedText.textContent; |
| generatedContent.classList.add('hidden'); |
| }); |
| |
| |
| searchBtn.addEventListener('click', function() { |
| searchModal.classList.remove('hidden'); |
| }); |
| |
| closeSearch.addEventListener('click', function() { |
| searchModal.classList.add('hidden'); |
| }); |
| |
| |
| saveBtn.addEventListener('click', function() { |
| alert('Note sauvegardée dans le cloud'); |
| }); |
| |
| exportBtn.addEventListener('click', function() { |
| alert('Exportation vers les réseaux sociaux'); |
| }); |
| }); |
| |
| |
| function formatText(command, value = null) { |
| document.execCommand(command, false, value); |
| } |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Chasme/bloc-note" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |