| | <!DOCTYPE html>
|
| | <html lang="ar">
|
| | <head>
|
| | <meta charset="UTF-8">
|
| | <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| | <title>مولد مقالات AI</title>
|
| | <style>
|
| | body {
|
| | font-family: 'Cairo', sans-serif;
|
| | margin: 20px;
|
| | padding: 0;
|
| | background-color: #f9f9f9;
|
| | direction: rtl;
|
| | }
|
| |
|
| | h1 {
|
| | font-size: 28px;
|
| | color: #333;
|
| | text-align: center;
|
| | margin-bottom: 30px;
|
| | }
|
| |
|
| | .container {
|
| | max-width: 800px;
|
| | margin: 0 auto;
|
| | }
|
| |
|
| | input[type="text"] {
|
| | width: 100%;
|
| | padding: 12px;
|
| | font-size: 16px;
|
| | border: 1px solid #ccc;
|
| | border-radius: 5px;
|
| | margin-bottom: 15px;
|
| | box-sizing: border-box;
|
| | }
|
| |
|
| | .btn {
|
| | width: 100%;
|
| | padding: 12px;
|
| | font-size: 16px;
|
| | background-color: #007bff;
|
| | color: #fff;
|
| | border: none;
|
| | border-radius: 5px;
|
| | cursor: pointer;
|
| | margin-bottom: 30px;
|
| | }
|
| |
|
| | .article-box {
|
| | background-color: #fff;
|
| | border: 1px solid #e0e0e0;
|
| | border-radius: 12px;
|
| | padding: 20px;
|
| | margin-bottom: 20px;
|
| | cursor: pointer;
|
| | transition: all 0.3s ease;
|
| | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
| | position: relative;
|
| | overflow: hidden;
|
| | }
|
| |
|
| |
|
| |
|
| | .article-title {
|
| | font-size: 20px;
|
| | font-weight: bold;
|
| | color: #333;
|
| | margin: 0 0 10px 0;
|
| | }
|
| |
|
| | .article-meta {
|
| | font-size: 14px;
|
| | color: #777;
|
| | margin: 0 0 10px 0;
|
| | }
|
| |
|
| |
|
| | .article-content {
|
| | display: none;
|
| | position: fixed;
|
| | top: 100%;
|
| | left: 50%;
|
| | width: 100%;
|
| | max-width: 600px;
|
| | height: 100%;
|
| | transform: translateX(-50%);
|
| | background-color: #fff;
|
| | border: none;
|
| | border-radius: 10px;
|
| |
|
| | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
| | z-index: 1000;
|
| | overflow-y: auto;
|
| | opacity: 0;
|
| | transition: opacity 0.3s ease-in-out, top 0.3s ease-in-out;
|
| | overflow-x: hidden;
|
| | }
|
| |
|
| | .article-content.show {
|
| | top: 50%;
|
| | opacity: 1;
|
| | transform: translate(-50%, -50%);
|
| | }
|
| |
|
| | .overlay {
|
| | display: none;
|
| | position: fixed;
|
| | top: 0;
|
| | left: 0;
|
| | width: 100%;
|
| | height: 100%;
|
| | background-color: rgba(0, 0, 0, 0.5);
|
| | z-index: 999;
|
| | opacity: 0;
|
| | transition: opacity 0.3s ease-in-out;
|
| | }
|
| |
|
| | .overlay.show {
|
| | opacity: 1;
|
| | }
|
| |
|
| | .close-btn {
|
| | position: sticky;
|
| | top: 10px;
|
| | right: 10px;
|
| | font-size: 24px;
|
| | cursor: pointer;
|
| | color: #333;
|
| | background-color: #fff;
|
| | border: 2px solid #ccc;
|
| | border-radius: 50%;
|
| | width: 40px;
|
| | height: 40px;
|
| | display: flex;
|
| | align-items: center;
|
| | justify-content: center;
|
| | z-index: 20;
|
| | transition: all 0.3s ease;
|
| | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
| | }
|
| |
|
| | .close-btn:hover {
|
| | color: #fff;
|
| | background-color: #ff4d4d;
|
| | border-color: #ff4d4d;
|
| | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
| | }
|
| |
|
| | .close-btn:active {
|
| | transform: scale(0.9);
|
| | }
|
| |
|
| | .close-btn:hover {
|
| | color: #000;
|
| | }
|
| |
|
| | .modal-header {
|
| | font-size: 20px;
|
| | font-weight: bold;
|
| | color: #333;
|
| | text-align: center;
|
| | width: 100%;
|
| | white-space: nowrap;
|
| | overflow: hidden;
|
| | text-overflow: ellipsis;
|
| | padding: 0 10px;
|
| | box-sizing: border-box;
|
| | }
|
| |
|
| | .article-body {
|
| | font-size: 16px;
|
| | color: #555;
|
| | line-height: 1.6;
|
| | padding: 20px;
|
| | }
|
| |
|
| | .modal-footer {
|
| | font-size: 14px;
|
| | color: #777;
|
| | margin-top: 20px;
|
| | text-align: center;
|
| | }
|
| |
|
| | .skeleton {
|
| | width: 100%;
|
| | height: 200px;
|
| | background: #f0f0f0;
|
| | animation: pulse 1.5s infinite ease-in-out;
|
| | border-radius: 5px;
|
| | }
|
| |
|
| | @keyframes pulse {
|
| | 0% {
|
| | background-color: #f0f0f0;
|
| | }
|
| | 50% {
|
| | background-color: #e0e0e0;
|
| | }
|
| | 100% {
|
| | background-color: #f0f0f0;
|
| | }
|
| | }
|
| |
|
| |
|
| | .search-box {
|
| | margin-bottom: 20px;
|
| | }
|
| |
|
| | .search-box input {
|
| | width: 100%;
|
| | padding: 10px;
|
| | font-size: 16px;
|
| | border: 1px solid #ccc;
|
| | border-radius: 5px;
|
| | }
|
| |
|
| | code{
|
| | color: #fff;
|
| | background-color: #000;
|
| | padding: 5px;
|
| | border-radius: 3px;
|
| | }
|
| |
|
| | .modal-footer {
|
| | display: flex;
|
| | justify-content: space-between;
|
| | align-items: center;
|
| | padding: 10px;
|
| | background-color: #f8f9fa;
|
| | border-top: 1px solid #e9ecef;
|
| | font-size: 14px;
|
| | color: #6c757d;
|
| | }
|
| |
|
| | .user-info {
|
| | font-weight: bold;
|
| | color: #007bff;
|
| | width: 23%;
|
| | }
|
| |
|
| | .date {
|
| | font-style: italic;
|
| | color: #6c757d;
|
| | }
|
| |
|
| | .time {
|
| | font-weight: bold;
|
| | color: #28a745;
|
| | }
|
| |
|
| | code{
|
| | color: #fff;
|
| | background-color: #000;
|
| | padding: 5px;
|
| | border-radius: 3px;
|
| | }
|
| |
|
| | .modal-footer {
|
| | display: flex;
|
| | justify-content: space-between;
|
| | align-items: center;
|
| | padding: 10px;
|
| | background-color: #f8f9fa;
|
| | border-top: 1px solid #e9ecef;
|
| | font-size: 14px;
|
| | color: #6c757d;
|
| | }
|
| |
|
| | .user-info {
|
| | font-weight: bold;
|
| | color: #007bff;
|
| | }
|
| |
|
| | .date {
|
| | font-style: italic;
|
| | color: #6c757d;
|
| | }
|
| |
|
| | .time {
|
| | font-weight: bold;
|
| | color: #28a745;
|
| | }
|
| |
|
| | code{
|
| | color: #fff;
|
| | background-color: #000;
|
| | padding: 5px;
|
| | border-radius: 3px;
|
| | }
|
| | .modal-footer {
|
| | display: flex;
|
| | justify-content: space-between;
|
| | align-items: center;
|
| | padding: 10px;
|
| | background-color: #f8f9fa;
|
| | border-top: 1px solid #e9ecef;
|
| | font-size: 14px;
|
| | color: #6c757d;
|
| | }
|
| |
|
| | .user-info {
|
| | font-weight: bold;
|
| | color: #007bff;
|
| | }
|
| |
|
| | .date {
|
| | font-style: italic;
|
| | color: #6c757d;
|
| | }
|
| |
|
| | .time {
|
| | font-weight: bold;
|
| | color: #28a745;
|
| | margin-right: 10px;
|
| | }
|
| |
|
| | .user-photo {
|
| | margin-left: 10px;
|
| | }
|
| |
|
| | .photo_user {
|
| | width: 40px;
|
| | height: 40px;
|
| | border-radius: 50%;
|
| | object-fit: cover;
|
| | border: 2px solid #007bff;
|
| | }
|
| |
|
| | .article-title {
|
| | font-size: 20px;
|
| | font-weight: bold;
|
| | color: #333;
|
| | margin: 0 0 10px 0;
|
| | position: sticky;
|
| | top: 0;
|
| | background-color: #fff;
|
| | padding: 10px 0;
|
| | z-index: 10;
|
| | border-bottom: 1px solid #ddd;
|
| | }
|
| |
|
| | .close-btn {
|
| |
|
| | |
| |
|
| | font-size: 30px;
|
| | cursor: pointer;
|
| | color: #333;
|
| | |
| | |
| | |
| |
|
| | padding: 10px;
|
| |
|
| |
|
| | }
|
| |
|
| | .controls{
|
| | position: sticky;
|
| | top: 0;
|
| | right: 0;
|
| | font-size: 30px;
|
| | cursor: pointer;
|
| | color: #333;
|
| | background: none;
|
| | border: none;
|
| | z-index: 20;
|
| | margin-left: auto;
|
| | padding: 5px 10px;
|
| | width: 100%;
|
| | background-color: #fff;
|
| | display: flex;
|
| | align-items: center;
|
| | justify-content: space-between;
|
| | background-color: #007bff;
|
| | }
|
| |
|
| |
|
| |
|
| | </style>
|
| |
|
| | <link href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.css" rel="stylesheet"/>
|
| |
|
| |
|
| | <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.js"></script>
|
| |
|
| | <script>
|
| | let overlay = null;
|
| |
|
| | function toggleContent(element) {
|
| | const content = element.querySelector('.article-content');
|
| |
|
| | if (content.style.display === 'none' || content.style.display === '') {
|
| | content.style.display = 'block';
|
| | setTimeout(() => {
|
| | content.classList.add('show');
|
| | }, 10);
|
| | }
|
| | }
|
| |
|
| |
|
| |
|
| | function closeContent(button) {
|
| | const content = button.closest('.article-content');
|
| | content.classList.remove('show');
|
| | setTimeout(() => {
|
| | content.style.display = 'none';
|
| | }, 500);
|
| | }
|
| | let isCreating = false;
|
| |
|
| |
|
| | async function createArticle() {
|
| | if (isCreating) {
|
| |
|
| | const message = document.createElement('div');
|
| | message.id = 'creation-message';
|
| | message.textContent = 'انتظر لم ننتهي بعد';
|
| | message.style.color = 'red';
|
| | message.style.position = 'fixed';
|
| | message.style.top = '10px';
|
| | message.style.left = '50%';
|
| | message.style.transform = 'translateX(-50%)';
|
| | message.style.padding = '10px';
|
| | message.style.backgroundColor = 'white';
|
| | message.style.border = '1px solid red';
|
| | message.style.borderRadius = '5px';
|
| | message.style.zIndex = '1000';
|
| | document.body.appendChild(message);
|
| |
|
| |
|
| | setTimeout(() => {
|
| | document.body.removeChild(message);
|
| | }, 3000);
|
| |
|
| | return;
|
| | }
|
| |
|
| | const title = document.getElementById('title').value;
|
| | if (!title) {
|
| | alert('يرجى إدخال عنوان المقال.');
|
| | return;
|
| | }
|
| |
|
| | isCreating = true;
|
| | document.getElementById('loading-text').style.display = 'block';
|
| |
|
| | const articleSection = document.getElementById('articles');
|
| | const loadingSkeleton = document.createElement('div');
|
| | loadingSkeleton.classList.add('skeleton');
|
| | articleSection.prepend(loadingSkeleton);
|
| |
|
| | try {
|
| |
|
| | const response = await fetch('/create', {
|
| | method: 'POST',
|
| | headers: { 'Content-Type': 'application/json' },
|
| | body: JSON.stringify({ title })
|
| | });
|
| |
|
| | if (!response.ok) {
|
| | throw new Error('حدث خطأ أثناء إنشاء المقال.');
|
| | }
|
| |
|
| | const data = await response.json();
|
| |
|
| |
|
| | const newArticle = document.createElement('div');
|
| | newArticle.classList.add('article-box');
|
| | newArticle.setAttribute("data-idUser" , `${data.id_user}`)
|
| | newArticle.setAttribute('onclick', 'toggleContent(this)');
|
| | newArticle.innerHTML = `
|
| | <h3 class="article-title">${data.title}</h3>
|
| | <p class="article-meta">By: ${data.user} - ${new Date(data.created_at).toLocaleString()}</p>
|
| | <div class="article-content">
|
| | <div class="controls">
|
| | <button class="close-btn" onclick="closeContent(this)">×</button>
|
| | <div class="modal-header">${data.title}</div>
|
| | </div>
|
| | <div class="article-body">${data.content}</div>
|
| | <div class="modal-footer">
|
| | <img class="photo_user" src="${data.photo_user}" alt="User Photo">
|
| | <span class="user-info">By: ${data.user}</span>
|
| | <span class="date">${new Date(data.created_at).toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}</span>
|
| | <span class="time">${new Date(data.created_at).toLocaleTimeString()}</span>
|
| | </div>
|
| | </div>
|
| | `;
|
| |
|
| |
|
| | articleSection.removeChild(loadingSkeleton);
|
| | articleSection.prepend(newArticle);
|
| |
|
| | } catch (error) {
|
| | console.error(error);
|
| | alert('حدث خطأ أثناء إنشاء المقال.');
|
| | articleSection.removeChild(loadingSkeleton);
|
| | } finally {
|
| | isCreating = false;
|
| | document.getElementById('loading-text').style.display = 'none';
|
| | }
|
| | }
|
| |
|
| |
|
| | function searchArticles() {
|
| | const searchTerm = document.getElementById('search').value.toLowerCase();
|
| | const articles = document.querySelectorAll('.article-box');
|
| | articles.forEach(article => {
|
| | const title = article.querySelector('.article-title').textContent.toLowerCase();
|
| | if (title.includes(searchTerm)) {
|
| | article.style.display = 'block';
|
| | } else {
|
| | article.style.display = 'none';
|
| | }
|
| | });
|
| | }
|
| |
|
| |
|
| |
|
| | document.addEventListener('DOMContentLoaded', () => {
|
| |
|
| | const showMyArticlesButton = document.getElementById('showMyArticles');
|
| | if (showMyArticlesButton) {
|
| | showMyArticlesButton.addEventListener('click', async () => {
|
| | const currentUserId = await getCurrentUserId();
|
| |
|
| | if (currentUserId) {
|
| | console.log('ID المستخدم الحالي:', currentUserId);
|
| |
|
| |
|
| | const articles = document.querySelectorAll('.article-box');
|
| | articles.forEach(article => {
|
| | const articleUserId = article.getAttribute('data-iduser');
|
| | if (articleUserId == currentUserId) {
|
| | article.style.display = 'block';
|
| | } else {
|
| | article.style.display = 'none';
|
| | }
|
| | });
|
| | } else {
|
| | console.log('لم يتم العثور على id المستخدم.');
|
| | alert('يجب تسجيل الدخول لعرض مقالاتك.');
|
| | }
|
| | });
|
| | } else {
|
| | console.error('الزر "عرض مقالاتي" غير موجود في الصفحة.');
|
| | }
|
| |
|
| |
|
| | const showAllArticlesButton = document.getElementById('showAllArticles');
|
| | if (showAllArticlesButton) {
|
| | showAllArticlesButton.addEventListener('click', () => {
|
| |
|
| | const articles = document.querySelectorAll('.article-box');
|
| | articles.forEach(article => {
|
| | article.style.display = 'block';
|
| | });
|
| | });
|
| | } else {
|
| | console.error('الزر "عرض كل المقالات" غير موجود في الصفحة.');
|
| | }
|
| | });
|
| |
|
| |
|
| | async function getCurrentUserId() {
|
| | try {
|
| | const response = await fetch('/current_user_id', {
|
| | method: 'GET',
|
| | headers: {
|
| | 'Content-Type': 'application/json'
|
| | }
|
| | });
|
| |
|
| | if (!response.ok) {
|
| | throw new Error('فشل في جلب بيانات المستخدم');
|
| | }
|
| |
|
| | const data = await response.json();
|
| | return data.id;
|
| | } catch (error) {
|
| | console.error('حدث خطأ:', error);
|
| | return null;
|
| | }
|
| | }
|
| |
|
| | </script>
|
| | </head>
|
| | <body>
|
| |
|
| | <div id="loading-text" style="text-align: center; margin-top: 20px; display: none;">
|
| | <p>جاري الإنشاء...</p>
|
| | </div>
|
| |
|
| |
|
| | <div class="container">
|
| | <h1>مولد مقالات AI</h1>
|
| |
|
| |
|
| | <div class="search-box">
|
| | <input type="text" id="search" oninput="searchArticles()" placeholder="بحث عن مقال...">
|
| | </div>
|
| |
|
| | <input type="text" id="title" placeholder="أدخل عنوان المقال">
|
| | <button class="btn" onclick="createArticle()">أنشئ مقال</button>
|
| | <button id="showMyArticles">عرض مقالاتي</button>
|
| | <button id="showAllArticles">عرض كل المقالات</button>
|
| |
|
| | <div id="articles">
|
| |
|
| | {% for article in articles %}
|
| | <div class="article-box" data-idUser="{{ article.id_user }}" onclick="toggleContent(this)">
|
| | <h3 class="article-title">{{ article.title }}</h3>
|
| | <p class="article-meta">By: {{ article.user }} - {{ article.created_at.strftime('%Y-%m-%d %H:%M:%S') }}</p>
|
| | <div class="article-content">
|
| | <div class="controls">
|
| | <button class="close-btn" onclick="closeContent(this)">×</button>
|
| | <div class="modal-header ">{{ article.title }}</div>
|
| | </div>
|
| | <div class="article-body">{{ article.content | safe }}</div>
|
| | <div class="modal-footer">
|
| | <img class="photo_user" src="{{ url_for('static', filename=article.photo_user) }}" alt="User Photo">
|
| | <span class="user-info">By: {{ article.user }}</span>
|
| | <span class="date">{{ article.created_at.strftime('%A, %Y-%m-%d') }}</span>
|
| | <span class="time">{{ article.created_at.strftime('%H:%M') }}</span>
|
| | <div class="user-photo">
|
| | </div> </div>
|
| | </div>
|
| | </div>
|
| | {% endfor %}
|
| | </div>
|
| |
|
| |
|
| | </body>
|
| | </html>
|
| |
|