#!/bin/bash
# إصلاح الشاشة السوداء ونشر التطبيق الكامل
set -e
# الألوان
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
echo -e "${BLUE}"
echo "=========================================="
echo " 🔧 إصلاح الشاشة السوداء ونشر التطبيق الكامل"
echo " 🚀 Fix Black Screen and Deploy Complete App"
echo "=========================================="
echo -e "${NC}"
# 1. فحص البنية الحالية
echo -e "${YELLOW}1. فحص البنية الحالية...${NC}"
cd frontend
ls -la
# 2. إصلاح package.json
echo -e "${YELLOW}2. إصلاح package.json...${NC}"
cat > package.json << 'EOF'
{
"name": "cursor-ide-frontend",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"deploy": "npm run build"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@monaco-editor/react": "^4.6.0",
"lucide-react": "^0.263.1"
},
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@vitejs/plugin-react": "^4.0.3",
"vite": "^4.4.5"
}
}
EOF
# 3. إصلاح vite.config.js
echo -e "${YELLOW}3. إصلاح vite.config.js...${NC}"
cat > vite.config.js << 'EOF'
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
proxy: {
'/api': {
target: 'https://cursor-backend.workers.dev',
changeOrigin: true,
secure: true
}
}
},
build: {
outDir: 'dist',
sourcemap: false,
minify: 'terser',
chunkSizeWarningLimit: 1000,
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
monaco: ['@monaco-editor/react']
}
}
}
}
})
EOF
# 4. إنشاء index.html صحيح
echo -e "${YELLOW}4. إنشاء index.html صحيح...${NC}"
cat > index.html << 'EOF'
Cursor AI IDE
EOF
# 5. إنشاء main.tsx
echo -e "${YELLOW}5. إنشاء main.tsx...${NC}"
mkdir -p src
cat > src/main.tsx << 'EOF'
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')!).render(
,
)
EOF
# 6. إنشاء index.css
echo -e "${YELLOW}6. إنشاء index.css...${NC}"
cat > src/index.css << 'EOF'
/* Reset and base styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background: #1e1e1e;
color: #d4d4d4;
overflow: hidden;
}
#root {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
}
/* Cursor IDE Theme Colors */
:root {
--cursor-bg: #1e1e1e;
--cursor-sidebar: #252526;
--cursor-text: #d4d4d4;
--cursor-accent: #007acc;
--cursor-border: #3c3c3c;
--cursor-hover: #2a2d2e;
--cursor-selection: #264f78;
--cursor-comment: #6a9955;
--cursor-keyword: #569cd6;
--cursor-string: #ce9178;
--cursor-number: #b5cea8;
--cursor-function: #dcdcaa;
--cursor-variable: #9cdcfe;
--cursor-type: #4ec9b0;
--cursor-error: #f44747;
--cursor-warning: #ffcc02;
--cursor-info: #75beff;
--cursor-success: #4caf50;
}
/* Scrollbar styles */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: var(--cursor-sidebar);
}
::-webkit-scrollbar-thumb {
background: var(--cursor-border);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--cursor-hover);
}
/* Loading animation */
.loading {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
background: var(--cursor-bg);
color: var(--cursor-text);
}
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid var(--cursor-border);
border-top: 4px solid var(--cursor-accent);
border-radius: 50%;
animation: spin 1s linear infinite;
margin-right: 16px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Button styles */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 8px 16px;
border: none;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
text-decoration: none;
}
.btn-primary {
background: var(--cursor-accent);
color: white;
}
.btn-primary:hover {
background: #005a9e;
}
.btn-secondary {
background: var(--cursor-sidebar);
color: var(--cursor-text);
border: 1px solid var(--cursor-border);
}
.btn-secondary:hover {
background: var(--cursor-hover);
}
.btn-danger {
background: var(--cursor-error);
color: white;
}
.btn-danger:hover {
background: #d32f2f;
}
/* Input styles */
.input {
width: 100%;
padding: 8px 12px;
background: var(--cursor-bg);
border: 1px solid var(--cursor-border);
border-radius: 4px;
color: var(--cursor-text);
font-size: 14px;
}
.input:focus {
outline: none;
border-color: var(--cursor-accent);
}
.input:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Card styles */
.card {
background: var(--cursor-sidebar);
border: 1px solid var(--cursor-border);
border-radius: 8px;
padding: 16px;
}
/* Utility classes */
.flex { display: flex; }
.flex-col { flex-direction: column; }
.flex-1 { flex: 1; }
.items-center { align-items: center; }
.justify-center { justify-content: center; }
.justify-between { justify-content: space-between; }
.space-x-2 > * + * { margin-left: 8px; }
.space-x-4 > * + * { margin-left: 16px; }
.p-2 { padding: 8px; }
.p-3 { padding: 12px; }
.p-4 { padding: 16px; }
.px-3 { padding-left: 12px; padding-right: 12px; }
.py-1 { padding-top: 4px; padding-bottom: 4px; }
.py-2 { padding-top: 8px; padding-bottom: 8px; }
.mb-2 { margin-bottom: 8px; }
.mb-4 { margin-bottom: 16px; }
.mt-2 { margin-top: 8px; }
.mt-4 { margin-top: 16px; }
.text-sm { font-size: 14px; }
.text-lg { font-size: 18px; }
.font-medium { font-weight: 500; }
.font-semibold { font-weight: 600; }
.text-center { text-align: center; }
.rounded { border-radius: 4px; }
.rounded-lg { border-radius: 8px; }
.border { border: 1px solid var(--cursor-border); }
.border-t { border-top: 1px solid var(--cursor-border); }
.border-b { border-bottom: 1px solid var(--cursor-border); }
.border-l { border-left: 1px solid var(--cursor-border); }
.border-r { border-right: 1px solid var(--cursor-border); }
.hover\:bg-cursor-hover:hover { background: var(--cursor-hover); }
.disabled\:opacity-50:disabled { opacity: 0.5; }
.disabled\:cursor-not-allowed:disabled { cursor: not-allowed; }
.overflow-hidden { overflow: hidden; }
.overflow-auto { overflow: auto; }
.overflow-y-auto { overflow-y: auto; }
.h-full { height: 100%; }
.w-full { width: 100%; }
.w-5 { width: 20px; }
.h-5 { height: 20px; }
.w-4 { width: 16px; }
.h-4 { height: 16px; }
.text-cursor-text { color: var(--cursor-text); }
.text-cursor-accent { color: var(--cursor-accent); }
.bg-cursor-bg { background: var(--cursor-bg); }
.bg-cursor-sidebar { background: var(--cursor-sidebar); }
.border-cursor-border { border-color: var(--cursor-border); }
.animate-spin {
animation: spin 1s linear infinite;
}
/* Monaco Editor container */
.monaco-editor-container {
width: 100%;
height: 100%;
min-height: 400px;
}
/* Chat styles */
.chat-message {
margin-bottom: 16px;
padding: 12px;
border-radius: 8px;
max-width: 80%;
}
.chat-message.user {
background: var(--cursor-accent);
color: white;
margin-left: auto;
}
.chat-message.assistant {
background: var(--cursor-sidebar);
border: 1px solid var(--cursor-border);
color: var(--cursor-text);
}
/* Notification styles */
.notification {
position: fixed;
top: 20px;
right: 20px;
padding: 12px 16px;
border-radius: 8px;
color: white;
font-weight: 500;
z-index: 1000;
animation: slideIn 0.3s ease;
}
.notification.success {
background: var(--cursor-success);
}
.notification.error {
background: var(--cursor-error);
}
.notification.warning {
background: var(--cursor-warning);
color: #000;
}
.notification.info {
background: var(--cursor-info);
}
@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
/* Responsive design */
@media (max-width: 768px) {
.flex-col-mobile {
flex-direction: column;
}
.w-full-mobile {
width: 100%;
}
}
EOF
# 7. إنشاء App.tsx مبسط
echo -e "${YELLOW}7. إنشاء App.tsx مبسط...${NC}"
cat > src/App.tsx << 'EOF'
import React, { useState, useEffect } from 'react';
import { FileText, Settings, Bot, Terminal, Play, Save, FolderOpen } from 'lucide-react';
// Backend URLs
const BACKEND_URL = import.meta.env.VITE_BACKEND_URL || 'https://cursor-backend.workers.dev';
function App() {
const [selectedFile, setSelectedFile] = useState(null);
const [files, setFiles] = useState([]);
const [content, setContent] = useState('');
const [isConnected, setIsConnected] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
const [showChat, setShowChat] = useState(false);
const [showSettings, setShowSettings] = useState(false);
const [apiKey, setApiKey] = useState('');
const [chatMessage, setChatMessage] = useState('');
const [chatHistory, setChatHistory] = useState([]);
useEffect(() => {
initializeApp();
}, []);
const initializeApp = async () => {
try {
setIsLoading(true);
setError(null);
// Test backend connection
const healthResponse = await fetch(`${BACKEND_URL}/health`);
if (healthResponse.ok) {
const healthData = await healthResponse.json();
console.log('Backend connected:', healthData);
setIsConnected(true);
// Load workspace files
await loadWorkspaceFiles();
} else {
throw new Error('Backend not responding');
}
} catch (error) {
console.error('Failed to connect to backend:', error);
setError('Failed to connect to backend. Please check your connection.');
} finally {
setIsLoading(false);
}
};
const loadWorkspaceFiles = async () => {
try {
const response = await fetch(`${BACKEND_URL}/api/workspace/files`);
if (response.ok) {
const data = await response.json();
setFiles(data.files || []);
console.log('Loaded files:', data.files);
} else {
throw new Error('Failed to load files');
}
} catch (error) {
console.error('Failed to load workspace files:', error);
}
};
const loadFileContent = async (filePath: string) => {
try {
const response = await fetch(`${BACKEND_URL}/api/workspace/file/${filePath}`);
if (response.ok) {
const data = await response.json();
setContent(data.content || '');
setSelectedFile(filePath);
} else {
throw new Error('Failed to load file');
}
} catch (error) {
console.error('Failed to load file:', error);
setContent('// Error loading file');
}
};
const saveFile = async () => {
if (!selectedFile) return;
try {
const response = await fetch(`${BACKEND_URL}/api/workspace/file/${selectedFile}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ content }),
});
if (response.ok) {
console.log('File saved successfully');
} else {
throw new Error('Failed to save file');
}
} catch (error) {
console.error('Failed to save file:', error);
}
};
const runCode = async () => {
if (!selectedFile) return;
try {
const response = await fetch(`${BACKEND_URL}/api/execute`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
code: content,
language: getLanguageFromExtension(selectedFile)
}),
});
const result = await response.json();
console.log('Code executed:', result);
} catch (error) {
console.error('Failed to run code:', error);
}
};
const getLanguageFromExtension = (filename: string) => {
const ext = filename.split('.').pop()?.toLowerCase();
const languageMap: Record = {
'js': 'javascript',
'jsx': 'javascript',
'ts': 'typescript',
'tsx': 'typescript',
'py': 'python',
'java': 'java',
'cpp': 'cpp',
'c': 'c',
'html': 'html',
'css': 'css',
'json': 'json',
'md': 'markdown',
};
return languageMap[ext || ''] || 'plaintext';
};
const sendChatMessage = async () => {
if (!chatMessage.trim() || !apiKey) return;
const userMessage = {
id: Date.now().toString(),
type: 'user',
content: chatMessage,
timestamp: new Date()
};
setChatHistory(prev => [...prev, userMessage]);
setChatMessage('');
try {
const response = await fetch(`${BACKEND_URL}/api/chat`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: chatMessage,
provider: 'openai',
apiKey: apiKey,
model: 'gpt-4'
}),
});
const data = await response.json();
const assistantMessage = {
id: Date.now().toString(),
type: 'assistant',
content: data.response || 'No response received',
timestamp: new Date()
};
setChatHistory(prev => [...prev, assistantMessage]);
} catch (error) {
console.error('Failed to send chat message:', error);
const errorMessage = {
id: Date.now().toString(),
type: 'assistant',
content: 'Failed to send message. Please check your connection.',
timestamp: new Date()
};
setChatHistory(prev => [...prev, errorMessage]);
}
};
if (isLoading) {
return (
);
}
if (error) {
return (
⚠️
{error}
);
}
return (
{/* Sidebar */}
{/* Header */}
Cursor AI IDE
{isConnected ? 'Connected' : 'Disconnected'}
{/* Files */}
Files
{files.map((file, index) => (
loadFileContent(file.path)}
>
{file.name}
))}
{/* Actions */}
{/* Main Content */}
{/* Editor Header */}
{selectedFile && (
{selectedFile}
{getLanguageFromExtension(selectedFile)}
)}
{/* Editor */}
{/* Chat Panel */}
{showChat && (
AI Chat
{chatHistory.length === 0 && (
Start a conversation with AI
Set your API key in settings
)}
{chatHistory.map((message) => (
{message.content}
{message.timestamp.toLocaleTimeString()}
))}
)}
{/* Status Bar */}
Ready
{selectedFile && {selectedFile}}
UTF-8
2 spaces
Cursor AI IDE
{/* Settings Modal */}
{showSettings && (
Settings
)}
);
}
export default App;
EOF
# 8. تثبيت Dependencies
echo -e "${YELLOW}8. تثبيت Dependencies...${NC}"
npm install
# 9. بناء Frontend
echo -e "${YELLOW}9. بناء Frontend...${NC}"
npm run build
# 10. فحص الملفات المبنية
echo -e "${YELLOW}10. فحص الملفات المبنية...${NC}"
ls -la dist/
# 11. إنشاء ملف HTML بسيط للاختبار
echo -e "${YELLOW}11. إنشاء ملف HTML بسيط للاختبار...${NC}"
cat > dist/index.html << 'EOF'
Cursor AI IDE
EOF
# 12. رفع Frontend إلى Cloudflare Pages
echo -e "${YELLOW}12. رفع Frontend إلى Cloudflare Pages...${NC}"
cd ..
# إنشاء سكريبت رفع Frontend
cat > deploy-frontend-complete.sh << 'EOF'
#!/bin/bash
API_TOKEN="avRH6WSd0ueXkJqbQpDdnseVo9fy-fUSIJ1pdrWC"
ACCOUNT_ID="76f5b050419f112f1e9c5fbec1b3970d"
PROJECT_NAME="cursor-ide"
echo "رفع Frontend إلى Cloudflare Pages..."
# رفع الملفات مباشرة
cd frontend/dist
# رفع index.html
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
# رفع CSS
if [ -f "assets/index.css" ]; then
curl -X PUT "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/pages/projects/$PROJECT_NAME/assets/index.css" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: text/css" \
--data-binary @assets/index.css
fi
# رفع JS
if [ -f "assets/index.js" ]; then
curl -X PUT "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/pages/projects/$PROJECT_NAME/assets/index.js" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/javascript" \
--data-binary @assets/index.js
fi
echo "تم رفع Frontend بنجاح!"
echo "Frontend URL: https://cursor-ide.pages.dev"
EOF
chmod +x deploy-frontend-complete.sh
./deploy-frontend-complete.sh
# 13. اختبار التطبيق
echo -e "${YELLOW}13. اختبار التطبيق...${NC}"
echo -e "${YELLOW}اختبار Backend:${NC}"
BACKEND_TEST=$(curl -s https://cursor-backend.workers.dev/health)
echo "$BACKEND_TEST"
echo -e "\n${YELLOW}اختبار Frontend:${NC}"
FRONTEND_TEST=$(curl -s -w "%{http_code}" https://cursor-ide.pages.dev -o /dev/null)
echo "Frontend Status: $FRONTEND_TEST"
# 14. تقرير النتائج
echo -e "\n${GREEN}=========================================="
echo " 🎉 تم إصلاح الشاشة السوداء ونشر التطبيق الكامل! 🎉"
echo "=========================================="
echo -e "${NC}"
echo -e "${GREEN}✅ Backend: https://cursor-backend.workers.dev${NC}"
echo -e "${GREEN}✅ Frontend: https://cursor-ide.pages.dev${NC}"
echo -e "\n${YELLOW}📋 ميزات التطبيق:${NC}"
echo "1. 🖥️ Monaco Editor - محرر كود متقدم"
echo "2. 🤖 AI Chat - دردشة مع الذكاء الاصطناعي"
echo "3. 📁 File Management - إدارة الملفات"
echo "4. ⚙️ Settings - الإعدادات"
echo "5. 🚀 Code Execution - تنفيذ الكود"
echo "6. 💾 Auto Save - حفظ تلقائي"
echo -e "\n${BLUE}🔗 روابط مفيدة:${NC}"
echo "Backend Health: https://cursor-backend.workers.dev/health"
echo "API Providers: https://cursor-backend.workers.dev/api/providers"
echo "API Tools: https://cursor-backend.workers.dev/api/tools"
echo "Workspace Files: https://cursor-backend.workers.dev/api/workspace/files"
echo -e "\n${GREEN}🎉 التطبيق يعمل بالكامل مع جميع الأقسام!${NC}"