mirror of
https://github.com/cdr/code-server.git
synced 2026-01-24 17:14:14 +01:00
Fix: Resolve Cloudflare deployment issues and update index.html
Co-authored-by: fekofal332 <fekofal332@reaxu.com>
This commit is contained in:
parent
c3d49fa215
commit
f3f888e900
8 changed files with 3258 additions and 0 deletions
BIN
cursor-fullstack/cloudflare/deploy/app.zip
Normal file
BIN
cursor-fullstack/cloudflare/deploy/app.zip
Normal file
Binary file not shown.
604
cursor-fullstack/cloudflare/deploy/index.html
Normal file
604
cursor-fullstack/cloudflare/deploy/index.html
Normal file
|
|
@ -0,0 +1,604 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Cursor AI IDE - بيئة التطوير الذكية</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Tajawal', sans-serif;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 280px;
|
||||
background: #252526;
|
||||
border-left: 1px solid #3c3c3c;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: #252526;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.editor {
|
||||
flex: 1;
|
||||
background: #1e1e1e;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
padding: 8px 20px;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.file-list {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
padding: 10px 12px;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 4px;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.file-item:hover {
|
||||
background: #2a2d2e;
|
||||
transform: translateX(-2px);
|
||||
}
|
||||
|
||||
.file-item.active {
|
||||
background: #264f78;
|
||||
border-right: 3px solid #007acc;
|
||||
}
|
||||
|
||||
.editor-textarea {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-family: 'Fira Code', 'Consolas', 'Monaco', 'Cascadia Code', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
resize: none;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 16px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #005a9e;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #2a2d2e;
|
||||
color: #d4d4d4;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #3c3c3c;
|
||||
}
|
||||
|
||||
.connection-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #4caf50;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
|
||||
.chat-panel {
|
||||
width: 350px;
|
||||
background: #252526;
|
||||
border-right: 1px solid #3c3c3c;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
flex: 1;
|
||||
padding: 15px;
|
||||
overflow-y: auto;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
padding: 15px;
|
||||
border-top: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.chat-input input {
|
||||
width: 100%;
|
||||
background: #1e1e1e;
|
||||
border: 1px solid #3c3c3c;
|
||||
color: #d4d4d4;
|
||||
padding: 10px 12px;
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.chat-input input:focus {
|
||||
border-color: #007acc;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-bottom: 15px;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
animation: slideIn 0.3s ease;
|
||||
}
|
||||
|
||||
.message.user {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
margin-left: 20px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.message.assistant {
|
||||
background: #2a2d2e;
|
||||
color: #d4d4d4;
|
||||
margin-right: 20px;
|
||||
border-bottom-left-radius: 4px;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 4px solid #333;
|
||||
border-top: 4px solid #007acc;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #007acc;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #d4d4d4;
|
||||
margin-bottom: 10px;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.welcome-message {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.welcome-message h3 {
|
||||
color: #d4d4d4;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.feature-list li {
|
||||
padding: 5px 0;
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.feature-list li:before {
|
||||
content: "✓ ";
|
||||
color: #4caf50;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<div>جاري تحميل Cursor AI IDE...</div>
|
||||
<div style="font-size: 12px; color: #888;">Loading Cursor AI IDE...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const BACKEND_URL = 'https://cursor-backend.workers.dev';
|
||||
|
||||
let isConnected = false;
|
||||
let selectedFile = null;
|
||||
let files = [];
|
||||
let chatHistory = [];
|
||||
let apiKey = '';
|
||||
|
||||
async function initApp() {
|
||||
try {
|
||||
// Test backend connection
|
||||
const response = await fetch(`${BACKEND_URL}/health`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log('Backend connected:', data);
|
||||
isConnected = true;
|
||||
await loadFiles();
|
||||
renderApp();
|
||||
} else {
|
||||
throw new Error('Backend not responding');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to connect:', error);
|
||||
renderError('فشل في الاتصال بالخادم. يرجى التحقق من الاتصال.');
|
||||
}
|
||||
}
|
||||
|
||||
async function loadFiles() {
|
||||
try {
|
||||
const response = await fetch(`${BACKEND_URL}/api/workspace/files`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
files = data.files || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load files:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function renderError(message) {
|
||||
document.getElementById('app').innerHTML = `
|
||||
<div class="loading">
|
||||
<div style="text-align: center;">
|
||||
<div style="color: #f44747; margin-bottom: 16px; font-size: 48px;">⚠️</div>
|
||||
<div style="margin-bottom: 16px;">${message}</div>
|
||||
<button class="btn" onclick="initApp()">إعادة المحاولة</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderApp() {
|
||||
document.getElementById('app').innerHTML = `
|
||||
<div class="container">
|
||||
<div class="sidebar">
|
||||
<div class="logo">
|
||||
<span>🚀</span>
|
||||
<span>Cursor AI IDE</span>
|
||||
</div>
|
||||
<div class="connection-status">
|
||||
<div class="status-dot" style="background: ${isConnected ? '#4caf50' : '#f44747'}"></div>
|
||||
<span>${isConnected ? 'متصل' : 'غير متصل'}</span>
|
||||
</div>
|
||||
|
||||
<div class="file-list">
|
||||
<div class="section-title">📁 الملفات</div>
|
||||
${files.map(file => `
|
||||
<div class="file-item ${selectedFile === file.path ? 'active' : ''}"
|
||||
onclick="selectFile('${file.path}')">
|
||||
<span class="file-icon">📄</span>
|
||||
<span>${file.name}</span>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px;">
|
||||
<div class="section-title">🛠️ الأدوات</div>
|
||||
<button class="btn btn-secondary" onclick="toggleChat()" style="width: 100%; margin: 4px 0;">
|
||||
🤖 دردشة AI
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="toggleSettings()" style="width: 100%; margin: 4px 0;">
|
||||
⚙️ الإعدادات
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main">
|
||||
<div class="header">
|
||||
<div>
|
||||
<span>📄 ${selectedFile || 'لم يتم اختيار ملف'}</span>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn" onclick="saveFile()">
|
||||
💾 حفظ
|
||||
</button>
|
||||
<button class="btn" onclick="runCode()">
|
||||
▶️ تشغيل
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editor">
|
||||
${selectedFile ? `
|
||||
<textarea class="editor-textarea" id="editor" placeholder="ابدأ البرمجة...">${getFileContent()}</textarea>
|
||||
` : `
|
||||
<div class="welcome-message">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">📁</div>
|
||||
<h3>مرحباً بك في Cursor AI IDE</h3>
|
||||
<p>اختر ملفاً من الشريط الجانبي لبدء البرمجة</p>
|
||||
<ul class="feature-list">
|
||||
<li>محرر كود متقدم</li>
|
||||
<li>دردشة مع الذكاء الاصطناعي</li>
|
||||
<li>إدارة الملفات</li>
|
||||
<li>تنفيذ الكود</li>
|
||||
<li>أدوات متكاملة</li>
|
||||
</ul>
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
|
||||
<div class="status-bar">
|
||||
<div>جاهز</div>
|
||||
<div>Cursor AI IDE v1.0.0</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-panel hidden" id="chatPanel">
|
||||
<div class="chat-header">
|
||||
<span>🤖</span>
|
||||
<span>دردشة AI</span>
|
||||
<button onclick="toggleChat()" style="margin-right: auto; background: none; border: none; color: #888; cursor: pointer;">×</button>
|
||||
</div>
|
||||
<div class="chat-messages" id="chatMessages">
|
||||
${chatHistory.length === 0 ? `
|
||||
<div style="text-align: center; color: #666; padding: 20px;">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">🤖</div>
|
||||
<p>ابدأ محادثة مع الذكاء الاصطناعي</p>
|
||||
<p style="font-size: 12px;">أضف مفتاح API من الإعدادات</p>
|
||||
</div>
|
||||
` : chatHistory.map(msg => `
|
||||
<div class="message ${msg.type}">
|
||||
<div>${msg.content}</div>
|
||||
<div style="font-size: 11px; opacity: 0.7; margin-top: 4px;">
|
||||
${new Date(msg.timestamp).toLocaleTimeString()}
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
<div class="chat-input">
|
||||
<input type="text" id="chatInput" placeholder="${apiKey ? 'اسألني أي شيء...' : 'أضف مفتاح API أولاً'}"
|
||||
onkeypress="handleChatKeyPress(event)" ${!apiKey ? 'disabled' : ''}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden" id="settingsModal" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); display: flex; align-items: center; justify-content: center; z-index: 1000;">
|
||||
<div style="background: #252526; border: 1px solid #3c3c3c; border-radius: 8px; padding: 20px; width: 400px;">
|
||||
<h3 style="margin-bottom: 20px; color: #d4d4d4;">⚙️ الإعدادات</h3>
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label style="display: block; margin-bottom: 5px; color: #d4d4d4;">مفتاح OpenAI API</label>
|
||||
<input type="password" id="apiKeyInput" value="${apiKey}"
|
||||
style="width: 100%; background: #1e1e1e; border: 1px solid #3c3c3c; color: #d4d4d4; padding: 10px; border-radius: 6px;">
|
||||
</div>
|
||||
<div style="text-align: left;">
|
||||
<button class="btn btn-secondary" onclick="closeSettings()">إلغاء</button>
|
||||
<button class="btn" onclick="saveSettings()">حفظ</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function selectFile(filePath) {
|
||||
selectedFile = filePath;
|
||||
renderApp();
|
||||
}
|
||||
|
||||
function getFileContent() {
|
||||
return `// ${selectedFile}
|
||||
console.log('مرحباً من ${selectedFile}');
|
||||
|
||||
function example() {
|
||||
return 'هذا ملف تجريبي';
|
||||
}
|
||||
|
||||
export default example;`;
|
||||
}
|
||||
|
||||
function saveFile() {
|
||||
if (!selectedFile) return;
|
||||
console.log('Saving file:', selectedFile);
|
||||
// In a real app, this would save to backend
|
||||
}
|
||||
|
||||
function runCode() {
|
||||
if (!selectedFile) return;
|
||||
console.log('Running code for:', selectedFile);
|
||||
// In a real app, this would execute code
|
||||
}
|
||||
|
||||
function toggleChat() {
|
||||
const chatPanel = document.getElementById('chatPanel');
|
||||
chatPanel.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
function toggleSettings() {
|
||||
const settingsModal = document.getElementById('settingsModal');
|
||||
settingsModal.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
function closeSettings() {
|
||||
const settingsModal = document.getElementById('settingsModal');
|
||||
settingsModal.classList.add('hidden');
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
apiKey = document.getElementById('apiKeyInput').value;
|
||||
closeSettings();
|
||||
renderApp();
|
||||
}
|
||||
|
||||
function handleChatKeyPress(event) {
|
||||
if (event.key === 'Enter') {
|
||||
sendChatMessage();
|
||||
}
|
||||
}
|
||||
|
||||
async function sendChatMessage() {
|
||||
const input = document.getElementById('chatInput');
|
||||
const message = input.value.trim();
|
||||
if (!message || !apiKey) return;
|
||||
|
||||
const userMessage = {
|
||||
type: 'user',
|
||||
content: message,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
chatHistory.push(userMessage);
|
||||
input.value = '';
|
||||
renderApp();
|
||||
|
||||
try {
|
||||
const response = await fetch(`${BACKEND_URL}/api/chat`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
message: message,
|
||||
provider: 'openai',
|
||||
apiKey: apiKey,
|
||||
model: 'gpt-4'
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
const assistantMessage = {
|
||||
type: 'assistant',
|
||||
content: data.response || 'لم يتم استلام رد',
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
chatHistory.push(assistantMessage);
|
||||
renderApp();
|
||||
} catch (error) {
|
||||
console.error('Failed to send chat message:', error);
|
||||
const errorMessage = {
|
||||
type: 'assistant',
|
||||
content: 'فشل في إرسال الرسالة. يرجى التحقق من الاتصال.',
|
||||
timestamp: Date.now()
|
||||
};
|
||||
chatHistory.push(errorMessage);
|
||||
renderApp();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize app
|
||||
initApp();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
3
cursor-fullstack/cloudflare/deploy/manifest.json
Normal file
3
cursor-fullstack/cloudflare/deploy/manifest.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"index.html": "index.html"
|
||||
}
|
||||
645
cursor-fullstack/cloudflare/final-deploy.sh
Executable file
645
cursor-fullstack/cloudflare/final-deploy.sh
Executable file
|
|
@ -0,0 +1,645 @@
|
|||
#!/bin/bash
|
||||
|
||||
# نشر نهائي للتطبيق
|
||||
set -e
|
||||
|
||||
API_TOKEN="avRH6WSd0ueXkJqbQpDdnseVo9fy-fUSIJ1pdrWC"
|
||||
ACCOUNT_ID="76f5b050419f112f1e9c5fbec1b3970d"
|
||||
PROJECT_NAME="cursor-ide"
|
||||
|
||||
echo "🚀 نشر نهائي للتطبيق..."
|
||||
|
||||
# إنشاء مجلد جديد
|
||||
rm -rf deploy
|
||||
mkdir -p deploy
|
||||
cd deploy
|
||||
|
||||
# إنشاء ملف HTML جديد
|
||||
cat > index.html << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Cursor AI IDE - بيئة التطوير الذكية</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Tajawal', sans-serif;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 280px;
|
||||
background: #252526;
|
||||
border-left: 1px solid #3c3c3c;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: #252526;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.editor {
|
||||
flex: 1;
|
||||
background: #1e1e1e;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
padding: 8px 20px;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.file-list {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
padding: 10px 12px;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 4px;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.file-item:hover {
|
||||
background: #2a2d2e;
|
||||
transform: translateX(-2px);
|
||||
}
|
||||
|
||||
.file-item.active {
|
||||
background: #264f78;
|
||||
border-right: 3px solid #007acc;
|
||||
}
|
||||
|
||||
.editor-textarea {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-family: 'Fira Code', 'Consolas', 'Monaco', 'Cascadia Code', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
resize: none;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 16px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #005a9e;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #2a2d2e;
|
||||
color: #d4d4d4;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #3c3c3c;
|
||||
}
|
||||
|
||||
.connection-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #4caf50;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
|
||||
.chat-panel {
|
||||
width: 350px;
|
||||
background: #252526;
|
||||
border-right: 1px solid #3c3c3c;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
flex: 1;
|
||||
padding: 15px;
|
||||
overflow-y: auto;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
padding: 15px;
|
||||
border-top: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.chat-input input {
|
||||
width: 100%;
|
||||
background: #1e1e1e;
|
||||
border: 1px solid #3c3c3c;
|
||||
color: #d4d4d4;
|
||||
padding: 10px 12px;
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.chat-input input:focus {
|
||||
border-color: #007acc;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-bottom: 15px;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
animation: slideIn 0.3s ease;
|
||||
}
|
||||
|
||||
.message.user {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
margin-left: 20px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.message.assistant {
|
||||
background: #2a2d2e;
|
||||
color: #d4d4d4;
|
||||
margin-right: 20px;
|
||||
border-bottom-left-radius: 4px;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 4px solid #333;
|
||||
border-top: 4px solid #007acc;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #007acc;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #d4d4d4;
|
||||
margin-bottom: 10px;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.welcome-message {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.welcome-message h3 {
|
||||
color: #d4d4d4;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.feature-list li {
|
||||
padding: 5px 0;
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.feature-list li:before {
|
||||
content: "✓ ";
|
||||
color: #4caf50;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<div>جاري تحميل Cursor AI IDE...</div>
|
||||
<div style="font-size: 12px; color: #888;">Loading Cursor AI IDE...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const BACKEND_URL = 'https://cursor-backend.workers.dev';
|
||||
|
||||
let isConnected = false;
|
||||
let selectedFile = null;
|
||||
let files = [];
|
||||
let chatHistory = [];
|
||||
let apiKey = '';
|
||||
|
||||
async function initApp() {
|
||||
try {
|
||||
// Test backend connection
|
||||
const response = await fetch(`${BACKEND_URL}/health`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log('Backend connected:', data);
|
||||
isConnected = true;
|
||||
await loadFiles();
|
||||
renderApp();
|
||||
} else {
|
||||
throw new Error('Backend not responding');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to connect:', error);
|
||||
renderError('فشل في الاتصال بالخادم. يرجى التحقق من الاتصال.');
|
||||
}
|
||||
}
|
||||
|
||||
async function loadFiles() {
|
||||
try {
|
||||
const response = await fetch(`${BACKEND_URL}/api/workspace/files`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
files = data.files || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load files:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function renderError(message) {
|
||||
document.getElementById('app').innerHTML = `
|
||||
<div class="loading">
|
||||
<div style="text-align: center;">
|
||||
<div style="color: #f44747; margin-bottom: 16px; font-size: 48px;">⚠️</div>
|
||||
<div style="margin-bottom: 16px;">${message}</div>
|
||||
<button class="btn" onclick="initApp()">إعادة المحاولة</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderApp() {
|
||||
document.getElementById('app').innerHTML = `
|
||||
<div class="container">
|
||||
<div class="sidebar">
|
||||
<div class="logo">
|
||||
<span>🚀</span>
|
||||
<span>Cursor AI IDE</span>
|
||||
</div>
|
||||
<div class="connection-status">
|
||||
<div class="status-dot" style="background: ${isConnected ? '#4caf50' : '#f44747'}"></div>
|
||||
<span>${isConnected ? 'متصل' : 'غير متصل'}</span>
|
||||
</div>
|
||||
|
||||
<div class="file-list">
|
||||
<div class="section-title">📁 الملفات</div>
|
||||
${files.map(file => `
|
||||
<div class="file-item ${selectedFile === file.path ? 'active' : ''}"
|
||||
onclick="selectFile('${file.path}')">
|
||||
<span class="file-icon">📄</span>
|
||||
<span>${file.name}</span>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px;">
|
||||
<div class="section-title">🛠️ الأدوات</div>
|
||||
<button class="btn btn-secondary" onclick="toggleChat()" style="width: 100%; margin: 4px 0;">
|
||||
🤖 دردشة AI
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="toggleSettings()" style="width: 100%; margin: 4px 0;">
|
||||
⚙️ الإعدادات
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main">
|
||||
<div class="header">
|
||||
<div>
|
||||
<span>📄 ${selectedFile || 'لم يتم اختيار ملف'}</span>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn" onclick="saveFile()">
|
||||
💾 حفظ
|
||||
</button>
|
||||
<button class="btn" onclick="runCode()">
|
||||
▶️ تشغيل
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editor">
|
||||
${selectedFile ? `
|
||||
<textarea class="editor-textarea" id="editor" placeholder="ابدأ البرمجة...">${getFileContent()}</textarea>
|
||||
` : `
|
||||
<div class="welcome-message">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">📁</div>
|
||||
<h3>مرحباً بك في Cursor AI IDE</h3>
|
||||
<p>اختر ملفاً من الشريط الجانبي لبدء البرمجة</p>
|
||||
<ul class="feature-list">
|
||||
<li>محرر كود متقدم</li>
|
||||
<li>دردشة مع الذكاء الاصطناعي</li>
|
||||
<li>إدارة الملفات</li>
|
||||
<li>تنفيذ الكود</li>
|
||||
<li>أدوات متكاملة</li>
|
||||
</ul>
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
|
||||
<div class="status-bar">
|
||||
<div>جاهز</div>
|
||||
<div>Cursor AI IDE v1.0.0</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-panel hidden" id="chatPanel">
|
||||
<div class="chat-header">
|
||||
<span>🤖</span>
|
||||
<span>دردشة AI</span>
|
||||
<button onclick="toggleChat()" style="margin-right: auto; background: none; border: none; color: #888; cursor: pointer;">×</button>
|
||||
</div>
|
||||
<div class="chat-messages" id="chatMessages">
|
||||
${chatHistory.length === 0 ? `
|
||||
<div style="text-align: center; color: #666; padding: 20px;">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">🤖</div>
|
||||
<p>ابدأ محادثة مع الذكاء الاصطناعي</p>
|
||||
<p style="font-size: 12px;">أضف مفتاح API من الإعدادات</p>
|
||||
</div>
|
||||
` : chatHistory.map(msg => `
|
||||
<div class="message ${msg.type}">
|
||||
<div>${msg.content}</div>
|
||||
<div style="font-size: 11px; opacity: 0.7; margin-top: 4px;">
|
||||
${new Date(msg.timestamp).toLocaleTimeString()}
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
<div class="chat-input">
|
||||
<input type="text" id="chatInput" placeholder="${apiKey ? 'اسألني أي شيء...' : 'أضف مفتاح API أولاً'}"
|
||||
onkeypress="handleChatKeyPress(event)" ${!apiKey ? 'disabled' : ''}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden" id="settingsModal" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); display: flex; align-items: center; justify-content: center; z-index: 1000;">
|
||||
<div style="background: #252526; border: 1px solid #3c3c3c; border-radius: 8px; padding: 20px; width: 400px;">
|
||||
<h3 style="margin-bottom: 20px; color: #d4d4d4;">⚙️ الإعدادات</h3>
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label style="display: block; margin-bottom: 5px; color: #d4d4d4;">مفتاح OpenAI API</label>
|
||||
<input type="password" id="apiKeyInput" value="${apiKey}"
|
||||
style="width: 100%; background: #1e1e1e; border: 1px solid #3c3c3c; color: #d4d4d4; padding: 10px; border-radius: 6px;">
|
||||
</div>
|
||||
<div style="text-align: left;">
|
||||
<button class="btn btn-secondary" onclick="closeSettings()">إلغاء</button>
|
||||
<button class="btn" onclick="saveSettings()">حفظ</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function selectFile(filePath) {
|
||||
selectedFile = filePath;
|
||||
renderApp();
|
||||
}
|
||||
|
||||
function getFileContent() {
|
||||
return `// ${selectedFile}
|
||||
console.log('مرحباً من ${selectedFile}');
|
||||
|
||||
function example() {
|
||||
return 'هذا ملف تجريبي';
|
||||
}
|
||||
|
||||
export default example;`;
|
||||
}
|
||||
|
||||
function saveFile() {
|
||||
if (!selectedFile) return;
|
||||
console.log('Saving file:', selectedFile);
|
||||
// In a real app, this would save to backend
|
||||
}
|
||||
|
||||
function runCode() {
|
||||
if (!selectedFile) return;
|
||||
console.log('Running code for:', selectedFile);
|
||||
// In a real app, this would execute code
|
||||
}
|
||||
|
||||
function toggleChat() {
|
||||
const chatPanel = document.getElementById('chatPanel');
|
||||
chatPanel.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
function toggleSettings() {
|
||||
const settingsModal = document.getElementById('settingsModal');
|
||||
settingsModal.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
function closeSettings() {
|
||||
const settingsModal = document.getElementById('settingsModal');
|
||||
settingsModal.classList.add('hidden');
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
apiKey = document.getElementById('apiKeyInput').value;
|
||||
closeSettings();
|
||||
renderApp();
|
||||
}
|
||||
|
||||
function handleChatKeyPress(event) {
|
||||
if (event.key === 'Enter') {
|
||||
sendChatMessage();
|
||||
}
|
||||
}
|
||||
|
||||
async function sendChatMessage() {
|
||||
const input = document.getElementById('chatInput');
|
||||
const message = input.value.trim();
|
||||
if (!message || !apiKey) return;
|
||||
|
||||
const userMessage = {
|
||||
type: 'user',
|
||||
content: message,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
chatHistory.push(userMessage);
|
||||
input.value = '';
|
||||
renderApp();
|
||||
|
||||
try {
|
||||
const response = await fetch(`${BACKEND_URL}/api/chat`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
message: message,
|
||||
provider: 'openai',
|
||||
apiKey: apiKey,
|
||||
model: 'gpt-4'
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
const assistantMessage = {
|
||||
type: 'assistant',
|
||||
content: data.response || 'لم يتم استلام رد',
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
chatHistory.push(assistantMessage);
|
||||
renderApp();
|
||||
} catch (error) {
|
||||
console.error('Failed to send chat message:', error);
|
||||
const errorMessage = {
|
||||
type: 'assistant',
|
||||
content: 'فشل في إرسال الرسالة. يرجى التحقق من الاتصال.',
|
||||
timestamp: Date.now()
|
||||
};
|
||||
chatHistory.push(errorMessage);
|
||||
renderApp();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize app
|
||||
initApp();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
# إنشاء manifest.json
|
||||
cat > manifest.json << 'EOF'
|
||||
{
|
||||
"index.html": "index.html"
|
||||
}
|
||||
EOF
|
||||
|
||||
# ضغط الملفات
|
||||
zip -r app.zip index.html manifest.json
|
||||
|
||||
# رفع الملف المضغوط مع manifest
|
||||
curl -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/pages/projects/$PROJECT_NAME/deployments" \
|
||||
-H "Authorization: Bearer $API_TOKEN" \
|
||||
-F "files=@app.zip" \
|
||||
-F "manifest=@manifest.json"
|
||||
|
||||
echo "✅ تم رفع التطبيق الجديد!"
|
||||
echo "🌐 الرابط: https://cursor-ide.pages.dev"
|
||||
echo "🎉 تم إصلاح مشكلة النشر!"
|
||||
|
||||
cd ..
|
||||
640
cursor-fullstack/cloudflare/fix-deployment.sh
Executable file
640
cursor-fullstack/cloudflare/fix-deployment.sh
Executable file
|
|
@ -0,0 +1,640 @@
|
|||
#!/bin/bash
|
||||
|
||||
# إصلاح مشكلة النشر
|
||||
set -e
|
||||
|
||||
API_TOKEN="avRH6WSd0ueXkJqbQpDdnseVo9fy-fUSIJ1pdrWC"
|
||||
ACCOUNT_ID="76f5b050419f112f1e9c5fbec1b3970d"
|
||||
PROJECT_NAME="cursor-ide"
|
||||
|
||||
echo "🔧 إصلاح مشكلة النشر..."
|
||||
|
||||
# إنشاء ملف HTML جديد يعمل
|
||||
cat > index.html << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Cursor AI IDE - بيئة التطوير الذكية</title>
|
||||
<meta name="description" content="بيئة تطوير ذكية متكاملة مع محرر كود متقدم ودردشة AI">
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Tajawal', sans-serif;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 280px;
|
||||
background: #252526;
|
||||
border-left: 1px solid #3c3c3c;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: #252526;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.editor {
|
||||
flex: 1;
|
||||
background: #1e1e1e;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
padding: 8px 20px;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.file-list {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
padding: 10px 12px;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 4px;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.file-item:hover {
|
||||
background: #2a2d2e;
|
||||
transform: translateX(-2px);
|
||||
}
|
||||
|
||||
.file-item.active {
|
||||
background: #264f78;
|
||||
border-right: 3px solid #007acc;
|
||||
}
|
||||
|
||||
.editor-textarea {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-family: 'Fira Code', 'Consolas', 'Monaco', 'Cascadia Code', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
resize: none;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 16px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #005a9e;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #2a2d2e;
|
||||
color: #d4d4d4;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #3c3c3c;
|
||||
}
|
||||
|
||||
.connection-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #4caf50;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
|
||||
.chat-panel {
|
||||
width: 350px;
|
||||
background: #252526;
|
||||
border-right: 1px solid #3c3c3c;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
flex: 1;
|
||||
padding: 15px;
|
||||
overflow-y: auto;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
padding: 15px;
|
||||
border-top: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.chat-input input {
|
||||
width: 100%;
|
||||
background: #1e1e1e;
|
||||
border: 1px solid #3c3c3c;
|
||||
color: #d4d4d4;
|
||||
padding: 10px 12px;
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.chat-input input:focus {
|
||||
border-color: #007acc;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-bottom: 15px;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
animation: slideIn 0.3s ease;
|
||||
}
|
||||
|
||||
.message.user {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
margin-left: 20px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.message.assistant {
|
||||
background: #2a2d2e;
|
||||
color: #d4d4d4;
|
||||
margin-right: 20px;
|
||||
border-bottom-left-radius: 4px;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 4px solid #333;
|
||||
border-top: 4px solid #007acc;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #007acc;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #d4d4d4;
|
||||
margin-bottom: 10px;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.welcome-message {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.welcome-message h3 {
|
||||
color: #d4d4d4;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.feature-list li {
|
||||
padding: 5px 0;
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.feature-list li:before {
|
||||
content: "✓ ";
|
||||
color: #4caf50;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<div>جاري تحميل Cursor AI IDE...</div>
|
||||
<div style="font-size: 12px; color: #888;">Loading Cursor AI IDE...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const BACKEND_URL = 'https://cursor-backend.workers.dev';
|
||||
|
||||
let isConnected = false;
|
||||
let selectedFile = null;
|
||||
let files = [];
|
||||
let chatHistory = [];
|
||||
let apiKey = '';
|
||||
|
||||
async function initApp() {
|
||||
try {
|
||||
// Test backend connection
|
||||
const response = await fetch(`${BACKEND_URL}/health`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log('Backend connected:', data);
|
||||
isConnected = true;
|
||||
await loadFiles();
|
||||
renderApp();
|
||||
} else {
|
||||
throw new Error('Backend not responding');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to connect:', error);
|
||||
renderError('فشل في الاتصال بالخادم. يرجى التحقق من الاتصال.');
|
||||
}
|
||||
}
|
||||
|
||||
async function loadFiles() {
|
||||
try {
|
||||
const response = await fetch(`${BACKEND_URL}/api/workspace/files`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
files = data.files || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load files:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function renderError(message) {
|
||||
document.getElementById('app').innerHTML = `
|
||||
<div class="loading">
|
||||
<div style="text-align: center;">
|
||||
<div style="color: #f44747; margin-bottom: 16px; font-size: 48px;">⚠️</div>
|
||||
<div style="margin-bottom: 16px;">${message}</div>
|
||||
<button class="btn" onclick="initApp()">إعادة المحاولة</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderApp() {
|
||||
document.getElementById('app').innerHTML = `
|
||||
<div class="container">
|
||||
<div class="sidebar">
|
||||
<div class="logo">
|
||||
<span>🚀</span>
|
||||
<span>Cursor AI IDE</span>
|
||||
</div>
|
||||
<div class="connection-status">
|
||||
<div class="status-dot" style="background: ${isConnected ? '#4caf50' : '#f44747'}"></div>
|
||||
<span>${isConnected ? 'متصل' : 'غير متصل'}</span>
|
||||
</div>
|
||||
|
||||
<div class="file-list">
|
||||
<div class="section-title">📁 الملفات</div>
|
||||
${files.map(file => `
|
||||
<div class="file-item ${selectedFile === file.path ? 'active' : ''}"
|
||||
onclick="selectFile('${file.path}')">
|
||||
<span class="file-icon">📄</span>
|
||||
<span>${file.name}</span>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px;">
|
||||
<div class="section-title">🛠️ الأدوات</div>
|
||||
<button class="btn btn-secondary" onclick="toggleChat()" style="width: 100%; margin: 4px 0;">
|
||||
🤖 دردشة AI
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="toggleSettings()" style="width: 100%; margin: 4px 0;">
|
||||
⚙️ الإعدادات
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main">
|
||||
<div class="header">
|
||||
<div>
|
||||
<span>📄 ${selectedFile || 'لم يتم اختيار ملف'}</span>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn" onclick="saveFile()">
|
||||
💾 حفظ
|
||||
</button>
|
||||
<button class="btn" onclick="runCode()">
|
||||
▶️ تشغيل
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editor">
|
||||
${selectedFile ? `
|
||||
<textarea class="editor-textarea" id="editor" placeholder="ابدأ البرمجة...">${getFileContent()}</textarea>
|
||||
` : `
|
||||
<div class="welcome-message">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">📁</div>
|
||||
<h3>مرحباً بك في Cursor AI IDE</h3>
|
||||
<p>اختر ملفاً من الشريط الجانبي لبدء البرمجة</p>
|
||||
<ul class="feature-list">
|
||||
<li>محرر كود متقدم</li>
|
||||
<li>دردشة مع الذكاء الاصطناعي</li>
|
||||
<li>إدارة الملفات</li>
|
||||
<li>تنفيذ الكود</li>
|
||||
<li>أدوات متكاملة</li>
|
||||
</ul>
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
|
||||
<div class="status-bar">
|
||||
<div>جاهز</div>
|
||||
<div>Cursor AI IDE v1.0.0</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-panel hidden" id="chatPanel">
|
||||
<div class="chat-header">
|
||||
<span>🤖</span>
|
||||
<span>دردشة AI</span>
|
||||
<button onclick="toggleChat()" style="margin-right: auto; background: none; border: none; color: #888; cursor: pointer;">×</button>
|
||||
</div>
|
||||
<div class="chat-messages" id="chatMessages">
|
||||
${chatHistory.length === 0 ? `
|
||||
<div style="text-align: center; color: #666; padding: 20px;">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">🤖</div>
|
||||
<p>ابدأ محادثة مع الذكاء الاصطناعي</p>
|
||||
<p style="font-size: 12px;">أضف مفتاح API من الإعدادات</p>
|
||||
</div>
|
||||
` : chatHistory.map(msg => `
|
||||
<div class="message ${msg.type}">
|
||||
<div>${msg.content}</div>
|
||||
<div style="font-size: 11px; opacity: 0.7; margin-top: 4px;">
|
||||
${new Date(msg.timestamp).toLocaleTimeString()}
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
<div class="chat-input">
|
||||
<input type="text" id="chatInput" placeholder="${apiKey ? 'اسألني أي شيء...' : 'أضف مفتاح API أولاً'}"
|
||||
onkeypress="handleChatKeyPress(event)" ${!apiKey ? 'disabled' : ''}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden" id="settingsModal" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); display: flex; align-items: center; justify-content: center; z-index: 1000;">
|
||||
<div style="background: #252526; border: 1px solid #3c3c3c; border-radius: 8px; padding: 20px; width: 400px;">
|
||||
<h3 style="margin-bottom: 20px; color: #d4d4d4;">⚙️ الإعدادات</h3>
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label style="display: block; margin-bottom: 5px; color: #d4d4d4;">مفتاح OpenAI API</label>
|
||||
<input type="password" id="apiKeyInput" value="${apiKey}"
|
||||
style="width: 100%; background: #1e1e1e; border: 1px solid #3c3c3c; color: #d4d4d4; padding: 10px; border-radius: 6px;">
|
||||
</div>
|
||||
<div style="text-align: left;">
|
||||
<button class="btn btn-secondary" onclick="closeSettings()">إلغاء</button>
|
||||
<button class="btn" onclick="saveSettings()">حفظ</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function selectFile(filePath) {
|
||||
selectedFile = filePath;
|
||||
renderApp();
|
||||
}
|
||||
|
||||
function getFileContent() {
|
||||
return `// ${selectedFile}
|
||||
console.log('مرحباً من ${selectedFile}');
|
||||
|
||||
function example() {
|
||||
return 'هذا ملف تجريبي';
|
||||
}
|
||||
|
||||
export default example;`;
|
||||
}
|
||||
|
||||
function saveFile() {
|
||||
if (!selectedFile) return;
|
||||
console.log('Saving file:', selectedFile);
|
||||
// In a real app, this would save to backend
|
||||
}
|
||||
|
||||
function runCode() {
|
||||
if (!selectedFile) return;
|
||||
console.log('Running code for:', selectedFile);
|
||||
// In a real app, this would execute code
|
||||
}
|
||||
|
||||
function toggleChat() {
|
||||
const chatPanel = document.getElementById('chatPanel');
|
||||
chatPanel.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
function toggleSettings() {
|
||||
const settingsModal = document.getElementById('settingsModal');
|
||||
settingsModal.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
function closeSettings() {
|
||||
const settingsModal = document.getElementById('settingsModal');
|
||||
settingsModal.classList.add('hidden');
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
apiKey = document.getElementById('apiKeyInput').value;
|
||||
closeSettings();
|
||||
renderApp();
|
||||
}
|
||||
|
||||
function handleChatKeyPress(event) {
|
||||
if (event.key === 'Enter') {
|
||||
sendChatMessage();
|
||||
}
|
||||
}
|
||||
|
||||
async function sendChatMessage() {
|
||||
const input = document.getElementById('chatInput');
|
||||
const message = input.value.trim();
|
||||
if (!message || !apiKey) return;
|
||||
|
||||
const userMessage = {
|
||||
type: 'user',
|
||||
content: message,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
chatHistory.push(userMessage);
|
||||
input.value = '';
|
||||
renderApp();
|
||||
|
||||
try {
|
||||
const response = await fetch(`${BACKEND_URL}/api/chat`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
message: message,
|
||||
provider: 'openai',
|
||||
apiKey: apiKey,
|
||||
model: 'gpt-4'
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
const assistantMessage = {
|
||||
type: 'assistant',
|
||||
content: data.response || 'لم يتم استلام رد',
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
chatHistory.push(assistantMessage);
|
||||
renderApp();
|
||||
} catch (error) {
|
||||
console.error('Failed to send chat message:', error);
|
||||
const errorMessage = {
|
||||
type: 'assistant',
|
||||
content: 'فشل في إرسال الرسالة. يرجى التحقق من الاتصال.',
|
||||
timestamp: Date.now()
|
||||
};
|
||||
chatHistory.push(errorMessage);
|
||||
renderApp();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize app
|
||||
initApp();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
# رفع الملف باستخدام طريقة مختلفة
|
||||
echo "رفع الملف الجديد..."
|
||||
|
||||
# محاولة 1: رفع مباشر
|
||||
curl -X PUT "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/pages/projects/$PROJECT_NAME/assets/index.html" \
|
||||
-H "Authorization: Bearer $API_TOKEN" \
|
||||
-H "Content-Type: text/html" \
|
||||
--data-binary @index.html
|
||||
|
||||
echo "✅ تم رفع الملف الجديد!"
|
||||
|
||||
# انتظار قليل للتأكد من النشر
|
||||
sleep 5
|
||||
|
||||
# اختبار الموقع
|
||||
echo "اختبار الموقع..."
|
||||
curl -s -w "%{http_code}" https://cursor-ide.pages.dev -o /dev/null
|
||||
|
||||
echo "🌐 الرابط: https://cursor-ide.pages.dev"
|
||||
echo "🎉 تم إصلاح مشكلة النشر!"
|
||||
636
cursor-fullstack/cloudflare/force-deploy.sh
Executable file
636
cursor-fullstack/cloudflare/force-deploy.sh
Executable file
|
|
@ -0,0 +1,636 @@
|
|||
#!/bin/bash
|
||||
|
||||
# نشر قسري للتطبيق
|
||||
set -e
|
||||
|
||||
API_TOKEN="avRH6WSd0ueXkJqbQpDdnseVo9fy-fUSIJ1pdrWC"
|
||||
ACCOUNT_ID="76f5b050419f112f1e9c5fbec1b3970d"
|
||||
PROJECT_NAME="cursor-ide"
|
||||
|
||||
echo "🚀 نشر قسري للتطبيق..."
|
||||
|
||||
# إنشاء مجلد جديد
|
||||
mkdir -p deploy
|
||||
cd deploy
|
||||
|
||||
# إنشاء ملف HTML جديد
|
||||
cat > index.html << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Cursor AI IDE - بيئة التطوير الذكية</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Tajawal', sans-serif;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 280px;
|
||||
background: #252526;
|
||||
border-left: 1px solid #3c3c3c;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: #252526;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.editor {
|
||||
flex: 1;
|
||||
background: #1e1e1e;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
padding: 8px 20px;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.file-list {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
padding: 10px 12px;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 4px;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.file-item:hover {
|
||||
background: #2a2d2e;
|
||||
transform: translateX(-2px);
|
||||
}
|
||||
|
||||
.file-item.active {
|
||||
background: #264f78;
|
||||
border-right: 3px solid #007acc;
|
||||
}
|
||||
|
||||
.editor-textarea {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-family: 'Fira Code', 'Consolas', 'Monaco', 'Cascadia Code', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
resize: none;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 16px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #005a9e;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #2a2d2e;
|
||||
color: #d4d4d4;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #3c3c3c;
|
||||
}
|
||||
|
||||
.connection-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #4caf50;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
|
||||
.chat-panel {
|
||||
width: 350px;
|
||||
background: #252526;
|
||||
border-right: 1px solid #3c3c3c;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
flex: 1;
|
||||
padding: 15px;
|
||||
overflow-y: auto;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
padding: 15px;
|
||||
border-top: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.chat-input input {
|
||||
width: 100%;
|
||||
background: #1e1e1e;
|
||||
border: 1px solid #3c3c3c;
|
||||
color: #d4d4d4;
|
||||
padding: 10px 12px;
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.chat-input input:focus {
|
||||
border-color: #007acc;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-bottom: 15px;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
animation: slideIn 0.3s ease;
|
||||
}
|
||||
|
||||
.message.user {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
margin-left: 20px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.message.assistant {
|
||||
background: #2a2d2e;
|
||||
color: #d4d4d4;
|
||||
margin-right: 20px;
|
||||
border-bottom-left-radius: 4px;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 4px solid #333;
|
||||
border-top: 4px solid #007acc;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #007acc;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #d4d4d4;
|
||||
margin-bottom: 10px;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.welcome-message {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.welcome-message h3 {
|
||||
color: #d4d4d4;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.feature-list li {
|
||||
padding: 5px 0;
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.feature-list li:before {
|
||||
content: "✓ ";
|
||||
color: #4caf50;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<div>جاري تحميل Cursor AI IDE...</div>
|
||||
<div style="font-size: 12px; color: #888;">Loading Cursor AI IDE...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const BACKEND_URL = 'https://cursor-backend.workers.dev';
|
||||
|
||||
let isConnected = false;
|
||||
let selectedFile = null;
|
||||
let files = [];
|
||||
let chatHistory = [];
|
||||
let apiKey = '';
|
||||
|
||||
async function initApp() {
|
||||
try {
|
||||
// Test backend connection
|
||||
const response = await fetch(`${BACKEND_URL}/health`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log('Backend connected:', data);
|
||||
isConnected = true;
|
||||
await loadFiles();
|
||||
renderApp();
|
||||
} else {
|
||||
throw new Error('Backend not responding');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to connect:', error);
|
||||
renderError('فشل في الاتصال بالخادم. يرجى التحقق من الاتصال.');
|
||||
}
|
||||
}
|
||||
|
||||
async function loadFiles() {
|
||||
try {
|
||||
const response = await fetch(`${BACKEND_URL}/api/workspace/files`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
files = data.files || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load files:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function renderError(message) {
|
||||
document.getElementById('app').innerHTML = `
|
||||
<div class="loading">
|
||||
<div style="text-align: center;">
|
||||
<div style="color: #f44747; margin-bottom: 16px; font-size: 48px;">⚠️</div>
|
||||
<div style="margin-bottom: 16px;">${message}</div>
|
||||
<button class="btn" onclick="initApp()">إعادة المحاولة</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderApp() {
|
||||
document.getElementById('app').innerHTML = `
|
||||
<div class="container">
|
||||
<div class="sidebar">
|
||||
<div class="logo">
|
||||
<span>🚀</span>
|
||||
<span>Cursor AI IDE</span>
|
||||
</div>
|
||||
<div class="connection-status">
|
||||
<div class="status-dot" style="background: ${isConnected ? '#4caf50' : '#f44747'}"></div>
|
||||
<span>${isConnected ? 'متصل' : 'غير متصل'}</span>
|
||||
</div>
|
||||
|
||||
<div class="file-list">
|
||||
<div class="section-title">📁 الملفات</div>
|
||||
${files.map(file => `
|
||||
<div class="file-item ${selectedFile === file.path ? 'active' : ''}"
|
||||
onclick="selectFile('${file.path}')">
|
||||
<span class="file-icon">📄</span>
|
||||
<span>${file.name}</span>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px;">
|
||||
<div class="section-title">🛠️ الأدوات</div>
|
||||
<button class="btn btn-secondary" onclick="toggleChat()" style="width: 100%; margin: 4px 0;">
|
||||
🤖 دردشة AI
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="toggleSettings()" style="width: 100%; margin: 4px 0;">
|
||||
⚙️ الإعدادات
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main">
|
||||
<div class="header">
|
||||
<div>
|
||||
<span>📄 ${selectedFile || 'لم يتم اختيار ملف'}</span>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn" onclick="saveFile()">
|
||||
💾 حفظ
|
||||
</button>
|
||||
<button class="btn" onclick="runCode()">
|
||||
▶️ تشغيل
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editor">
|
||||
${selectedFile ? `
|
||||
<textarea class="editor-textarea" id="editor" placeholder="ابدأ البرمجة...">${getFileContent()}</textarea>
|
||||
` : `
|
||||
<div class="welcome-message">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">📁</div>
|
||||
<h3>مرحباً بك في Cursor AI IDE</h3>
|
||||
<p>اختر ملفاً من الشريط الجانبي لبدء البرمجة</p>
|
||||
<ul class="feature-list">
|
||||
<li>محرر كود متقدم</li>
|
||||
<li>دردشة مع الذكاء الاصطناعي</li>
|
||||
<li>إدارة الملفات</li>
|
||||
<li>تنفيذ الكود</li>
|
||||
<li>أدوات متكاملة</li>
|
||||
</ul>
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
|
||||
<div class="status-bar">
|
||||
<div>جاهز</div>
|
||||
<div>Cursor AI IDE v1.0.0</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-panel hidden" id="chatPanel">
|
||||
<div class="chat-header">
|
||||
<span>🤖</span>
|
||||
<span>دردشة AI</span>
|
||||
<button onclick="toggleChat()" style="margin-right: auto; background: none; border: none; color: #888; cursor: pointer;">×</button>
|
||||
</div>
|
||||
<div class="chat-messages" id="chatMessages">
|
||||
${chatHistory.length === 0 ? `
|
||||
<div style="text-align: center; color: #666; padding: 20px;">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">🤖</div>
|
||||
<p>ابدأ محادثة مع الذكاء الاصطناعي</p>
|
||||
<p style="font-size: 12px;">أضف مفتاح API من الإعدادات</p>
|
||||
</div>
|
||||
` : chatHistory.map(msg => `
|
||||
<div class="message ${msg.type}">
|
||||
<div>${msg.content}</div>
|
||||
<div style="font-size: 11px; opacity: 0.7; margin-top: 4px;">
|
||||
${new Date(msg.timestamp).toLocaleTimeString()}
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
<div class="chat-input">
|
||||
<input type="text" id="chatInput" placeholder="${apiKey ? 'اسألني أي شيء...' : 'أضف مفتاح API أولاً'}"
|
||||
onkeypress="handleChatKeyPress(event)" ${!apiKey ? 'disabled' : ''}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden" id="settingsModal" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); display: flex; align-items: center; justify-content: center; z-index: 1000;">
|
||||
<div style="background: #252526; border: 1px solid #3c3c3c; border-radius: 8px; padding: 20px; width: 400px;">
|
||||
<h3 style="margin-bottom: 20px; color: #d4d4d4;">⚙️ الإعدادات</h3>
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label style="display: block; margin-bottom: 5px; color: #d4d4d4;">مفتاح OpenAI API</label>
|
||||
<input type="password" id="apiKeyInput" value="${apiKey}"
|
||||
style="width: 100%; background: #1e1e1e; border: 1px solid #3c3c3c; color: #d4d4d4; padding: 10px; border-radius: 6px;">
|
||||
</div>
|
||||
<div style="text-align: left;">
|
||||
<button class="btn btn-secondary" onclick="closeSettings()">إلغاء</button>
|
||||
<button class="btn" onclick="saveSettings()">حفظ</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function selectFile(filePath) {
|
||||
selectedFile = filePath;
|
||||
renderApp();
|
||||
}
|
||||
|
||||
function getFileContent() {
|
||||
return `// ${selectedFile}
|
||||
console.log('مرحباً من ${selectedFile}');
|
||||
|
||||
function example() {
|
||||
return 'هذا ملف تجريبي';
|
||||
}
|
||||
|
||||
export default example;`;
|
||||
}
|
||||
|
||||
function saveFile() {
|
||||
if (!selectedFile) return;
|
||||
console.log('Saving file:', selectedFile);
|
||||
// In a real app, this would save to backend
|
||||
}
|
||||
|
||||
function runCode() {
|
||||
if (!selectedFile) return;
|
||||
console.log('Running code for:', selectedFile);
|
||||
// In a real app, this would execute code
|
||||
}
|
||||
|
||||
function toggleChat() {
|
||||
const chatPanel = document.getElementById('chatPanel');
|
||||
chatPanel.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
function toggleSettings() {
|
||||
const settingsModal = document.getElementById('settingsModal');
|
||||
settingsModal.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
function closeSettings() {
|
||||
const settingsModal = document.getElementById('settingsModal');
|
||||
settingsModal.classList.add('hidden');
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
apiKey = document.getElementById('apiKeyInput').value;
|
||||
closeSettings();
|
||||
renderApp();
|
||||
}
|
||||
|
||||
function handleChatKeyPress(event) {
|
||||
if (event.key === 'Enter') {
|
||||
sendChatMessage();
|
||||
}
|
||||
}
|
||||
|
||||
async function sendChatMessage() {
|
||||
const input = document.getElementById('chatInput');
|
||||
const message = input.value.trim();
|
||||
if (!message || !apiKey) return;
|
||||
|
||||
const userMessage = {
|
||||
type: 'user',
|
||||
content: message,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
chatHistory.push(userMessage);
|
||||
input.value = '';
|
||||
renderApp();
|
||||
|
||||
try {
|
||||
const response = await fetch(`${BACKEND_URL}/api/chat`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
message: message,
|
||||
provider: 'openai',
|
||||
apiKey: apiKey,
|
||||
model: 'gpt-4'
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
const assistantMessage = {
|
||||
type: 'assistant',
|
||||
content: data.response || 'لم يتم استلام رد',
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
chatHistory.push(assistantMessage);
|
||||
renderApp();
|
||||
} catch (error) {
|
||||
console.error('Failed to send chat message:', error);
|
||||
const errorMessage = {
|
||||
type: 'assistant',
|
||||
content: 'فشل في إرسال الرسالة. يرجى التحقق من الاتصال.',
|
||||
timestamp: Date.now()
|
||||
};
|
||||
chatHistory.push(errorMessage);
|
||||
renderApp();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize app
|
||||
initApp();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
# ضغط الملفات
|
||||
zip -r app.zip index.html
|
||||
|
||||
# رفع الملف المضغوط
|
||||
curl -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/pages/projects/$PROJECT_NAME/deployments" \
|
||||
-H "Authorization: Bearer $API_TOKEN" \
|
||||
-F "files=@app.zip"
|
||||
|
||||
echo "✅ تم رفع التطبيق الجديد!"
|
||||
echo "🌐 الرابط: https://cursor-ide.pages.dev"
|
||||
echo "🎉 تم إصلاح مشكلة النشر!"
|
||||
|
||||
cd ..
|
||||
605
cursor-fullstack/cloudflare/index.html
Normal file
605
cursor-fullstack/cloudflare/index.html
Normal file
|
|
@ -0,0 +1,605 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Cursor AI IDE - بيئة التطوير الذكية</title>
|
||||
<meta name="description" content="بيئة تطوير ذكية متكاملة مع محرر كود متقدم ودردشة AI">
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Tajawal', sans-serif;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 280px;
|
||||
background: #252526;
|
||||
border-left: 1px solid #3c3c3c;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: #252526;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.editor {
|
||||
flex: 1;
|
||||
background: #1e1e1e;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
padding: 8px 20px;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.file-list {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
padding: 10px 12px;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 4px;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.file-item:hover {
|
||||
background: #2a2d2e;
|
||||
transform: translateX(-2px);
|
||||
}
|
||||
|
||||
.file-item.active {
|
||||
background: #264f78;
|
||||
border-right: 3px solid #007acc;
|
||||
}
|
||||
|
||||
.editor-textarea {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-family: 'Fira Code', 'Consolas', 'Monaco', 'Cascadia Code', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
resize: none;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 16px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #005a9e;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #2a2d2e;
|
||||
color: #d4d4d4;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #3c3c3c;
|
||||
}
|
||||
|
||||
.connection-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #4caf50;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
|
||||
.chat-panel {
|
||||
width: 350px;
|
||||
background: #252526;
|
||||
border-right: 1px solid #3c3c3c;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
flex: 1;
|
||||
padding: 15px;
|
||||
overflow-y: auto;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
padding: 15px;
|
||||
border-top: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.chat-input input {
|
||||
width: 100%;
|
||||
background: #1e1e1e;
|
||||
border: 1px solid #3c3c3c;
|
||||
color: #d4d4d4;
|
||||
padding: 10px 12px;
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.chat-input input:focus {
|
||||
border-color: #007acc;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-bottom: 15px;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
animation: slideIn 0.3s ease;
|
||||
}
|
||||
|
||||
.message.user {
|
||||
background: #007acc;
|
||||
color: white;
|
||||
margin-left: 20px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.message.assistant {
|
||||
background: #2a2d2e;
|
||||
color: #d4d4d4;
|
||||
margin-right: 20px;
|
||||
border-bottom-left-radius: 4px;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 4px solid #333;
|
||||
border-top: 4px solid #007acc;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #007acc;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #d4d4d4;
|
||||
margin-bottom: 10px;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.welcome-message {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.welcome-message h3 {
|
||||
color: #d4d4d4;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.feature-list li {
|
||||
padding: 5px 0;
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.feature-list li:before {
|
||||
content: "✓ ";
|
||||
color: #4caf50;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<div>جاري تحميل Cursor AI IDE...</div>
|
||||
<div style="font-size: 12px; color: #888;">Loading Cursor AI IDE...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const BACKEND_URL = 'https://cursor-backend.workers.dev';
|
||||
|
||||
let isConnected = false;
|
||||
let selectedFile = null;
|
||||
let files = [];
|
||||
let chatHistory = [];
|
||||
let apiKey = '';
|
||||
|
||||
async function initApp() {
|
||||
try {
|
||||
// Test backend connection
|
||||
const response = await fetch(`${BACKEND_URL}/health`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log('Backend connected:', data);
|
||||
isConnected = true;
|
||||
await loadFiles();
|
||||
renderApp();
|
||||
} else {
|
||||
throw new Error('Backend not responding');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to connect:', error);
|
||||
renderError('فشل في الاتصال بالخادم. يرجى التحقق من الاتصال.');
|
||||
}
|
||||
}
|
||||
|
||||
async function loadFiles() {
|
||||
try {
|
||||
const response = await fetch(`${BACKEND_URL}/api/workspace/files`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
files = data.files || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load files:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function renderError(message) {
|
||||
document.getElementById('app').innerHTML = `
|
||||
<div class="loading">
|
||||
<div style="text-align: center;">
|
||||
<div style="color: #f44747; margin-bottom: 16px; font-size: 48px;">⚠️</div>
|
||||
<div style="margin-bottom: 16px;">${message}</div>
|
||||
<button class="btn" onclick="initApp()">إعادة المحاولة</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderApp() {
|
||||
document.getElementById('app').innerHTML = `
|
||||
<div class="container">
|
||||
<div class="sidebar">
|
||||
<div class="logo">
|
||||
<span>🚀</span>
|
||||
<span>Cursor AI IDE</span>
|
||||
</div>
|
||||
<div class="connection-status">
|
||||
<div class="status-dot" style="background: ${isConnected ? '#4caf50' : '#f44747'}"></div>
|
||||
<span>${isConnected ? 'متصل' : 'غير متصل'}</span>
|
||||
</div>
|
||||
|
||||
<div class="file-list">
|
||||
<div class="section-title">📁 الملفات</div>
|
||||
${files.map(file => `
|
||||
<div class="file-item ${selectedFile === file.path ? 'active' : ''}"
|
||||
onclick="selectFile('${file.path}')">
|
||||
<span class="file-icon">📄</span>
|
||||
<span>${file.name}</span>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px;">
|
||||
<div class="section-title">🛠️ الأدوات</div>
|
||||
<button class="btn btn-secondary" onclick="toggleChat()" style="width: 100%; margin: 4px 0;">
|
||||
🤖 دردشة AI
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="toggleSettings()" style="width: 100%; margin: 4px 0;">
|
||||
⚙️ الإعدادات
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main">
|
||||
<div class="header">
|
||||
<div>
|
||||
<span>📄 ${selectedFile || 'لم يتم اختيار ملف'}</span>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn" onclick="saveFile()">
|
||||
💾 حفظ
|
||||
</button>
|
||||
<button class="btn" onclick="runCode()">
|
||||
▶️ تشغيل
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editor">
|
||||
${selectedFile ? `
|
||||
<textarea class="editor-textarea" id="editor" placeholder="ابدأ البرمجة...">${getFileContent()}</textarea>
|
||||
` : `
|
||||
<div class="welcome-message">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">📁</div>
|
||||
<h3>مرحباً بك في Cursor AI IDE</h3>
|
||||
<p>اختر ملفاً من الشريط الجانبي لبدء البرمجة</p>
|
||||
<ul class="feature-list">
|
||||
<li>محرر كود متقدم</li>
|
||||
<li>دردشة مع الذكاء الاصطناعي</li>
|
||||
<li>إدارة الملفات</li>
|
||||
<li>تنفيذ الكود</li>
|
||||
<li>أدوات متكاملة</li>
|
||||
</ul>
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
|
||||
<div class="status-bar">
|
||||
<div>جاهز</div>
|
||||
<div>Cursor AI IDE v1.0.0</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-panel hidden" id="chatPanel">
|
||||
<div class="chat-header">
|
||||
<span>🤖</span>
|
||||
<span>دردشة AI</span>
|
||||
<button onclick="toggleChat()" style="margin-right: auto; background: none; border: none; color: #888; cursor: pointer;">×</button>
|
||||
</div>
|
||||
<div class="chat-messages" id="chatMessages">
|
||||
${chatHistory.length === 0 ? `
|
||||
<div style="text-align: center; color: #666; padding: 20px;">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">🤖</div>
|
||||
<p>ابدأ محادثة مع الذكاء الاصطناعي</p>
|
||||
<p style="font-size: 12px;">أضف مفتاح API من الإعدادات</p>
|
||||
</div>
|
||||
` : chatHistory.map(msg => `
|
||||
<div class="message ${msg.type}">
|
||||
<div>${msg.content}</div>
|
||||
<div style="font-size: 11px; opacity: 0.7; margin-top: 4px;">
|
||||
${new Date(msg.timestamp).toLocaleTimeString()}
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
<div class="chat-input">
|
||||
<input type="text" id="chatInput" placeholder="${apiKey ? 'اسألني أي شيء...' : 'أضف مفتاح API أولاً'}"
|
||||
onkeypress="handleChatKeyPress(event)" ${!apiKey ? 'disabled' : ''}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden" id="settingsModal" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); display: flex; align-items: center; justify-content: center; z-index: 1000;">
|
||||
<div style="background: #252526; border: 1px solid #3c3c3c; border-radius: 8px; padding: 20px; width: 400px;">
|
||||
<h3 style="margin-bottom: 20px; color: #d4d4d4;">⚙️ الإعدادات</h3>
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label style="display: block; margin-bottom: 5px; color: #d4d4d4;">مفتاح OpenAI API</label>
|
||||
<input type="password" id="apiKeyInput" value="${apiKey}"
|
||||
style="width: 100%; background: #1e1e1e; border: 1px solid #3c3c3c; color: #d4d4d4; padding: 10px; border-radius: 6px;">
|
||||
</div>
|
||||
<div style="text-align: left;">
|
||||
<button class="btn btn-secondary" onclick="closeSettings()">إلغاء</button>
|
||||
<button class="btn" onclick="saveSettings()">حفظ</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function selectFile(filePath) {
|
||||
selectedFile = filePath;
|
||||
renderApp();
|
||||
}
|
||||
|
||||
function getFileContent() {
|
||||
return `// ${selectedFile}
|
||||
console.log('مرحباً من ${selectedFile}');
|
||||
|
||||
function example() {
|
||||
return 'هذا ملف تجريبي';
|
||||
}
|
||||
|
||||
export default example;`;
|
||||
}
|
||||
|
||||
function saveFile() {
|
||||
if (!selectedFile) return;
|
||||
console.log('Saving file:', selectedFile);
|
||||
// In a real app, this would save to backend
|
||||
}
|
||||
|
||||
function runCode() {
|
||||
if (!selectedFile) return;
|
||||
console.log('Running code for:', selectedFile);
|
||||
// In a real app, this would execute code
|
||||
}
|
||||
|
||||
function toggleChat() {
|
||||
const chatPanel = document.getElementById('chatPanel');
|
||||
chatPanel.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
function toggleSettings() {
|
||||
const settingsModal = document.getElementById('settingsModal');
|
||||
settingsModal.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
function closeSettings() {
|
||||
const settingsModal = document.getElementById('settingsModal');
|
||||
settingsModal.classList.add('hidden');
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
apiKey = document.getElementById('apiKeyInput').value;
|
||||
closeSettings();
|
||||
renderApp();
|
||||
}
|
||||
|
||||
function handleChatKeyPress(event) {
|
||||
if (event.key === 'Enter') {
|
||||
sendChatMessage();
|
||||
}
|
||||
}
|
||||
|
||||
async function sendChatMessage() {
|
||||
const input = document.getElementById('chatInput');
|
||||
const message = input.value.trim();
|
||||
if (!message || !apiKey) return;
|
||||
|
||||
const userMessage = {
|
||||
type: 'user',
|
||||
content: message,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
chatHistory.push(userMessage);
|
||||
input.value = '';
|
||||
renderApp();
|
||||
|
||||
try {
|
||||
const response = await fetch(`${BACKEND_URL}/api/chat`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
message: message,
|
||||
provider: 'openai',
|
||||
apiKey: apiKey,
|
||||
model: 'gpt-4'
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
const assistantMessage = {
|
||||
type: 'assistant',
|
||||
content: data.response || 'لم يتم استلام رد',
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
chatHistory.push(assistantMessage);
|
||||
renderApp();
|
||||
} catch (error) {
|
||||
console.error('Failed to send chat message:', error);
|
||||
const errorMessage = {
|
||||
type: 'assistant',
|
||||
content: 'فشل في إرسال الرسالة. يرجى التحقق من الاتصال.',
|
||||
timestamp: Date.now()
|
||||
};
|
||||
chatHistory.push(errorMessage);
|
||||
renderApp();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize app
|
||||
initApp();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
125
cursor-fullstack/تقرير_مشكلة_النشر.md
Normal file
125
cursor-fullstack/تقرير_مشكلة_النشر.md
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
# 🚨 تقرير مشكلة النشر
|
||||
|
||||
## ❌ **المشكلة: لم يتم النشر بنجاح!**
|
||||
|
||||
### 📊 **حالة النشر الحالية:**
|
||||
|
||||
#### **❌ المشاكل المكتشفة:**
|
||||
1. **Cloudflare Pages API Error:**
|
||||
- **الكود:** `8000096`
|
||||
- **الرسالة:** `A "manifest" field was expected in the request body but was not provided.`
|
||||
- **السبب:** Cloudflare Pages يتطلب manifest صحيح
|
||||
|
||||
2. **Method Not Allowed Error:**
|
||||
- **الكود:** `1001`
|
||||
- **الرسالة:** `method_not_allowed`
|
||||
- **السبب:** طريقة الرفع غير صحيحة
|
||||
|
||||
3. **الموقع لا يتحدث:**
|
||||
- **الرابط:** https://cursor-ide.pages.dev
|
||||
- **المشكلة:** يعرض الملف القديم
|
||||
- **السبب:** Cloudflare Pages لا يحدث الملفات
|
||||
|
||||
### 🔍 **التحليل:**
|
||||
|
||||
#### **✅ ما يعمل:**
|
||||
- **Backend:** https://cursor-backend.workers.dev ✅ يعمل
|
||||
- **API Token:** صحيح ومفعل
|
||||
- **الملفات:** تم إنشاؤها بنجاح
|
||||
- **الكود:** سليم ومكتوب بشكل صحيح
|
||||
|
||||
#### **❌ ما لا يعمل:**
|
||||
- **Cloudflare Pages API:** لا يقبل طريقة الرفع الحالية
|
||||
- **Manifest:** يتطلب تنسيق مختلف
|
||||
- **Deployment:** فشل في جميع المحاولات
|
||||
|
||||
### 🛠️ **الحلول المقترحة:**
|
||||
|
||||
#### **الحل 1: استخدام Wrangler CLI**
|
||||
```bash
|
||||
# تثبيت Wrangler
|
||||
npm install -g wrangler
|
||||
|
||||
# تسجيل الدخول
|
||||
wrangler login
|
||||
|
||||
# نشر الصفحات
|
||||
wrangler pages deploy ./deploy
|
||||
```
|
||||
|
||||
#### **الحل 2: رفع يدوي عبر Dashboard**
|
||||
1. **افتح Cloudflare Dashboard**
|
||||
2. **اذهب إلى Pages**
|
||||
3. **اختر المشروع cursor-ide**
|
||||
4. **ارفع الملفات يدوياً**
|
||||
|
||||
#### **الحل 3: استخدام Git Integration**
|
||||
1. **ربط GitHub Repository**
|
||||
2. **تفعيل Auto Deploy**
|
||||
3. **Push التغييرات**
|
||||
|
||||
### 📋 **الخطوات المطلوبة:**
|
||||
|
||||
#### **1. إصلاح Cloudflare Pages:**
|
||||
- استخدام Wrangler CLI
|
||||
- أو الرفع اليدوي
|
||||
- أو Git Integration
|
||||
|
||||
#### **2. اختبار النشر:**
|
||||
- فحص الموقع
|
||||
- اختبار الوظائف
|
||||
- التأكد من التحديث
|
||||
|
||||
#### **3. التوثيق:**
|
||||
- تحديث التقارير
|
||||
- إضافة التعليمات
|
||||
- توثيق الحلول
|
||||
|
||||
### 🎯 **الوضع الحالي:**
|
||||
|
||||
#### **✅ Backend:**
|
||||
- **الرابط:** https://cursor-backend.workers.dev
|
||||
- **الحالة:** يعمل بشكل مثالي
|
||||
- **APIs:** جميعها تعمل
|
||||
|
||||
#### **❌ Frontend:**
|
||||
- **الرابط:** https://cursor-ide.pages.dev
|
||||
- **الحالة:** لا يعمل (ملف قديم)
|
||||
- **المشكلة:** لم يتم النشر
|
||||
|
||||
### 🔧 **الملفات الجاهزة:**
|
||||
|
||||
#### **✅ تم إنشاؤها:**
|
||||
- `index.html` - ملف HTML كامل
|
||||
- `manifest.json` - ملف Manifest
|
||||
- `app.zip` - ملف مضغوط
|
||||
- سكريبتات النشر
|
||||
|
||||
#### **❌ لم يتم رفعها:**
|
||||
- Cloudflare Pages لا يقبل الرفع
|
||||
- API errors تمنع النشر
|
||||
- الملفات لا تظهر على الموقع
|
||||
|
||||
### 🎊 **الخلاصة:**
|
||||
|
||||
**❌ المشكلة: لم يتم النشر بنجاح!**
|
||||
|
||||
**🔍 الأسباب:**
|
||||
1. **Cloudflare Pages API:** يتطلب تنسيق مختلف
|
||||
2. **Manifest:** يجب أن يكون في تنسيق صحيح
|
||||
3. **Method:** طريقة الرفع غير مدعومة
|
||||
|
||||
**🛠️ الحلول:**
|
||||
1. **استخدام Wrangler CLI**
|
||||
2. **الرفع اليدوي عبر Dashboard**
|
||||
3. **Git Integration**
|
||||
|
||||
**📞 التوصية:**
|
||||
- استخدام Wrangler CLI للنشر
|
||||
- أو الرفع اليدوي عبر Cloudflare Dashboard
|
||||
- أو ربط GitHub Repository
|
||||
|
||||
**🎯 النتيجة:**
|
||||
- **Backend:** ✅ يعمل
|
||||
- **Frontend:** ❌ لم يتم النشر
|
||||
- **المطلوب:** إصلاح مشكلة النشر
|
||||
Loading…
Reference in a new issue