Upload 37 files
Browse files- .babelrc +6 -0
- .dockerignore +60 -0
- .env.example +102 -0
- .gitignore +92 -0
- .htaccess +120 -0
- .huggingface.yaml +14 -0
- Dockerfile +142 -0
- Dockerfile.railway +0 -0
- LICENSE +21 -0
- README-RAILWAY.md +80 -0
- Railway.json +7 -0
- admin.php +413 -0
- api.php +142 -0
- app.py +333 -0
- composer-schema.json +25 -0
- composer.json +34 -0
- contato.php +300 -0
- database.sql +0 -0
- dev.sh +58 -0
- feedback.php +163 -0
- health.php +59 -0
- index.php +100 -0
- keep-alive.js +76 -0
- login.php +5 -0
- package.json +85 -0
- php.ini +67 -0
- projetos.php +444 -0
- react-demo.php +207 -0
- react-fallback.html +277 -0
- register.php +0 -0
- render.yaml +25 -0
- requirements.txt +4 -0
- servicos.php +388 -0
- sobre.php +290 -0
- test-react.php +0 -0
- test.html +49 -0
- webpack.config.js +184 -0
.babelrc
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"presets": [
|
| 3 |
+
"@babel/preset-env",
|
| 4 |
+
"@babel/preset-react"
|
| 5 |
+
]
|
| 6 |
+
}
|
.dockerignore
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Git
|
| 2 |
+
.git
|
| 3 |
+
.gitignore
|
| 4 |
+
|
| 5 |
+
# Documentation
|
| 6 |
+
README.md
|
| 7 |
+
*.md
|
| 8 |
+
|
| 9 |
+
# Development files
|
| 10 |
+
.env
|
| 11 |
+
.env.example
|
| 12 |
+
.vscode/
|
| 13 |
+
.idea/
|
| 14 |
+
|
| 15 |
+
# Logs
|
| 16 |
+
logs/
|
| 17 |
+
*.log
|
| 18 |
+
|
| 19 |
+
# OS generated files
|
| 20 |
+
.DS_Store
|
| 21 |
+
.DS_Store?
|
| 22 |
+
._*
|
| 23 |
+
.Spotlight-V100
|
| 24 |
+
.Trashes
|
| 25 |
+
ehthumbs.db
|
| 26 |
+
Thumbs.db
|
| 27 |
+
|
| 28 |
+
# Node modules (if any)
|
| 29 |
+
node_modules/
|
| 30 |
+
|
| 31 |
+
# Temporary files
|
| 32 |
+
tmp/
|
| 33 |
+
temp/
|
| 34 |
+
*.tmp
|
| 35 |
+
|
| 36 |
+
# Backup files
|
| 37 |
+
*.bak
|
| 38 |
+
*.backup
|
| 39 |
+
*~
|
| 40 |
+
|
| 41 |
+
# IDE files
|
| 42 |
+
.vscode/
|
| 43 |
+
.idea/
|
| 44 |
+
*.swp
|
| 45 |
+
*.swo
|
| 46 |
+
|
| 47 |
+
# Composer cache
|
| 48 |
+
vendor/
|
| 49 |
+
|
| 50 |
+
# Docker files
|
| 51 |
+
Dockerfile*
|
| 52 |
+
docker-compose*.yml
|
| 53 |
+
.dockerignore
|
| 54 |
+
|
| 55 |
+
# Railway/Render configs
|
| 56 |
+
railway.json
|
| 57 |
+
render.yaml
|
| 58 |
+
|
| 59 |
+
# Keep-alive script (not needed in main container)
|
| 60 |
+
keep-alive.js
|
.env.example
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SoftEdge Corporation - Environment Configuration
|
| 2 |
+
# Copy this file to .env and configure your settings
|
| 3 |
+
|
| 4 |
+
# ===========================================
|
| 5 |
+
# APPLICATION SETTINGS
|
| 6 |
+
# ===========================================
|
| 7 |
+
APP_NAME=SoftEdge Corporation
|
| 8 |
+
APP_ENV=production
|
| 9 |
+
APP_KEY=your_app_key_here
|
| 10 |
+
APP_URL=https://softedge-corporation.up.railway.app
|
| 11 |
+
|
| 12 |
+
# ===========================================
|
| 13 |
+
# DATABASE CONFIGURATION
|
| 14 |
+
# ===========================================
|
| 15 |
+
DB_CONNECTION=mysql
|
| 16 |
+
DB_HOST=localhost
|
| 17 |
+
DB_PORT=3306
|
| 18 |
+
DB_NAME=softedge_db
|
| 19 |
+
DB_USER=root
|
| 20 |
+
DB_PASS=
|
| 21 |
+
|
| 22 |
+
# ===========================================
|
| 23 |
+
# SECURITY SETTINGS
|
| 24 |
+
# ===========================================
|
| 25 |
+
JWT_SECRET=your_jwt_secret_here
|
| 26 |
+
CSRF_SECRET=your_csrf_secret_here
|
| 27 |
+
|
| 28 |
+
# ===========================================
|
| 29 |
+
# EMAIL CONFIGURATION
|
| 30 |
+
# ===========================================
|
| 31 |
+
MAIL_MAILER=smtp
|
| 32 |
+
MAIL_HOST=smtp.gmail.com
|
| 33 |
+
MAIL_PORT=587
|
| 34 |
+
MAIL_USERNAME=your_email@gmail.com
|
| 35 |
+
MAIL_PASSWORD=your_app_password
|
| 36 |
+
MAIL_ENCRYPTION=tls
|
| 37 |
+
MAIL_FROM_ADDRESS=your_email@gmail.com
|
| 38 |
+
MAIL_FROM_NAME="SoftEdge Corporation"
|
| 39 |
+
|
| 40 |
+
# ===========================================
|
| 41 |
+
# SOCIAL LOGIN (Optional)
|
| 42 |
+
# ===========================================
|
| 43 |
+
GOOGLE_CLIENT_ID=your_google_client_id
|
| 44 |
+
GOOGLE_CLIENT_SECRET=your_google_client_secret
|
| 45 |
+
|
| 46 |
+
GITHUB_CLIENT_ID=your_github_client_id
|
| 47 |
+
GITHUB_CLIENT_SECRET=your_github_client_secret
|
| 48 |
+
|
| 49 |
+
# ===========================================
|
| 50 |
+
# ADMIN CONFIGURATION
|
| 51 |
+
# ===========================================
|
| 52 |
+
ADMIN_EMAIL=admin@softedge.com
|
| 53 |
+
ADMIN_PASSWORD=Admin@123456
|
| 54 |
+
ADMIN_NAME=Isaac Quarenta
|
| 55 |
+
|
| 56 |
+
# ===========================================
|
| 57 |
+
# RATE LIMITING
|
| 58 |
+
# ===========================================
|
| 59 |
+
RATE_LIMIT_LOGIN=5
|
| 60 |
+
RATE_LIMIT_CONTACT=3
|
| 61 |
+
LOCKOUT_DURATION=900
|
| 62 |
+
|
| 63 |
+
# ===========================================
|
| 64 |
+
# ANALYTICS & LOGGING
|
| 65 |
+
# ===========================================
|
| 66 |
+
ANALYTICS_RETENTION_DAYS=365
|
| 67 |
+
LOG_LEVEL=info
|
| 68 |
+
|
| 69 |
+
# ===========================================
|
| 70 |
+
# TIMEZONE & LOCALIZATION
|
| 71 |
+
# ===========================================
|
| 72 |
+
TIMEZONE=Africa/Luanda
|
| 73 |
+
LANGUAGE=pt-BR
|
| 74 |
+
|
| 75 |
+
# ===========================================
|
| 76 |
+
# FILE UPLOAD SETTINGS
|
| 77 |
+
# ===========================================
|
| 78 |
+
MAX_FILE_SIZE=10240
|
| 79 |
+
ALLOWED_FILE_TYPES=jpg,jpeg,png,pdf,doc,docx
|
| 80 |
+
|
| 81 |
+
# ===========================================
|
| 82 |
+
# CACHE & PERFORMANCE
|
| 83 |
+
# ===========================================
|
| 84 |
+
CACHE_DRIVER=file
|
| 85 |
+
SESSION_DRIVER=file
|
| 86 |
+
SESSION_LIFETIME=86400
|
| 87 |
+
|
| 88 |
+
# ===========================================
|
| 89 |
+
# EXTERNAL SERVICES
|
| 90 |
+
# ===========================================
|
| 91 |
+
# Google Analytics
|
| 92 |
+
GA_TRACKING_ID=GA_MEASUREMENT_ID
|
| 93 |
+
|
| 94 |
+
# reCAPTCHA
|
| 95 |
+
RECAPTCHA_SITE_KEY=your_recaptcha_site_key
|
| 96 |
+
RECAPTCHA_SECRET_KEY=your_recaptcha_secret_key
|
| 97 |
+
|
| 98 |
+
# ===========================================
|
| 99 |
+
# DEVELOPMENT SETTINGS
|
| 100 |
+
# ===========================================
|
| 101 |
+
DEBUG=false
|
| 102 |
+
LOG_QUERIES=false
|
.gitignore
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Dependencies
|
| 2 |
+
/vendor/
|
| 3 |
+
/node_modules/
|
| 4 |
+
|
| 5 |
+
# Environment variables
|
| 6 |
+
.env
|
| 7 |
+
.env.local
|
| 8 |
+
.env.production
|
| 9 |
+
.env.staging
|
| 10 |
+
|
| 11 |
+
# Logs
|
| 12 |
+
logs/
|
| 13 |
+
*.log
|
| 14 |
+
npm-debug.log*
|
| 15 |
+
yarn-debug.log*
|
| 16 |
+
yarn-error.log*
|
| 17 |
+
|
| 18 |
+
# Runtime data
|
| 19 |
+
pids
|
| 20 |
+
*.pid
|
| 21 |
+
*.seed
|
| 22 |
+
*.pid.lock
|
| 23 |
+
|
| 24 |
+
# Coverage directory used by tools like istanbul
|
| 25 |
+
coverage/
|
| 26 |
+
.nyc_output
|
| 27 |
+
|
| 28 |
+
# Dependency directories
|
| 29 |
+
jspm_packages/
|
| 30 |
+
|
| 31 |
+
# Optional npm cache directory
|
| 32 |
+
.npm
|
| 33 |
+
|
| 34 |
+
# Optional REPL history
|
| 35 |
+
.node_repl_history
|
| 36 |
+
|
| 37 |
+
# Output of 'npm pack'
|
| 38 |
+
*.tgz
|
| 39 |
+
|
| 40 |
+
# Yarn Integrity file
|
| 41 |
+
.yarn-integrity
|
| 42 |
+
|
| 43 |
+
# dotenv environment variables file
|
| 44 |
+
.env
|
| 45 |
+
|
| 46 |
+
# IDE files
|
| 47 |
+
.vscode/
|
| 48 |
+
.idea/
|
| 49 |
+
*.swp
|
| 50 |
+
*.swo
|
| 51 |
+
*~
|
| 52 |
+
|
| 53 |
+
# OS generated files
|
| 54 |
+
.DS_Store
|
| 55 |
+
.DS_Store?
|
| 56 |
+
._*
|
| 57 |
+
.Spotlight-V100
|
| 58 |
+
.Trashes
|
| 59 |
+
ehthumbs.db
|
| 60 |
+
Thumbs.db
|
| 61 |
+
|
| 62 |
+
# Temporary files
|
| 63 |
+
tmp/
|
| 64 |
+
temp/
|
| 65 |
+
*.tmp
|
| 66 |
+
*.bak
|
| 67 |
+
*.backup
|
| 68 |
+
|
| 69 |
+
# Composer
|
| 70 |
+
composer.lock
|
| 71 |
+
/vendor/
|
| 72 |
+
|
| 73 |
+
# PHP
|
| 74 |
+
.phpunit.result.cache
|
| 75 |
+
|
| 76 |
+
# Docker
|
| 77 |
+
.dockerignore
|
| 78 |
+
|
| 79 |
+
# Railway/Render
|
| 80 |
+
railway.json
|
| 81 |
+
render.yaml
|
| 82 |
+
|
| 83 |
+
# Keep-alive script
|
| 84 |
+
keep-alive.js
|
| 85 |
+
|
| 86 |
+
# React build output
|
| 87 |
+
dist/
|
| 88 |
+
build/
|
| 89 |
+
|
| 90 |
+
# Documentation
|
| 91 |
+
README.md
|
| 92 |
+
*.md
|
.htaccess
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SoftEdge Corporation - Professional Apache Configuration
|
| 2 |
+
# Security and Performance Optimizations
|
| 3 |
+
|
| 4 |
+
# Prevent access to sensitive files
|
| 5 |
+
<FilesMatch "\.(htaccess|htpasswd|ini|log|sh|sql|conf)$">
|
| 6 |
+
Order Allow,Deny
|
| 7 |
+
Deny from all
|
| 8 |
+
</FilesMatch>
|
| 9 |
+
|
| 10 |
+
# Prevent access to vendor directory (using FilesMatch instead)
|
| 11 |
+
<FilesMatch "^vendor/">
|
| 12 |
+
Order Allow,Deny
|
| 13 |
+
Deny from all
|
| 14 |
+
</FilesMatch>
|
| 15 |
+
|
| 16 |
+
# Prevent access to logs directory (using FilesMatch instead)
|
| 17 |
+
<FilesMatch "^logs/">
|
| 18 |
+
Order Allow,Deny
|
| 19 |
+
Deny from all
|
| 20 |
+
</FilesMatch>
|
| 21 |
+
|
| 22 |
+
# Prevent access to .env files
|
| 23 |
+
<Files ".env*">
|
| 24 |
+
Order Allow,Deny
|
| 25 |
+
Deny from all
|
| 26 |
+
</Files>
|
| 27 |
+
|
| 28 |
+
# Enable URL rewriting
|
| 29 |
+
RewriteEngine On
|
| 30 |
+
|
| 31 |
+
# Force HTTPS (uncomment when SSL is available)
|
| 32 |
+
# RewriteCond %{HTTPS} off
|
| 33 |
+
# RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
| 34 |
+
|
| 35 |
+
# Remove trailing slash
|
| 36 |
+
RewriteCond %{REQUEST_FILENAME} !-d
|
| 37 |
+
RewriteCond %{REQUEST_URI} (.+)/$
|
| 38 |
+
RewriteRule ^ %1 [R=301,L]
|
| 39 |
+
|
| 40 |
+
# Handle PHP files without .php extension (optional)
|
| 41 |
+
# RewriteCond %{REQUEST_FILENAME} !-d
|
| 42 |
+
# RewriteCond %{REQUEST_FILENAME} !-f
|
| 43 |
+
# RewriteCond %{REQUEST_FILENAME}.php -f
|
| 44 |
+
# RewriteRule ^(.*)$ $1.php [L]
|
| 45 |
+
|
| 46 |
+
# Health check endpoint
|
| 47 |
+
RewriteRule ^health$ health.php [L]
|
| 48 |
+
|
| 49 |
+
# Security headers (additional layer)
|
| 50 |
+
<IfModule mod_headers.c>
|
| 51 |
+
# Prevent clickjacking
|
| 52 |
+
Header always set X-Frame-Options DENY
|
| 53 |
+
|
| 54 |
+
# Prevent MIME type sniffing
|
| 55 |
+
Header always set X-Content-Type-Options nosniff
|
| 56 |
+
|
| 57 |
+
# Enable XSS filtering
|
| 58 |
+
Header always set X-XSS-Protection "1; mode=block"
|
| 59 |
+
|
| 60 |
+
# Referrer Policy
|
| 61 |
+
Header always set Referrer-Policy "strict-origin-when-cross-origin"
|
| 62 |
+
|
| 63 |
+
# Content Security Policy
|
| 64 |
+
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://unpkg.com https://cdn.tailwindcss.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self'"
|
| 65 |
+
|
| 66 |
+
# HSTS (uncomment when SSL is available)
|
| 67 |
+
# Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
| 68 |
+
</IfModule>
|
| 69 |
+
|
| 70 |
+
# Compression
|
| 71 |
+
<IfModule mod_deflate.c>
|
| 72 |
+
AddOutputFilterByType DEFLATE text/plain
|
| 73 |
+
AddOutputFilterByType DEFLATE text/html
|
| 74 |
+
AddOutputFilterByType DEFLATE text/xml
|
| 75 |
+
AddOutputFilterByType DEFLATE text/css
|
| 76 |
+
AddOutputFilterByType DEFLATE application/xml
|
| 77 |
+
AddOutputFilterByType DEFLATE application/xhtml+xml
|
| 78 |
+
AddOutputFilterByType DEFLATE application/rss+xml
|
| 79 |
+
AddOutputFilterByType DEFLATE application/javascript
|
| 80 |
+
AddOutputFilterByType DEFLATE application/x-javascript
|
| 81 |
+
AddOutputFilterByType DEFLATE application/json
|
| 82 |
+
</IfModule>
|
| 83 |
+
|
| 84 |
+
# Browser caching
|
| 85 |
+
<IfModule mod_expires.c>
|
| 86 |
+
ExpiresActive On
|
| 87 |
+
ExpiresByType image/jpg "access plus 1 month"
|
| 88 |
+
ExpiresByType image/jpeg "access plus 1 month"
|
| 89 |
+
ExpiresByType image/gif "access plus 1 month"
|
| 90 |
+
ExpiresByType image/png "access plus 1 month"
|
| 91 |
+
ExpiresByType image/svg+xml "access plus 1 month"
|
| 92 |
+
ExpiresByType text/css "access plus 1 month"
|
| 93 |
+
ExpiresByType application/pdf "access plus 1 month"
|
| 94 |
+
ExpiresByType text/javascript "access plus 1 week"
|
| 95 |
+
ExpiresByType application/javascript "access plus 1 week"
|
| 96 |
+
ExpiresByType application/x-shockwave-flash "access plus 1 month"
|
| 97 |
+
ExpiresByType image/x-icon "access plus 1 year"
|
| 98 |
+
ExpiresDefault "access plus 2 days"
|
| 99 |
+
</IfModule>
|
| 100 |
+
|
| 101 |
+
# PHP settings
|
| 102 |
+
<IfModule mod_php.c>
|
| 103 |
+
php_value upload_max_filesize 10M
|
| 104 |
+
php_value post_max_size 10M
|
| 105 |
+
php_value max_execution_time 300
|
| 106 |
+
php_value memory_limit 256M
|
| 107 |
+
php_flag display_errors Off
|
| 108 |
+
php_flag log_errors On
|
| 109 |
+
php_value error_log logs/php_errors.log
|
| 110 |
+
</IfModule>
|
| 111 |
+
|
| 112 |
+
# Error pages (commented out - files don't exist)
|
| 113 |
+
# ErrorDocument 404 /404.php
|
| 114 |
+
# ErrorDocument 403 /403.php
|
| 115 |
+
# ErrorDocument 500 /500.php
|
| 116 |
+
|
| 117 |
+
# Prevent image hotlinking (optional)
|
| 118 |
+
# RewriteCond %{HTTP_REFERER} !^$
|
| 119 |
+
# RewriteCond %{HTTP_REFERER} !^https?://(www\.)?softedge-corporation\.up\.railway\.app [NC]
|
| 120 |
+
# RewriteRule \.(gif|jpg|jpeg|png|svg)$ - [F,L]
|
.huggingface.yaml
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
emoji: 🚀
|
| 2 |
+
colorFrom: blue
|
| 3 |
+
colorTo: cyan
|
| 4 |
+
sdk: static
|
| 5 |
+
pinned: false
|
| 6 |
+
=======
|
| 7 |
+
title: SoftEdge Corporation
|
| 8 |
+
emoji: 🚀
|
| 9 |
+
colorFrom: blue
|
| 10 |
+
colorTo: cyan
|
| 11 |
+
sdk: gradio
|
| 12 |
+
sdk_version: 4.44.1
|
| 13 |
+
app_file: app.py
|
| 14 |
+
pinned: false
|
Dockerfile
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ================================
|
| 2 |
+
# SoftEdge Corporation — HF Spaces
|
| 3 |
+
# PHP 8.3 + Apache (ESTÁVEL)
|
| 4 |
+
# ================================
|
| 5 |
+
FROM php:8.3-apache
|
| 6 |
+
|
| 7 |
+
# ----------------
|
| 8 |
+
# VARIÁVEIS
|
| 9 |
+
# ----------------
|
| 10 |
+
ENV PORT=7860
|
| 11 |
+
ENV APACHE_RUN_USER=www-data
|
| 12 |
+
ENV APACHE_RUN_GROUP=www-data
|
| 13 |
+
ENV APACHE_LOG_DIR=/var/log/apache2
|
| 14 |
+
|
| 15 |
+
# ----------------
|
| 16 |
+
# DEPENDÊNCIAS DO SISTEMA
|
| 17 |
+
# ----------------
|
| 18 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 19 |
+
libpng-dev \
|
| 20 |
+
libjpeg-dev \
|
| 21 |
+
libfreetype6-dev \
|
| 22 |
+
libzip-dev \
|
| 23 |
+
libicu-dev \
|
| 24 |
+
libxml2-dev \
|
| 25 |
+
libcurl4-openssl-dev \
|
| 26 |
+
libonig-dev \
|
| 27 |
+
sqlite3 \
|
| 28 |
+
libsqlite3-dev \
|
| 29 |
+
git \
|
| 30 |
+
curl \
|
| 31 |
+
cron \
|
| 32 |
+
unzip \
|
| 33 |
+
ca-certificates \
|
| 34 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 35 |
+
|
| 36 |
+
# ----------------
|
| 37 |
+
# EXTENSÕES PHP (CONTROLADAS)
|
| 38 |
+
# ----------------
|
| 39 |
+
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
|
| 40 |
+
&& docker-php-ext-install \
|
| 41 |
+
mbstring \
|
| 42 |
+
exif \
|
| 43 |
+
bcmath \
|
| 44 |
+
intl \
|
| 45 |
+
zip \
|
| 46 |
+
gd \
|
| 47 |
+
mysqli \
|
| 48 |
+
pdo \
|
| 49 |
+
pdo_mysql \
|
| 50 |
+
pdo_sqlite \
|
| 51 |
+
&& docker-php-ext-enable \
|
| 52 |
+
mbstring exif bcmath intl zip gd mysqli pdo_mysql pdo_sqlite
|
| 53 |
+
|
| 54 |
+
# 🔥 LIMPEZA DE INIs DUPLICADOS (CRÍTICO)
|
| 55 |
+
RUN find /usr/local/etc/php/conf.d -type f -name "*docker-php-ext-*" -exec sed -i '/^extension=/d' {} \;
|
| 56 |
+
|
| 57 |
+
# ----------------
|
| 58 |
+
# COMPOSER
|
| 59 |
+
# ----------------
|
| 60 |
+
RUN curl -sS https://getcomposer.org/installer | php -- \
|
| 61 |
+
--install-dir=/usr/local/bin \
|
| 62 |
+
--filename=composer
|
| 63 |
+
|
| 64 |
+
# ----------------
|
| 65 |
+
# NODE (opcional p/ React)
|
| 66 |
+
# ----------------
|
| 67 |
+
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
| 68 |
+
&& apt-get install -y nodejs \
|
| 69 |
+
&& node -v && npm -v
|
| 70 |
+
|
| 71 |
+
# ----------------
|
| 72 |
+
# APACHE CONFIG
|
| 73 |
+
# ----------------
|
| 74 |
+
RUN a2enmod rewrite headers
|
| 75 |
+
|
| 76 |
+
# ServerName GLOBAL (remove AH00558 de vez)
|
| 77 |
+
RUN echo "ServerName localhost" > /etc/apache2/conf-available/servername.conf \
|
| 78 |
+
&& a2enconf servername
|
| 79 |
+
|
| 80 |
+
# Porta HF Spaces
|
| 81 |
+
RUN sed -i 's/Listen 80/Listen 7860/' /etc/apache2/ports.conf
|
| 82 |
+
|
| 83 |
+
RUN printf '<VirtualHost *:7860>\n\
|
| 84 |
+
ServerName localhost\n\
|
| 85 |
+
DocumentRoot /var/www/html\n\
|
| 86 |
+
<Directory /var/www/html>\n\
|
| 87 |
+
AllowOverride All\n\
|
| 88 |
+
Require all granted\n\
|
| 89 |
+
</Directory>\n\
|
| 90 |
+
ErrorLog ${APACHE_LOG_DIR}/error.log\n\
|
| 91 |
+
CustomLog ${APACHE_LOG_DIR}/access.log combined\n\
|
| 92 |
+
</VirtualHost>\n' > /etc/apache2/sites-available/000-default.conf
|
| 93 |
+
|
| 94 |
+
# ----------------
|
| 95 |
+
# APP
|
| 96 |
+
# ----------------
|
| 97 |
+
WORKDIR /var/www/html
|
| 98 |
+
COPY . .
|
| 99 |
+
|
| 100 |
+
# Logs e storage
|
| 101 |
+
RUN mkdir -p logs storage \
|
| 102 |
+
&& chown -R www-data:www-data /var/www/html \
|
| 103 |
+
&& chmod -R 775 logs storage
|
| 104 |
+
|
| 105 |
+
# ----------------
|
| 106 |
+
# COMPOSER INSTALL
|
| 107 |
+
# ----------------
|
| 108 |
+
RUN if [ -f composer.json ]; then \
|
| 109 |
+
composer install --no-dev --optimize-autoloader --no-interaction; \
|
| 110 |
+
fi
|
| 111 |
+
|
| 112 |
+
# ----------------
|
| 113 |
+
# REACT BUILD (SE EXISTIR)
|
| 114 |
+
# ----------------
|
| 115 |
+
RUN if [ -f package.json ]; then \
|
| 116 |
+
npm install && npm run build; \
|
| 117 |
+
fi
|
| 118 |
+
|
| 119 |
+
# ----------------
|
| 120 |
+
# PHP CONFIG FINAL
|
| 121 |
+
# ----------------
|
| 122 |
+
RUN printf "display_errors=Off\n\
|
| 123 |
+
log_errors=On\n\
|
| 124 |
+
error_log=/var/www/html/logs/php_errors.log\n\
|
| 125 |
+
memory_limit=256M\n\
|
| 126 |
+
upload_max_filesize=10M\n\
|
| 127 |
+
post_max_size=10M\n\
|
| 128 |
+
max_execution_time=300\n" > /usr/local/etc/php/conf.d/99-softedge.ini
|
| 129 |
+
|
| 130 |
+
# ----------------
|
| 131 |
+
# HEALTHCHECK
|
| 132 |
+
# ----------------
|
| 133 |
+
RUN echo "<?php http_response_code(200); echo 'OK';" > /var/www/html/health.php
|
| 134 |
+
|
| 135 |
+
HEALTHCHECK --interval=60s --timeout=5s \
|
| 136 |
+
CMD curl -f http://localhost:7860/health.php || exit 1
|
| 137 |
+
|
| 138 |
+
# ----------------
|
| 139 |
+
# START
|
| 140 |
+
# ----------------
|
| 141 |
+
EXPOSE 7860
|
| 142 |
+
CMD ["apache2-foreground"]
|
Dockerfile.railway
ADDED
|
File without changes
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2025 SoftEdge Corporation
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
README-RAILWAY.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚂 SoftEdge Corporation - Railway Deployment Guide
|
| 2 |
+
|
| 3 |
+
## Problema Identificado
|
| 4 |
+
|
| 5 |
+
O erro `AH00534: apache2: Configuration error: More than one MPM loaded` ocorre especificamente no Railway devido a conflitos entre múltiplos MPMs (Multi-Processing Modules) do Apache.
|
| 6 |
+
|
| 7 |
+
## Solução
|
| 8 |
+
|
| 9 |
+
Use o `Dockerfile.railway` otimizado especificamente para Railway:
|
| 10 |
+
|
| 11 |
+
### Passos para Deploy no Railway:
|
| 12 |
+
|
| 13 |
+
1. **Renomeie o Dockerfile:**
|
| 14 |
+
```bash
|
| 15 |
+
mv Dockerfile Dockerfile.original
|
| 16 |
+
mv Dockerfile.railway Dockerfile
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
2. **Commit e Push:**
|
| 20 |
+
```bash
|
| 21 |
+
git add .
|
| 22 |
+
git commit -m "Fix Railway MPM conflict with optimized Dockerfile"
|
| 23 |
+
git push origin main
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
3. **Railway fará automaticamente:**
|
| 27 |
+
- Build da imagem Docker otimizada
|
| 28 |
+
- Resolução do conflito de MPMs
|
| 29 |
+
- Deploy bem-sucedido
|
| 30 |
+
|
| 31 |
+
## O que foi alterado no Dockerfile.railway:
|
| 32 |
+
|
| 33 |
+
### ✅ Correções Aplicadas:
|
| 34 |
+
|
| 35 |
+
1. **MPM Fix Robusto:**
|
| 36 |
+
```dockerfile
|
| 37 |
+
RUN service apache2 stop && \
|
| 38 |
+
a2dismod mpm_event 2>/dev/null || true && \
|
| 39 |
+
a2dismod mpm_worker 2>/dev/null || true && \
|
| 40 |
+
a2dismod mpm_prefork 2>/dev/null || true && \
|
| 41 |
+
a2enmod mpm_prefork
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
2. **Configuração Apache Simplificada:**
|
| 45 |
+
- Removidos headers de segurança complexos que podem causar conflitos
|
| 46 |
+
- Configuração mínima necessária para Railway
|
| 47 |
+
|
| 48 |
+
3. **Startup Direto:**
|
| 49 |
+
- Removido script de startup complexo
|
| 50 |
+
- Apache iniciado diretamente com `apache2-foreground`
|
| 51 |
+
|
| 52 |
+
## Verificação
|
| 53 |
+
|
| 54 |
+
Após o deploy, verifique:
|
| 55 |
+
- ✅ Container inicia sem erros de MPM
|
| 56 |
+
- ✅ Apache responde na porta configurada
|
| 57 |
+
- ✅ Aplicação PHP+React funcionando
|
| 58 |
+
- ✅ Health check passando
|
| 59 |
+
|
| 60 |
+
## Rollback (se necessário)
|
| 61 |
+
|
| 62 |
+
Para voltar à versão original:
|
| 63 |
+
```bash
|
| 64 |
+
mv Dockerfile Dockerfile.railway
|
| 65 |
+
mv Dockerfile.original Dockerfile
|
| 66 |
+
git add .
|
| 67 |
+
git commit -m "Rollback to original Dockerfile"
|
| 68 |
+
git push origin main
|
| 69 |
+
```
|
| 70 |
+
|
| 71 |
+
## Suporte
|
| 72 |
+
|
| 73 |
+
Se o problema persistir:
|
| 74 |
+
1. Verifique os logs do Railway
|
| 75 |
+
2. Confirme que está usando `Dockerfile.railway`
|
| 76 |
+
3. Teste localmente: `docker build -f Dockerfile.railway -t test . && docker run -p 8080:8080 test`
|
| 77 |
+
|
| 78 |
+
---
|
| 79 |
+
|
| 80 |
+
**🎯 Esta solução resolve especificamente o conflito de MPMs no Railway mantendo toda a funcionalidade da aplicação.**
|
Railway.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"$schema": "https://railway.app/railway.schema.json",
|
| 3 |
+
"build": {
|
| 4 |
+
"builder": "dockerfile"
|
| 5 |
+
},
|
| 6 |
+
"start": "apache2-foreground"
|
| 7 |
+
}
|
admin.php
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
// Start session and check authentication
|
| 3 |
+
session_start();
|
| 4 |
+
|
| 5 |
+
// Check if user is logged in and is admin
|
| 6 |
+
if (!isset($_SESSION['user']) || !isset($_SESSION['session_token'])) {
|
| 7 |
+
header('Location: login.php');
|
| 8 |
+
exit;
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
// Autoload Composer dependencies
|
| 12 |
+
require_once __DIR__ . '/vendor/autoload.php';
|
| 13 |
+
|
| 14 |
+
// Load environment variables
|
| 15 |
+
if (file_exists(__DIR__ . '/.env')) {
|
| 16 |
+
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
|
| 17 |
+
$dotenv->load();
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
// Initialize User class
|
| 21 |
+
$user = new \SoftEdge\User();
|
| 22 |
+
|
| 23 |
+
// Validate session
|
| 24 |
+
$sessionUser = $user->validateSession($_SESSION['session_token']);
|
| 25 |
+
if (!$sessionUser || $sessionUser['role'] !== 'admin') {
|
| 26 |
+
session_destroy();
|
| 27 |
+
header('Location: login.php');
|
| 28 |
+
exit;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
// Get admin statistics
|
| 32 |
+
$stats = $user->getAdminStats();
|
| 33 |
+
|
| 34 |
+
// Log admin page visit
|
| 35 |
+
$user->logPageVisit($sessionUser['id'], 'admin_dashboard', $_SERVER['HTTP_USER_AGENT'] ?? '');
|
| 36 |
+
|
| 37 |
+
// Handle logout
|
| 38 |
+
if (isset($_POST['logout'])) {
|
| 39 |
+
// Invalidate session
|
| 40 |
+
try {
|
| 41 |
+
$db = new PDO("mysql:host={$_ENV['DB_HOST']};dbname={$_ENV['DB_NAME']}", $_ENV['DB_USER'], $_ENV['DB_PASS']);
|
| 42 |
+
$stmt = $db->prepare("DELETE FROM user_sessions WHERE session_token = ?");
|
| 43 |
+
$stmt->execute([$_SESSION['session_token']]);
|
| 44 |
+
} catch (Exception $e) {
|
| 45 |
+
error_log("Session cleanup failed: " . $e->getMessage());
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
session_destroy();
|
| 49 |
+
header('Location: login.php');
|
| 50 |
+
exit;
|
| 51 |
+
}
|
| 52 |
+
?>
|
| 53 |
+
|
| 54 |
+
<!DOCTYPE html>
|
| 55 |
+
<html lang="pt-BR" class="scroll-smooth">
|
| 56 |
+
<head>
|
| 57 |
+
<meta charset="UTF-8" />
|
| 58 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 59 |
+
<title>Painel Administrativo - SoftEdge Corporation</title>
|
| 60 |
+
|
| 61 |
+
<!-- SEO -->
|
| 62 |
+
<meta name="description" content="Painel administrativo SoftEdge Corporation">
|
| 63 |
+
<meta name="robots" content="noindex, nofollow">
|
| 64 |
+
|
| 65 |
+
<!-- Favicon -->
|
| 66 |
+
<link rel="icon" href="/assets/placeholder.svg" type="image/svg+xml">
|
| 67 |
+
|
| 68 |
+
<!-- Fonts -->
|
| 69 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 70 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 71 |
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
| 72 |
+
|
| 73 |
+
<!-- Tailwind CSS -->
|
| 74 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 75 |
+
<script>
|
| 76 |
+
tailwind.config = {
|
| 77 |
+
theme: {
|
| 78 |
+
extend: {
|
| 79 |
+
fontFamily: {
|
| 80 |
+
sans: ['Inter', 'system-ui', 'sans-serif'],
|
| 81 |
+
},
|
| 82 |
+
colors: {
|
| 83 |
+
primary: {
|
| 84 |
+
50: '#f8fafc',
|
| 85 |
+
100: '#f1f5f9',
|
| 86 |
+
200: '#e2e8f0',
|
| 87 |
+
300: '#cbd5e1',
|
| 88 |
+
400: '#94a3b8',
|
| 89 |
+
500: '#64748b',
|
| 90 |
+
600: '#475569',
|
| 91 |
+
700: '#334155',
|
| 92 |
+
800: '#1e293b',
|
| 93 |
+
900: '#0f172a',
|
| 94 |
+
}
|
| 95 |
+
}
|
| 96 |
+
}
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
</script>
|
| 100 |
+
|
| 101 |
+
<!-- Lucide Icons -->
|
| 102 |
+
<script src="https://unpkg.com/lucide@latest"></script>
|
| 103 |
+
|
| 104 |
+
<!-- Chart.js for analytics -->
|
| 105 |
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
| 106 |
+
|
| 107 |
+
<style>
|
| 108 |
+
.glass-card {
|
| 109 |
+
background: rgba(30, 41, 59, 0.8);
|
| 110 |
+
backdrop-filter: blur(20px);
|
| 111 |
+
-webkit-backdrop-filter: blur(20px);
|
| 112 |
+
border: 1px solid rgba(148, 163, 184, 0.1);
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
.stat-card {
|
| 116 |
+
transition: all 0.3s ease;
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
.stat-card:hover {
|
| 120 |
+
transform: translateY(-2px);
|
| 121 |
+
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
.fade-in {
|
| 125 |
+
animation: fadeIn 0.6s ease-out;
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
@keyframes fadeIn {
|
| 129 |
+
from { opacity: 0; transform: translateY(20px); }
|
| 130 |
+
to { opacity: 1; transform: translateY(0); }
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
.sidebar {
|
| 134 |
+
transform: translateX(-100%);
|
| 135 |
+
transition: transform 0.3s ease;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
.sidebar.open {
|
| 139 |
+
transform: translateX(0);
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
@media (min-width: 768px) {
|
| 143 |
+
.sidebar {
|
| 144 |
+
transform: translateX(0);
|
| 145 |
+
}
|
| 146 |
+
}
|
| 147 |
+
</style>
|
| 148 |
+
</head>
|
| 149 |
+
|
| 150 |
+
<body class="bg-slate-950 min-h-screen">
|
| 151 |
+
<!-- Sidebar -->
|
| 152 |
+
<div class="sidebar fixed inset-y-0 left-0 z-50 w-64 bg-slate-900 border-r border-slate-700 md:relative md:translate-x-0">
|
| 153 |
+
<div class="flex flex-col h-full">
|
| 154 |
+
<!-- Logo -->
|
| 155 |
+
<div class="flex items-center justify-center p-6 border-b border-slate-700">
|
| 156 |
+
<div class="flex items-center space-x-3">
|
| 157 |
+
<div class="w-8 h-8 rounded-lg overflow-hidden bg-slate-700 border border-slate-600">
|
| 158 |
+
<img src="/assets/logo.jpeg" alt="SoftEdge Logo" class="w-full h-full object-cover">
|
| 159 |
+
</div>
|
| 160 |
+
<span class="text-lg font-semibold text-slate-200 tracking-tight">
|
| 161 |
+
Admin Panel
|
| 162 |
+
</span>
|
| 163 |
+
</div>
|
| 164 |
+
</div>
|
| 165 |
+
|
| 166 |
+
<!-- Navigation -->
|
| 167 |
+
<nav class="flex-1 px-4 py-6 space-y-2">
|
| 168 |
+
<a href="#dashboard" class="nav-link flex items-center gap-3 px-4 py-3 text-slate-300 hover:text-white hover:bg-slate-800 rounded-lg transition-colors active">
|
| 169 |
+
<i data-lucide="layout-dashboard" class="w-5 h-5"></i>
|
| 170 |
+
<span>Dashboard</span>
|
| 171 |
+
</a>
|
| 172 |
+
|
| 173 |
+
<a href="#users" class="nav-link flex items-center gap-3 px-4 py-3 text-slate-400 hover:text-white hover:bg-slate-800 rounded-lg transition-colors">
|
| 174 |
+
<i data-lucide="users" class="w-5 h-5"></i>
|
| 175 |
+
<span>Usuários</span>
|
| 176 |
+
</a>
|
| 177 |
+
|
| 178 |
+
<a href="#analytics" class="nav-link flex items-center gap-3 px-4 py-3 text-slate-400 hover:text-white hover:bg-slate-800 rounded-lg transition-colors">
|
| 179 |
+
<i data-lucide="bar-chart-3" class="w-5 h-5"></i>
|
| 180 |
+
<span>Analytics</span>
|
| 181 |
+
</a>
|
| 182 |
+
|
| 183 |
+
<a href="#settings" class="nav-link flex items-center gap-3 px-4 py-3 text-slate-400 hover:text-white hover:bg-slate-800 rounded-lg transition-colors">
|
| 184 |
+
<i data-lucide="settings" class="w-5 h-5"></i>
|
| 185 |
+
<span>Configurações</span>
|
| 186 |
+
</a>
|
| 187 |
+
</nav>
|
| 188 |
+
|
| 189 |
+
<!-- User Info & Logout -->
|
| 190 |
+
<div class="p-4 border-t border-slate-700">
|
| 191 |
+
<div class="flex items-center gap-3 mb-4">
|
| 192 |
+
<div class="w-8 h-8 rounded-full bg-slate-700 flex items-center justify-center">
|
| 193 |
+
<i data-lucide="user" class="w-4 h-4 text-slate-400"></i>
|
| 194 |
+
</div>
|
| 195 |
+
<div class="flex-1 min-w-0">
|
| 196 |
+
<p class="text-sm font-medium text-slate-200 truncate">
|
| 197 |
+
<?php echo htmlspecialchars($sessionUser['name']); ?>
|
| 198 |
+
</p>
|
| 199 |
+
<p class="text-xs text-slate-400">Administrador</p>
|
| 200 |
+
</div>
|
| 201 |
+
</div>
|
| 202 |
+
|
| 203 |
+
<form method="POST" class="w-full">
|
| 204 |
+
<button type="submit" name="logout" class="w-full flex items-center gap-3 px-4 py-2 text-slate-400 hover:text-white hover:bg-red-500/10 hover:border-red-500/20 border border-transparent rounded-lg transition-all">
|
| 205 |
+
<i data-lucide="log-out" class="w-4 h-4"></i>
|
| 206 |
+
<span class="text-sm">Sair</span>
|
| 207 |
+
</button>
|
| 208 |
+
</form>
|
| 209 |
+
</div>
|
| 210 |
+
</div>
|
| 211 |
+
</div>
|
| 212 |
+
|
| 213 |
+
<!-- Mobile Overlay -->
|
| 214 |
+
<div class="sidebar-overlay fixed inset-0 bg-black/50 z-40 md:hidden opacity-0 pointer-events-none transition-opacity"></div>
|
| 215 |
+
|
| 216 |
+
<!-- Main Content -->
|
| 217 |
+
<div class="md:ml-64">
|
| 218 |
+
<!-- Header -->
|
| 219 |
+
<header class="bg-slate-900/50 backdrop-blur-xl border-b border-slate-700 p-4 md:p-6">
|
| 220 |
+
<div class="flex items-center justify-between">
|
| 221 |
+
<div class="flex items-center gap-4">
|
| 222 |
+
<button class="md:hidden text-slate-400 hover:text-white p-2" id="sidebarToggle">
|
| 223 |
+
<i data-lucide="menu" class="w-6 h-6"></i>
|
| 224 |
+
</button>
|
| 225 |
+
<div>
|
| 226 |
+
<h1 class="text-2xl font-bold text-white">Dashboard Administrativo</h1>
|
| 227 |
+
<p class="text-slate-400 text-sm">Bem-vindo de volta, <?php echo htmlspecialchars(explode(' ', $sessionUser['name'])[0]); ?>!</p>
|
| 228 |
+
</div>
|
| 229 |
+
</div>
|
| 230 |
+
|
| 231 |
+
<div class="flex items-center gap-4">
|
| 232 |
+
<div class="hidden md:flex items-center gap-2 text-slate-400 text-sm">
|
| 233 |
+
<i data-lucide="clock" class="w-4 h-4"></i>
|
| 234 |
+
<span><?php echo date('d/m/Y H:i'); ?></span>
|
| 235 |
+
</div>
|
| 236 |
+
</div>
|
| 237 |
+
</div>
|
| 238 |
+
</header>
|
| 239 |
+
|
| 240 |
+
<!-- Dashboard Content -->
|
| 241 |
+
<main class="p-4 md:p-6 space-y-6">
|
| 242 |
+
<!-- Stats Cards -->
|
| 243 |
+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
| 244 |
+
<div class="stat-card glass-card p-6 rounded-xl">
|
| 245 |
+
<div class="flex items-center justify-between">
|
| 246 |
+
<div>
|
| 247 |
+
<p class="text-slate-400 text-sm font-medium">Total de Usuários</p>
|
| 248 |
+
<p class="text-2xl font-bold text-white"><?php echo number_format($stats['total_users'] ?? 0); ?></p>
|
| 249 |
+
</div>
|
| 250 |
+
<div class="w-12 h-12 bg-blue-500/20 rounded-lg flex items-center justify-center">
|
| 251 |
+
<i data-lucide="users" class="w-6 h-6 text-blue-400"></i>
|
| 252 |
+
</div>
|
| 253 |
+
</div>
|
| 254 |
+
</div>
|
| 255 |
+
|
| 256 |
+
<div class="stat-card glass-card p-6 rounded-xl">
|
| 257 |
+
<div class="flex items-center justify-between">
|
| 258 |
+
<div>
|
| 259 |
+
<p class="text-slate-400 text-sm font-medium">Total de Visitas</p>
|
| 260 |
+
<p class="text-2xl font-bold text-white"><?php echo number_format($stats['total_visits'] ?? 0); ?></p>
|
| 261 |
+
</div>
|
| 262 |
+
<div class="w-12 h-12 bg-green-500/20 rounded-lg flex items-center justify-center">
|
| 263 |
+
<i data-lucide="eye" class="w-6 h-6 text-green-400"></i>
|
| 264 |
+
</div>
|
| 265 |
+
</div>
|
| 266 |
+
</div>
|
| 267 |
+
|
| 268 |
+
<div class="stat-card glass-card p-6 rounded-xl">
|
| 269 |
+
<div class="flex items-center justify-between">
|
| 270 |
+
<div>
|
| 271 |
+
<p class="text-slate-400 text-sm font-medium">Visitas (30 dias)</p>
|
| 272 |
+
<p class="text-2xl font-bold text-white"><?php echo number_format($stats['recent_visits'] ?? 0); ?></p>
|
| 273 |
+
</div>
|
| 274 |
+
<div class="w-12 h-12 bg-purple-500/20 rounded-lg flex items-center justify-center">
|
| 275 |
+
<i data-lucide="trending-up" class="w-6 h-6 text-purple-400"></i>
|
| 276 |
+
</div>
|
| 277 |
+
</div>
|
| 278 |
+
</div>
|
| 279 |
+
|
| 280 |
+
<div class="stat-card glass-card p-6 rounded-xl">
|
| 281 |
+
<div class="flex items-center justify-between">
|
| 282 |
+
<div>
|
| 283 |
+
<p class="text-slate-400 text-sm font-medium">Taxa de Conversão</p>
|
| 284 |
+
<p class="text-2xl font-bold text-white">
|
| 285 |
+
<?php
|
| 286 |
+
$conversion = $stats['total_users'] > 0 ? (($stats['total_visits'] ?? 0) / $stats['total_users']) : 0;
|
| 287 |
+
echo number_format($conversion, 1);
|
| 288 |
+
?>x
|
| 289 |
+
</p>
|
| 290 |
+
</div>
|
| 291 |
+
<div class="w-12 h-12 bg-orange-500/20 rounded-lg flex items-center justify-center">
|
| 292 |
+
<i data-lucide="target" class="w-6 h-6 text-orange-400"></i>
|
| 293 |
+
</div>
|
| 294 |
+
</div>
|
| 295 |
+
</div>
|
| 296 |
+
</div>
|
| 297 |
+
|
| 298 |
+
<!-- Charts and Tables -->
|
| 299 |
+
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
| 300 |
+
<!-- Top Pages Chart -->
|
| 301 |
+
<div class="glass-card p-6 rounded-xl">
|
| 302 |
+
<h3 class="text-lg font-semibold text-white mb-4 flex items-center gap-2">
|
| 303 |
+
<i data-lucide="bar-chart-3" class="w-5 h-5 text-slate-400"></i>
|
| 304 |
+
Páginas Mais Visitadas
|
| 305 |
+
</h3>
|
| 306 |
+
<div class="space-y-3">
|
| 307 |
+
<?php foreach (($stats['top_pages'] ?? []) as $page): ?>
|
| 308 |
+
<div class="flex items-center justify-between p-3 bg-slate-800/50 rounded-lg">
|
| 309 |
+
<span class="text-slate-300 capitalize"><?php echo htmlspecialchars($page['page']); ?></span>
|
| 310 |
+
<span class="text-slate-400 text-sm"><?php echo number_format($page['visits']); ?> visitas</span>
|
| 311 |
+
</div>
|
| 312 |
+
<?php endforeach; ?>
|
| 313 |
+
</div>
|
| 314 |
+
</div>
|
| 315 |
+
|
| 316 |
+
<!-- Recent Users -->
|
| 317 |
+
<div class="glass-card p-6 rounded-xl">
|
| 318 |
+
<h3 class="text-lg font-semibold text-white mb-4 flex items-center gap-2">
|
| 319 |
+
<i data-lucide="user-plus" class="w-5 h-5 text-slate-400"></i>
|
| 320 |
+
Usuários Recentes
|
| 321 |
+
</h3>
|
| 322 |
+
<div class="space-y-3">
|
| 323 |
+
<?php foreach (($stats['recent_users'] ?? []) as $recentUser): ?>
|
| 324 |
+
<div class="flex items-center gap-3 p-3 bg-slate-800/50 rounded-lg">
|
| 325 |
+
<div class="w-8 h-8 rounded-full bg-slate-700 flex items-center justify-center">
|
| 326 |
+
<i data-lucide="user" class="w-4 h-4 text-slate-400"></i>
|
| 327 |
+
</div>
|
| 328 |
+
<div class="flex-1 min-w-0">
|
| 329 |
+
<p class="text-slate-300 text-sm font-medium truncate"><?php echo htmlspecialchars($recentUser['name']); ?></p>
|
| 330 |
+
<p class="text-slate-400 text-xs"><?php echo date('d/m/Y', strtotime($recentUser['created_at'])); ?></p>
|
| 331 |
+
</div>
|
| 332 |
+
</div>
|
| 333 |
+
<?php endforeach; ?>
|
| 334 |
+
</div>
|
| 335 |
+
</div>
|
| 336 |
+
</div>
|
| 337 |
+
|
| 338 |
+
<!-- System Info -->
|
| 339 |
+
<div class="glass-card p-6 rounded-xl">
|
| 340 |
+
<h3 class="text-lg font-semibold text-white mb-4 flex items-center gap-2">
|
| 341 |
+
<i data-lucide="server" class="w-5 h-5 text-slate-400"></i>
|
| 342 |
+
Informações do Sistema
|
| 343 |
+
</h3>
|
| 344 |
+
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
| 345 |
+
<div class="p-4 bg-slate-800/50 rounded-lg">
|
| 346 |
+
<p class="text-slate-400 text-sm">PHP Version</p>
|
| 347 |
+
<p class="text-white font-medium"><?php echo PHP_VERSION; ?></p>
|
| 348 |
+
</div>
|
| 349 |
+
<div class="p-4 bg-slate-800/50 rounded-lg">
|
| 350 |
+
<p class="text-slate-400 text-sm">Database</p>
|
| 351 |
+
<p class="text-white font-medium">MySQL</p>
|
| 352 |
+
</div>
|
| 353 |
+
<div class="p-4 bg-slate-800/50 rounded-lg">
|
| 354 |
+
<p class="text-slate-400 text-sm">Último Backup</p>
|
| 355 |
+
<p class="text-white font-medium"><?php echo date('d/m/Y H:i'); ?></p>
|
| 356 |
+
</div>
|
| 357 |
+
</div>
|
| 358 |
+
</div>
|
| 359 |
+
</main>
|
| 360 |
+
</div>
|
| 361 |
+
|
| 362 |
+
<!-- Scripts -->
|
| 363 |
+
<script src="https://unpkg.com/lucide@latest"></script>
|
| 364 |
+
<script>
|
| 365 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 366 |
+
// Initialize Lucide icons
|
| 367 |
+
lucide.createIcons();
|
| 368 |
+
|
| 369 |
+
// Sidebar toggle for mobile
|
| 370 |
+
const sidebar = document.querySelector('.sidebar');
|
| 371 |
+
const overlay = document.querySelector('.sidebar-overlay');
|
| 372 |
+
const sidebarToggle = document.getElementById('sidebarToggle');
|
| 373 |
+
|
| 374 |
+
const toggleSidebar = () => {
|
| 375 |
+
sidebar.classList.toggle('open');
|
| 376 |
+
overlay.classList.toggle('opacity-0');
|
| 377 |
+
overlay.classList.toggle('pointer-events-none');
|
| 378 |
+
};
|
| 379 |
+
|
| 380 |
+
sidebarToggle?.addEventListener('click', toggleSidebar);
|
| 381 |
+
overlay?.addEventListener('click', toggleSidebar);
|
| 382 |
+
|
| 383 |
+
// Navigation active state
|
| 384 |
+
const navLinks = document.querySelectorAll('.nav-link');
|
| 385 |
+
navLinks.forEach(link => {
|
| 386 |
+
link.addEventListener('click', function(e) {
|
| 387 |
+
e.preventDefault();
|
| 388 |
+
|
| 389 |
+
// Remove active class from all links
|
| 390 |
+
navLinks.forEach(l => l.classList.remove('active', 'text-white'));
|
| 391 |
+
navLinks.forEach(l => l.classList.add('text-slate-400'));
|
| 392 |
+
|
| 393 |
+
// Add active class to clicked link
|
| 394 |
+
this.classList.add('active', 'text-white');
|
| 395 |
+
this.classList.remove('text-slate-400');
|
| 396 |
+
|
| 397 |
+
// Close sidebar on mobile
|
| 398 |
+
if (window.innerWidth < 768) {
|
| 399 |
+
toggleSidebar();
|
| 400 |
+
}
|
| 401 |
+
});
|
| 402 |
+
});
|
| 403 |
+
|
| 404 |
+
// Auto-refresh stats every 30 seconds
|
| 405 |
+
setInterval(() => {
|
| 406 |
+
// In a real application, you might want to implement AJAX calls here
|
| 407 |
+
// to refresh the statistics without reloading the page
|
| 408 |
+
console.log('Refreshing stats...');
|
| 409 |
+
}, 30000);
|
| 410 |
+
});
|
| 411 |
+
</script>
|
| 412 |
+
</body>
|
| 413 |
+
</html>
|
api.php
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
declare(strict_types=1);
|
| 3 |
+
|
| 4 |
+
require_once __DIR__ . '/src/Bootstrap.php';
|
| 5 |
+
\SoftEdge\Env::load(__DIR__);
|
| 6 |
+
\SoftEdge\Bootstrap::init();
|
| 7 |
+
|
| 8 |
+
use SoftEdge\Response;
|
| 9 |
+
use SoftEdge\Validation;
|
| 10 |
+
use SoftEdge\AuthService;
|
| 11 |
+
use SoftEdge\RateLimiter;
|
| 12 |
+
use SoftEdge\DB;
|
| 13 |
+
use PDO;
|
| 14 |
+
|
| 15 |
+
// Default JSON header
|
| 16 |
+
if (!headers_sent()) {
|
| 17 |
+
header('Content-Type: application/json; charset=utf-8');
|
| 18 |
+
header('X-Powered-By: SoftEdge');
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
// Handle OPTIONS (CORS preflight for development/SPA usage)
|
| 22 |
+
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
| 23 |
+
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
| 24 |
+
header('Access-Control-Allow-Headers: Content-Type, X-CSRF-Token, Authorization');
|
| 25 |
+
header('Access-Control-Max-Age: 86400');
|
| 26 |
+
http_response_code(204);
|
| 27 |
+
exit;
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
// Very limited CORS allowance if same-origin or configured
|
| 31 |
+
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
|
| 32 |
+
$host = $_SERVER['HTTP_HOST'] ?? '';
|
| 33 |
+
if ($origin && str_contains($origin, $host)) {
|
| 34 |
+
header('Access-Control-Allow-Origin: ' . $origin);
|
| 35 |
+
header('Vary: Origin');
|
| 36 |
+
header('Access-Control-Allow-Credentials: true');
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
function path(): string {
|
| 40 |
+
$uri = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
|
| 41 |
+
// Support both /api.php?r=... and /api/... styles
|
| 42 |
+
if (isset($_GET['r'])) {
|
| 43 |
+
$r = '/' . ltrim((string)$_GET['r'], '/');
|
| 44 |
+
return $r;
|
| 45 |
+
}
|
| 46 |
+
if (preg_match('#/api(?:\.php)?(.*)$#', $uri, $m)) {
|
| 47 |
+
return $m[1] ? (string)$m[1] : '/';
|
| 48 |
+
}
|
| 49 |
+
return $uri;
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
function json_body(): array {
|
| 53 |
+
$raw = file_get_contents('php://input');
|
| 54 |
+
$data = json_decode((string)$raw, true);
|
| 55 |
+
return is_array($data) ? $data : [];
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
| 59 |
+
$route = rtrim(path(), '/') ?: '/';
|
| 60 |
+
|
| 61 |
+
try {
|
| 62 |
+
switch (true) {
|
| 63 |
+
case $method === 'GET' && $route === '/health':
|
| 64 |
+
Response::json([
|
| 65 |
+
'ok' => true,
|
| 66 |
+
'time' => date('c'),
|
| 67 |
+
'app' => 'SoftEdge API',
|
| 68 |
+
'env' => \SoftEdge\Env::get('APP_ENV', 'production'),
|
| 69 |
+
]);
|
| 70 |
+
break;
|
| 71 |
+
|
| 72 |
+
case $method === 'POST' && $route === '/auth/login':
|
| 73 |
+
$body = json_body();
|
| 74 |
+
$csrf = (string)($body['csrf'] ?? ($_SERVER['HTTP_X_CSRF_TOKEN'] ?? ''));
|
| 75 |
+
if (!\SoftEdge\Csrf::validate($csrf)) {
|
| 76 |
+
Response::json(['ok' => false, 'error' => 'CSRF inválido'], 400);
|
| 77 |
+
break;
|
| 78 |
+
}
|
| 79 |
+
$email = trim((string)($body['email'] ?? ''));
|
| 80 |
+
$password = (string)($body['password'] ?? '');
|
| 81 |
+
if (!Validation::email($email)) {
|
| 82 |
+
Response::json(['ok' => false, 'error' => 'Email inválido'], 422);
|
| 83 |
+
break;
|
| 84 |
+
}
|
| 85 |
+
$res = AuthService::login($email, $password);
|
| 86 |
+
Response::json($res, (int)($res['status'] ?? 200));
|
| 87 |
+
break;
|
| 88 |
+
|
| 89 |
+
case $method === 'POST' && $route === '/auth/logout':
|
| 90 |
+
AuthService::logout();
|
| 91 |
+
Response::json(['ok' => true]);
|
| 92 |
+
break;
|
| 93 |
+
|
| 94 |
+
case $method === 'POST' && $route === '/contact':
|
| 95 |
+
$body = json_body();
|
| 96 |
+
$csrf = (string)($body['csrf'] ?? ($_SERVER['HTTP_X_CSRF_TOKEN'] ?? ''));
|
| 97 |
+
if (!\SoftEdge\Csrf::validate($csrf)) {
|
| 98 |
+
Response::json(['ok' => false, 'error' => 'CSRF inválido'], 400);
|
| 99 |
+
break;
|
| 100 |
+
}
|
| 101 |
+
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
|
| 102 |
+
if (!RateLimiter::allow('contact:' . $ip, \SoftEdge\Env::int('RATE_LIMIT_CONTACT', 3), 3600)) {
|
| 103 |
+
Response::json(['ok' => false, 'error' => 'Muitas solicitações. Tente mais tarde.'], 429);
|
| 104 |
+
break;
|
| 105 |
+
}
|
| 106 |
+
$name = trim((string)($body['name'] ?? ''));
|
| 107 |
+
$email = trim((string)($body['email'] ?? ''));
|
| 108 |
+
$message = trim((string)($body['message'] ?? ''));
|
| 109 |
+
$phone = trim((string)($body['phone'] ?? ''));
|
| 110 |
+
$company = trim((string)($body['company'] ?? ''));
|
| 111 |
+
$subject = trim((string)($body['subject'] ?? ''));
|
| 112 |
+
|
| 113 |
+
$errors = Validation::required(['name' => $name, 'email' => $email, 'message' => $message], ['name','email','message']);
|
| 114 |
+
if (!empty($errors) || !Validation::email($email)) {
|
| 115 |
+
$errors['email'] = $errors['email'] ?? (!Validation::email($email) ? 'Email inválido' : null);
|
| 116 |
+
Response::json(['ok' => false, 'errors' => array_filter($errors)], 422);
|
| 117 |
+
break;
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
$pdo = DB::pdo();
|
| 121 |
+
$stmt = $pdo->prepare('INSERT INTO contact_submissions (name, email, phone, company, subject, message, status) VALUES (:name,:email,:phone,:company,:subject,:message,\'new\')');
|
| 122 |
+
$stmt->execute([
|
| 123 |
+
':name' => $name,
|
| 124 |
+
':email' => $email,
|
| 125 |
+
':phone' => $phone ?: null,
|
| 126 |
+
':company' => $company ?: null,
|
| 127 |
+
':subject' => $subject ?: null,
|
| 128 |
+
':message' => $message,
|
| 129 |
+
]);
|
| 130 |
+
Response::json(['ok' => true, 'id' => (int)$pdo->lastInsertId()], 201);
|
| 131 |
+
break;
|
| 132 |
+
|
| 133 |
+
default:
|
| 134 |
+
Response::json(['ok' => false, 'error' => 'Rota não encontrada', 'route' => $route], 404);
|
| 135 |
+
break;
|
| 136 |
+
}
|
| 137 |
+
} catch (Throwable $e) {
|
| 138 |
+
Response::json([
|
| 139 |
+
'ok' => false,
|
| 140 |
+
'error' => 'Erro interno',
|
| 141 |
+
], 500);
|
| 142 |
+
}
|
app.py
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from flask import Flask, request, jsonify, render_template, send_from_directory, redirect, url_for, flash, session, Response
|
| 2 |
+
import os
|
| 3 |
+
import json
|
| 4 |
+
import subprocess
|
| 5 |
+
import sys
|
| 6 |
+
from datetime import datetime, timedelta
|
| 7 |
+
import sqlite3
|
| 8 |
+
from werkzeug.security import generate_password_hash, check_password_hash
|
| 9 |
+
import jwt
|
| 10 |
+
import secrets
|
| 11 |
+
import requests
|
| 12 |
+
|
| 13 |
+
app = Flask(__name__)
|
| 14 |
+
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', secrets.token_hex(32))
|
| 15 |
+
app.config['JWT_SECRET'] = os.environ.get('JWT_SECRET', secrets.token_hex(32))
|
| 16 |
+
|
| 17 |
+
# Database setup
|
| 18 |
+
def init_db():
|
| 19 |
+
conn = sqlite3.connect('softedge.db')
|
| 20 |
+
c = conn.cursor()
|
| 21 |
+
c.execute('''CREATE TABLE IF NOT EXISTS users
|
| 22 |
+
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
| 23 |
+
email TEXT UNIQUE NOT NULL,
|
| 24 |
+
password TEXT NOT NULL,
|
| 25 |
+
name TEXT,
|
| 26 |
+
role TEXT DEFAULT 'user',
|
| 27 |
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
|
| 28 |
+
c.execute('''CREATE TABLE IF NOT EXISTS contact_submissions
|
| 29 |
+
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
| 30 |
+
name TEXT NOT NULL,
|
| 31 |
+
email TEXT NOT NULL,
|
| 32 |
+
message TEXT NOT NULL,
|
| 33 |
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
|
| 34 |
+
c.execute('''CREATE TABLE IF NOT EXISTS projects
|
| 35 |
+
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
| 36 |
+
title TEXT NOT NULL,
|
| 37 |
+
description TEXT NOT NULL,
|
| 38 |
+
status TEXT DEFAULT 'active',
|
| 39 |
+
technologies TEXT,
|
| 40 |
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
|
| 41 |
+
conn.commit()
|
| 42 |
+
conn.close()
|
| 43 |
+
|
| 44 |
+
init_db()
|
| 45 |
+
|
| 46 |
+
# Helper functions
|
| 47 |
+
def get_db_connection():
|
| 48 |
+
conn = sqlite3.connect('softedge.db')
|
| 49 |
+
conn.row_factory = sqlite3.Row
|
| 50 |
+
return conn
|
| 51 |
+
|
| 52 |
+
def create_token(user_id):
|
| 53 |
+
payload = {
|
| 54 |
+
'user_id': user_id,
|
| 55 |
+
'exp': datetime.utcnow() + timedelta(hours=24)
|
| 56 |
+
}
|
| 57 |
+
return jwt.encode(payload, app.config['JWT_SECRET'], algorithm='HS256')
|
| 58 |
+
|
| 59 |
+
# PHP Integration
|
| 60 |
+
def call_php_script(script_name, method='GET', data=None):
|
| 61 |
+
"""Call PHP script and return response"""
|
| 62 |
+
try:
|
| 63 |
+
php_path = os.path.join(os.getcwd(), script_name)
|
| 64 |
+
if not os.path.exists(php_path):
|
| 65 |
+
return None
|
| 66 |
+
|
| 67 |
+
# For simple GET requests, we can execute PHP directly
|
| 68 |
+
if method == 'GET':
|
| 69 |
+
result = subprocess.run(['php', php_path],
|
| 70 |
+
capture_output=True, text=True, timeout=30)
|
| 71 |
+
if result.returncode == 0:
|
| 72 |
+
return result.stdout
|
| 73 |
+
return None
|
| 74 |
+
except Exception as e:
|
| 75 |
+
print(f"PHP execution error: {e}")
|
| 76 |
+
return None
|
| 77 |
+
|
| 78 |
+
# Routes
|
| 79 |
+
@app.route('/')
|
| 80 |
+
def home():
|
| 81 |
+
# Get dynamic stats
|
| 82 |
+
stats = {'projects': 0, 'contacts': 0, 'satisfaction': 4.9}
|
| 83 |
+
try:
|
| 84 |
+
conn = get_db_connection()
|
| 85 |
+
stats['projects'] = conn.execute('SELECT COUNT(*) as count FROM projects').fetchone()['count']
|
| 86 |
+
stats['contacts'] = conn.execute('SELECT COUNT(*) as count FROM contact_submissions').fetchone()['count']
|
| 87 |
+
conn.close()
|
| 88 |
+
except Exception as e:
|
| 89 |
+
print(f"Stats error: {e}")
|
| 90 |
+
|
| 91 |
+
return render_template('index.html', stats=stats)
|
| 92 |
+
|
| 93 |
+
@app.route('/sobre')
|
| 94 |
+
def sobre():
|
| 95 |
+
return render_template('sobre.html')
|
| 96 |
+
|
| 97 |
+
@app.route('/servicos')
|
| 98 |
+
def servicos():
|
| 99 |
+
return render_template('servicos.html')
|
| 100 |
+
|
| 101 |
+
@app.route('/projetos')
|
| 102 |
+
def projetos():
|
| 103 |
+
# Get projects from database
|
| 104 |
+
projects = []
|
| 105 |
+
try:
|
| 106 |
+
conn = get_db_connection()
|
| 107 |
+
projects = conn.execute('SELECT * FROM projects ORDER BY created_at DESC').fetchall()
|
| 108 |
+
conn.close()
|
| 109 |
+
projects = [dict(project) for project in projects]
|
| 110 |
+
except Exception as e:
|
| 111 |
+
print(f"Projects error: {e}")
|
| 112 |
+
|
| 113 |
+
return render_template('projetos.html', projects=projects)
|
| 114 |
+
|
| 115 |
+
@app.route('/contato')
|
| 116 |
+
def contato():
|
| 117 |
+
return render_template('contato.html')
|
| 118 |
+
|
| 119 |
+
@app.route('/login')
|
| 120 |
+
def login():
|
| 121 |
+
return render_template('login.html')
|
| 122 |
+
|
| 123 |
+
@app.route('/register')
|
| 124 |
+
def register():
|
| 125 |
+
return render_template('register.html')
|
| 126 |
+
|
| 127 |
+
@app.route('/admin')
|
| 128 |
+
def admin():
|
| 129 |
+
# Check authentication
|
| 130 |
+
if 'user_id' not in session:
|
| 131 |
+
return redirect(url_for('login'))
|
| 132 |
+
|
| 133 |
+
# Get admin stats
|
| 134 |
+
stats = {'total_users': 0, 'total_contacts': 0, 'recent_users': [], 'recent_contacts': []}
|
| 135 |
+
try:
|
| 136 |
+
conn = get_db_connection()
|
| 137 |
+
stats['total_users'] = conn.execute('SELECT COUNT(*) as count FROM users').fetchone()['count']
|
| 138 |
+
stats['total_contacts'] = conn.execute('SELECT COUNT(*) as count FROM contact_submissions').fetchone()['count']
|
| 139 |
+
|
| 140 |
+
# Recent users
|
| 141 |
+
stats['recent_users'] = conn.execute(
|
| 142 |
+
'SELECT name, email, created_at FROM users ORDER BY created_at DESC LIMIT 5'
|
| 143 |
+
).fetchall()
|
| 144 |
+
|
| 145 |
+
# Recent contacts
|
| 146 |
+
stats['recent_contacts'] = conn.execute(
|
| 147 |
+
'SELECT name, email, message, created_at FROM contact_submissions ORDER BY created_at DESC LIMIT 5'
|
| 148 |
+
).fetchall()
|
| 149 |
+
|
| 150 |
+
conn.close()
|
| 151 |
+
stats['recent_users'] = [dict(user) for user in stats['recent_users']]
|
| 152 |
+
stats['recent_contacts'] = [dict(contact) for contact in stats['recent_contacts']]
|
| 153 |
+
except Exception as e:
|
| 154 |
+
print(f"Admin stats error: {e}")
|
| 155 |
+
|
| 156 |
+
return render_template('admin.html', stats=stats)
|
| 157 |
+
|
| 158 |
+
# API Routes
|
| 159 |
+
@app.route('/api/health')
|
| 160 |
+
def health():
|
| 161 |
+
return jsonify({
|
| 162 |
+
'status': 'ok',
|
| 163 |
+
'timestamp': datetime.now().isoformat(),
|
| 164 |
+
'service': 'SoftEdge Hybrid API',
|
| 165 |
+
'version': '3.0.0',
|
| 166 |
+
'technologies': ['Flask', 'PHP', 'Node.js', 'MySQL']
|
| 167 |
+
})
|
| 168 |
+
|
| 169 |
+
@app.route('/api/stats')
|
| 170 |
+
def stats():
|
| 171 |
+
try:
|
| 172 |
+
conn = get_db_connection()
|
| 173 |
+
projects_count = conn.execute('SELECT COUNT(*) as count FROM projects').fetchone()['count']
|
| 174 |
+
contact_count = conn.execute('SELECT COUNT(*) as count FROM contact_submissions').fetchone()['count']
|
| 175 |
+
conn.close()
|
| 176 |
+
|
| 177 |
+
return jsonify({
|
| 178 |
+
'projects': projects_count,
|
| 179 |
+
'contacts': contact_count,
|
| 180 |
+
'satisfaction': 4.9,
|
| 181 |
+
'uptime': '99.9%'
|
| 182 |
+
})
|
| 183 |
+
except Exception as e:
|
| 184 |
+
return jsonify({'error': 'Database error'}), 500
|
| 185 |
+
|
| 186 |
+
@app.route('/api/contact', methods=['POST'])
|
| 187 |
+
def contact():
|
| 188 |
+
data = request.get_json()
|
| 189 |
+
|
| 190 |
+
if not data or not all(k in data for k in ['name', 'email', 'message']):
|
| 191 |
+
return jsonify({'error': 'Missing required fields'}), 400
|
| 192 |
+
|
| 193 |
+
try:
|
| 194 |
+
conn = get_db_connection()
|
| 195 |
+
conn.execute('INSERT INTO contact_submissions (name, email, message) VALUES (?, ?, ?)',
|
| 196 |
+
(data['name'], data['email'], data['message']))
|
| 197 |
+
conn.commit()
|
| 198 |
+
conn.close()
|
| 199 |
+
|
| 200 |
+
return jsonify({'message': 'Message sent successfully', 'status': 'success'}), 200
|
| 201 |
+
except Exception as e:
|
| 202 |
+
return jsonify({'error': 'Database error'}), 500
|
| 203 |
+
|
| 204 |
+
@app.route('/api/auth/login', methods=['POST'])
|
| 205 |
+
def api_login():
|
| 206 |
+
data = request.get_json()
|
| 207 |
+
|
| 208 |
+
if not data or not all(k in data for k in ['email', 'password']):
|
| 209 |
+
return jsonify({'error': 'Missing credentials'}), 400
|
| 210 |
+
|
| 211 |
+
try:
|
| 212 |
+
conn = get_db_connection()
|
| 213 |
+
user = conn.execute('SELECT * FROM users WHERE email = ?', (data['email'],)).fetchone()
|
| 214 |
+
conn.close()
|
| 215 |
+
|
| 216 |
+
if user and check_password_hash(user['password'], data['password']):
|
| 217 |
+
session['user_id'] = user['id']
|
| 218 |
+
session['user_email'] = user['email']
|
| 219 |
+
session['user_name'] = user['name']
|
| 220 |
+
session['user_role'] = user['role']
|
| 221 |
+
token = create_token(user['id'])
|
| 222 |
+
|
| 223 |
+
return jsonify({
|
| 224 |
+
'message': 'Login successful',
|
| 225 |
+
'token': token,
|
| 226 |
+
'user': {
|
| 227 |
+
'id': user['id'],
|
| 228 |
+
'email': user['email'],
|
| 229 |
+
'name': user['name'],
|
| 230 |
+
'role': user['role']
|
| 231 |
+
}
|
| 232 |
+
}), 200
|
| 233 |
+
else:
|
| 234 |
+
return jsonify({'error': 'Invalid credentials'}), 401
|
| 235 |
+
except Exception as e:
|
| 236 |
+
return jsonify({'error': 'Database error'}), 500
|
| 237 |
+
|
| 238 |
+
@app.route('/api/auth/register', methods=['POST'])
|
| 239 |
+
def api_register():
|
| 240 |
+
data = request.get_json()
|
| 241 |
+
|
| 242 |
+
if not data or not all(k in data for k in ['email', 'password', 'name']):
|
| 243 |
+
return jsonify({'error': 'Missing required fields'}), 400
|
| 244 |
+
|
| 245 |
+
try:
|
| 246 |
+
hashed_password = generate_password_hash(data['password'])
|
| 247 |
+
|
| 248 |
+
conn = get_db_connection()
|
| 249 |
+
conn.execute('INSERT INTO users (email, password, name) VALUES (?, ?, ?)',
|
| 250 |
+
(data['email'], hashed_password, data['name']))
|
| 251 |
+
conn.commit()
|
| 252 |
+
user_id = conn.execute('SELECT last_insert_rowid()').fetchone()[0]
|
| 253 |
+
conn.close()
|
| 254 |
+
|
| 255 |
+
token = create_token(user_id)
|
| 256 |
+
return jsonify({
|
| 257 |
+
'message': 'Registration successful',
|
| 258 |
+
'token': token,
|
| 259 |
+
'user': {
|
| 260 |
+
'id': user_id,
|
| 261 |
+
'email': data['email'],
|
| 262 |
+
'name': data['name']
|
| 263 |
+
}
|
| 264 |
+
}), 201
|
| 265 |
+
except sqlite3.IntegrityError:
|
| 266 |
+
return jsonify({'error': 'Email already exists'}), 409
|
| 267 |
+
except Exception as e:
|
| 268 |
+
return jsonify({'error': 'Database error'}), 500
|
| 269 |
+
|
| 270 |
+
@app.route('/api/auth/logout')
|
| 271 |
+
def logout():
|
| 272 |
+
session.clear()
|
| 273 |
+
return jsonify({'message': 'Logged out successfully'})
|
| 274 |
+
|
| 275 |
+
# PHP Integration Routes
|
| 276 |
+
@app.route('/php/<path:script>')
|
| 277 |
+
def php_route(script):
|
| 278 |
+
"""Route to execute PHP scripts"""
|
| 279 |
+
result = call_php_script(f'{script}.php')
|
| 280 |
+
if result:
|
| 281 |
+
return Response(result, mimetype='text/html')
|
| 282 |
+
return jsonify({'error': 'PHP script not found'}), 404
|
| 283 |
+
|
| 284 |
+
# Static files
|
| 285 |
+
@app.route('/assets/<path:filename>')
|
| 286 |
+
def assets(filename):
|
| 287 |
+
return send_from_directory('assets', filename)
|
| 288 |
+
|
| 289 |
+
@app.route('/css/<path:filename>')
|
| 290 |
+
def css_files(filename):
|
| 291 |
+
return send_from_directory('css', filename)
|
| 292 |
+
|
| 293 |
+
@app.route('/js/<path:filename>')
|
| 294 |
+
def js_files(filename):
|
| 295 |
+
return send_from_directory('js', filename)
|
| 296 |
+
|
| 297 |
+
# React integration
|
| 298 |
+
@app.route('/react-app')
|
| 299 |
+
def react_app():
|
| 300 |
+
return render_template('react-app.html')
|
| 301 |
+
|
| 302 |
+
if __name__ == '__main__':
|
| 303 |
+
# Seed initial data
|
| 304 |
+
conn = get_db_connection()
|
| 305 |
+
if not conn.execute('SELECT COUNT(*) FROM projects').fetchone()[0]:
|
| 306 |
+
projects = [
|
| 307 |
+
('AKIRA IA', 'Assistente virtual angolano com processamento de linguagem natural', 'Concluído', 'Python, TensorFlow, FastAPI'),
|
| 308 |
+
('ERP Gestão Total', 'Sistema completo de gestão empresarial', 'Concluído', 'Laravel, Vue.js, MySQL'),
|
| 309 |
+
('E-commerce ShopFast', 'Plataforma de vendas online de alta performance', 'Concluído', 'Next.js, Stripe, Prisma'),
|
| 310 |
+
('Sistema de Gestão Escolar', 'Plataforma completa para gestão educacional', 'Em desenvolvimento', 'React, Node.js, PostgreSQL'),
|
| 311 |
+
('App Mobile Delivery', 'Aplicativo de delivery com geolocalização', 'Em desenvolvimento', 'Flutter, Firebase, Google Maps')
|
| 312 |
+
]
|
| 313 |
+
conn.executemany('INSERT INTO projects (title, description, status, technologies) VALUES (?, ?, ?, ?)', projects)
|
| 314 |
+
conn.commit()
|
| 315 |
+
|
| 316 |
+
# Create admin user
|
| 317 |
+
admin_email = os.environ.get('ADMIN_EMAIL', 'admin@softedge.com')
|
| 318 |
+
admin_password = os.environ.get('ADMIN_PASSWORD', 'Admin@123456')
|
| 319 |
+
admin_name = os.environ.get('ADMIN_NAME', 'Isaac Quarenta')
|
| 320 |
+
|
| 321 |
+
if not conn.execute('SELECT id FROM users WHERE email = ?', (admin_email,)).fetchone():
|
| 322 |
+
hashed_password = generate_password_hash(admin_password)
|
| 323 |
+
conn.execute('INSERT INTO users (email, password, name, role) VALUES (?, ?, ?, ?)',
|
| 324 |
+
(admin_email, hashed_password, admin_name, 'super_admin'))
|
| 325 |
+
conn.commit()
|
| 326 |
+
|
| 327 |
+
conn.close()
|
| 328 |
+
|
| 329 |
+
print("🚀 SoftEdge Corporation - Hybrid Architecture Started!")
|
| 330 |
+
print("Technologies: Flask (Python) + PHP + Node.js + MySQL")
|
| 331 |
+
print("Server running on http://localhost:7860")
|
| 332 |
+
|
| 333 |
+
app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 7860)))
|
composer-schema.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
| 3 |
+
"type": "object",
|
| 4 |
+
"properties": {
|
| 5 |
+
"name": { "type": "string" },
|
| 6 |
+
"description": { "type": "string" },
|
| 7 |
+
"type": { "type": "string" },
|
| 8 |
+
"license": { "type": "string" },
|
| 9 |
+
"authors": {
|
| 10 |
+
"type": "array",
|
| 11 |
+
"items": {
|
| 12 |
+
"type": "object",
|
| 13 |
+
"properties": {
|
| 14 |
+
"name": { "type": "string" },
|
| 15 |
+
"email": { "type": "string" }
|
| 16 |
+
}
|
| 17 |
+
}
|
| 18 |
+
},
|
| 19 |
+
"require": { "type": "object" },
|
| 20 |
+
"require-dev": { "type": "object" },
|
| 21 |
+
"autoload": { "type": "object" },
|
| 22 |
+
"config": { "type": "object" },
|
| 23 |
+
"minimum-stability": { "type": "string" }
|
| 24 |
+
}
|
| 25 |
+
}
|
composer.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"$schema": "./composer-schema.json",
|
| 3 |
+
"name": "softedge/softedge-corporation",
|
| 4 |
+
"description": "Professional website for SoftEdge Corporation - Modern web solutions with user management",
|
| 5 |
+
"type": "project",
|
| 6 |
+
"license": "MIT",
|
| 7 |
+
"authors": [
|
| 8 |
+
{
|
| 9 |
+
"name": "SoftEdge Corporation",
|
| 10 |
+
"email": "softedgecorporation@gmail.com"
|
| 11 |
+
}
|
| 12 |
+
],
|
| 13 |
+
"require": {
|
| 14 |
+
"php": ">=8.1",
|
| 15 |
+
"phpmailer/phpmailer": "^6.8",
|
| 16 |
+
"monolog/monolog": "^3.0",
|
| 17 |
+
"vlucas/phpdotenv": "^5.5",
|
| 18 |
+
"firebase/php-jwt": "^6.4"
|
| 19 |
+
},
|
| 20 |
+
"require-dev": {
|
| 21 |
+
"phpunit/phpunit": "^10.0"
|
| 22 |
+
},
|
| 23 |
+
"autoload": {
|
| 24 |
+
"psr-4": {
|
| 25 |
+
"SoftEdge\\": "src/"
|
| 26 |
+
}
|
| 27 |
+
},
|
| 28 |
+
"config": {
|
| 29 |
+
"optimize-autoloader": true,
|
| 30 |
+
"prefer-stable": true,
|
| 31 |
+
"sort-packages": true
|
| 32 |
+
},
|
| 33 |
+
"minimum-stability": "stable"
|
| 34 |
+
}
|
contato.php
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
require_once __DIR__ . '/src/Bootstrap.php';
|
| 3 |
+
\SoftEdge\Env::load(__DIR__);
|
| 4 |
+
\SoftEdge\Bootstrap::init();
|
| 5 |
+
include 'components/header.php';
|
| 6 |
+
?>
|
| 7 |
+
|
| 8 |
+
<!-- HERO SECTION -->
|
| 9 |
+
<section class="relative min-h-screen flex items-center justify-center overflow-hidden">
|
| 10 |
+
<!-- Background -->
|
| 11 |
+
<div class="absolute inset-0 -z-10">
|
| 12 |
+
<div class="absolute inset-0 bg-linear-to-br from-slate-950 via-slate-900 to-slate-950"></div>
|
| 13 |
+
<div class="absolute inset-0 opacity-30">
|
| 14 |
+
<div class="absolute top-1/4 left-1/4 w-96 h-96 bg-cyan-500/20 rounded-full blur-3xl animate-pulse"></div>
|
| 15 |
+
<div class="absolute bottom-1/4 right-1/4 w-96 h-96 bg-blue-500/20 rounded-full blur-3xl animate-pulse" style="animation-delay: 2s;"></div>
|
| 16 |
+
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[600px] h-[600px] bg-purple-500/10 rounded-full blur-3xl"></div>
|
| 17 |
+
</div>
|
| 18 |
+
</div>
|
| 19 |
+
|
| 20 |
+
<!-- Content -->
|
| 21 |
+
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20">
|
| 22 |
+
<div class="text-center space-y-12">
|
| 23 |
+
|
| 24 |
+
<!-- Badge -->
|
| 25 |
+
<div class="inline-block px-4 py-2 bg-cyan-500/10 rounded-full border border-cyan-500/20 backdrop-blur-sm">
|
| 26 |
+
<span class="text-cyan-400 text-xs sm:text-sm font-semibold uppercase tracking-wider">
|
| 27 |
+
💬 Entre em Contato
|
| 28 |
+
</span>
|
| 29 |
+
</div>
|
| 30 |
+
|
| 31 |
+
<!-- Main Heading -->
|
| 32 |
+
<div class="space-y-6">
|
| 33 |
+
<h1 class="text-4xl sm:text-5xl md:text-6xl lg:text-7xl xl:text-8xl font-bold leading-tight">
|
| 34 |
+
<span class="block text-white mb-2">Vamos conversar</span>
|
| 35 |
+
<span class="block bg-linear-to-r from-cyan-400 via-blue-500 to-purple-500 bg-clip-text text-transparent">
|
| 36 |
+
sobre seu projeto?
|
| 37 |
+
</span>
|
| 38 |
+
</h1>
|
| 39 |
+
|
| 40 |
+
<p class="text-base sm:text-lg md:text-xl text-gray-300 max-w-2xl mx-auto leading-relaxed">
|
| 41 |
+
Estamos prontos para transformar suas ideias em realidade.<br class="hidden sm:block">
|
| 42 |
+
Escolha o melhor canal para falar conosco.
|
| 43 |
+
</p>
|
| 44 |
+
</div>
|
| 45 |
+
|
| 46 |
+
<!-- Contact Cards Grid -->
|
| 47 |
+
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-8 mt-16 max-w-5xl mx-auto">
|
| 48 |
+
|
| 49 |
+
<!-- Card 1: Email -->
|
| 50 |
+
<a href="mailto:softedgecorporation@gmail.com"
|
| 51 |
+
class="group relative">
|
| 52 |
+
<div class="absolute inset-0 bg-linear-to-br from-cyan-500/20 to-blue-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
| 53 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/10 hover:border-cyan-500/50 rounded-2xl p-8 transition-all duration-300 group-hover:scale-105 h-full flex flex-col items-center text-center">
|
| 54 |
+
<div class="w-16 h-16 bg-cyan-500/20 rounded-2xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform">
|
| 55 |
+
<i data-lucide="mail" class="w-8 h-8 text-cyan-400"></i>
|
| 56 |
+
</div>
|
| 57 |
+
<h3 class="text-xl font-bold text-white mb-3">Email Direto</h3>
|
| 58 |
+
<p class="text-gray-400 text-sm mb-4 grow">
|
| 59 |
+
Envie sua mensagem e receba resposta em até 24 horas
|
| 60 |
+
</p>
|
| 61 |
+
<div class="text-cyan-400 font-medium text-sm break-all">
|
| 62 |
+
softedgecorporation@gmail.com
|
| 63 |
+
</div>
|
| 64 |
+
<div class="mt-4 inline-flex items-center gap-2 text-cyan-400 text-sm font-medium">
|
| 65 |
+
<span>Enviar email</span>
|
| 66 |
+
<i data-lucide="arrow-right" class="w-4 h-4 group-hover:translate-x-1 transition-transform"></i>
|
| 67 |
+
</div>
|
| 68 |
+
</div>
|
| 69 |
+
</a>
|
| 70 |
+
|
| 71 |
+
<!-- Card 2: WhatsApp -->
|
| 72 |
+
<a href="https://whatsapp.com/channel/0029VawQLpGHltY2Y87fR83m"
|
| 73 |
+
target="_blank"
|
| 74 |
+
rel="noopener noreferrer"
|
| 75 |
+
class="group relative">
|
| 76 |
+
<div class="absolute inset-0 bg-linear-to-br from-green-500/20 to-emerald-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
| 77 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/10 hover:border-green-500/50 rounded-2xl p-8 transition-all duration-300 group-hover:scale-105 h-full flex flex-col items-center text-center">
|
| 78 |
+
<div class="w-16 h-16 bg-green-500/20 rounded-2xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform">
|
| 79 |
+
<i data-lucide="message-circle" class="w-8 h-8 text-green-400"></i>
|
| 80 |
+
</div>
|
| 81 |
+
<h3 class="text-xl font-bold text-white mb-3">Canal WhatsApp</h3>
|
| 82 |
+
<p class="text-gray-400 text-sm mb-4 grow">
|
| 83 |
+
Junte-se ao nosso canal e receba novidades em primeira mão
|
| 84 |
+
</p>
|
| 85 |
+
<div class="inline-flex items-center gap-2 px-4 py-2 bg-green-500/20 border border-green-500/30 rounded-lg">
|
| 86 |
+
<i data-lucide="users" class="w-4 h-4 text-green-400"></i>
|
| 87 |
+
<span class="text-green-400 font-medium text-sm">Canal Oficial</span>
|
| 88 |
+
</div>
|
| 89 |
+
<div class="mt-4 inline-flex items-center gap-2 text-green-400 text-sm font-medium">
|
| 90 |
+
<span>Entrar agora</span>
|
| 91 |
+
<i data-lucide="arrow-right" class="w-4 h-4 group-hover:translate-x-1 transition-transform"></i>
|
| 92 |
+
</div>
|
| 93 |
+
</div>
|
| 94 |
+
</a>
|
| 95 |
+
|
| 96 |
+
<!-- Card 3: Twitter/X -->
|
| 97 |
+
<a href="https://x.com/softedge40"
|
| 98 |
+
target="_blank"
|
| 99 |
+
rel="noopener noreferrer"
|
| 100 |
+
class="group relative sm:col-span-2 lg:col-span-1">
|
| 101 |
+
<div class="absolute inset-0 bg-linear-to-br from-blue-500/20 to-purple-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
| 102 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/10 hover:border-blue-500/50 rounded-2xl p-8 transition-all duration-300 group-hover:scale-105 h-full flex flex-col items-center text-center">
|
| 103 |
+
<div class="w-16 h-16 bg-blue-500/20 rounded-2xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform">
|
| 104 |
+
<i data-lucide="twitter" class="w-8 h-8 text-blue-400"></i>
|
| 105 |
+
</div>
|
| 106 |
+
<h3 class="text-xl font-bold text-white mb-3">Twitter / X</h3>
|
| 107 |
+
<p class="text-gray-400 text-sm mb-4 grow">
|
| 108 |
+
Siga-nos para dicas, projetos e conteúdo sobre tecnologia
|
| 109 |
+
</p>
|
| 110 |
+
<div class="text-blue-400 font-medium text-sm">
|
| 111 |
+
@softedge40
|
| 112 |
+
</div>
|
| 113 |
+
<div class="mt-4 inline-flex items-center gap-2 text-blue-400 text-sm font-medium">
|
| 114 |
+
<span>Seguir agora</span>
|
| 115 |
+
<i data-lucide="arrow-right" class="w-4 h-4 group-hover:translate-x-1 transition-transform"></i>
|
| 116 |
+
</div>
|
| 117 |
+
</div>
|
| 118 |
+
</a>
|
| 119 |
+
</div>
|
| 120 |
+
|
| 121 |
+
<!-- Divider -->
|
| 122 |
+
<div class="relative py-12">
|
| 123 |
+
<div class="absolute inset-0 flex items-center">
|
| 124 |
+
<div class="w-full border-t border-white/10"></div>
|
| 125 |
+
</div>
|
| 126 |
+
<div class="relative flex justify-center">
|
| 127 |
+
<span class="px-6 bg-slate-950 text-gray-400 text-sm uppercase tracking-wider">Ou</span>
|
| 128 |
+
</div>
|
| 129 |
+
</div>
|
| 130 |
+
|
| 131 |
+
<!-- CTA Section -->
|
| 132 |
+
<div class="max-w-3xl mx-auto">
|
| 133 |
+
<div class="relative">
|
| 134 |
+
<div class="absolute inset-0 bg-linear-to-r from-cyan-500/10 via-blue-500/10 to-purple-500/10 rounded-3xl blur-2xl"></div>
|
| 135 |
+
|
| 136 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/10 rounded-3xl p-8 lg:p-12">
|
| 137 |
+
<div class="space-y-6">
|
| 138 |
+
<div class="w-14 h-14 bg-linear-to-br from-cyan-500 to-blue-600 rounded-xl flex items-center justify-center mx-auto">
|
| 139 |
+
<i data-lucide="send" class="w-7 h-7 text-white"></i>
|
| 140 |
+
</div>
|
| 141 |
+
|
| 142 |
+
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-white">
|
| 143 |
+
Prefere um formulário completo?
|
| 144 |
+
</h2>
|
| 145 |
+
|
| 146 |
+
<p class="text-gray-300 text-base sm:text-lg">
|
| 147 |
+
Preencha nosso formulário de contato com todos os detalhes do seu projeto e receba uma resposta personalizada em até 24 horas.
|
| 148 |
+
</p>
|
| 149 |
+
|
| 150 |
+
<a href="feedback.php"
|
| 151 |
+
class="inline-flex items-center justify-center gap-3 bg-slate-700 hover:bg-slate-600 border border-slate-600 text-slate-200 font-medium text-lg px-8 py-4 rounded-lg transition-all duration-300">
|
| 152 |
+
Preencher Formulário
|
| 153 |
+
<i data-lucide="arrow-right" class="w-5 h-5"></i>
|
| 154 |
+
</a>
|
| 155 |
+
</div>
|
| 156 |
+
</div>
|
| 157 |
+
</div>
|
| 158 |
+
</div>
|
| 159 |
+
|
| 160 |
+
<!-- Info Section -->
|
| 161 |
+
<div class="grid sm:grid-cols-3 gap-6 lg:gap-8 mt-16 max-w-4xl mx-auto">
|
| 162 |
+
<!-- Info 1 -->
|
| 163 |
+
<div class="text-center">
|
| 164 |
+
<div class="w-12 h-12 bg-cyan-500/10 rounded-xl flex items-center justify-center mx-auto mb-4">
|
| 165 |
+
<i data-lucide="clock" class="w-6 h-6 text-cyan-400"></i>
|
| 166 |
+
</div>
|
| 167 |
+
<h3 class="text-white font-semibold mb-2">Resposta Rápida</h3>
|
| 168 |
+
<p class="text-gray-400 text-sm">Até 24 horas úteis</p>
|
| 169 |
+
</div>
|
| 170 |
+
|
| 171 |
+
<!-- Info 2 -->
|
| 172 |
+
<div class="text-center">
|
| 173 |
+
<div class="w-12 h-12 bg-blue-500/10 rounded-xl flex items-center justify-center mx-auto mb-4">
|
| 174 |
+
<i data-lucide="shield-check" class="w-6 h-6 text-blue-400"></i>
|
| 175 |
+
</div>
|
| 176 |
+
<h3 class="text-white font-semibold mb-2">100% Seguro</h3>
|
| 177 |
+
<p class="text-gray-400 text-sm">Seus dados protegidos</p>
|
| 178 |
+
</div>
|
| 179 |
+
|
| 180 |
+
<!-- Info 3 -->
|
| 181 |
+
<div class="text-center">
|
| 182 |
+
<div class="w-12 h-12 bg-purple-500/10 rounded-xl flex items-center justify-center mx-auto mb-4">
|
| 183 |
+
<i data-lucide="headphones" class="w-6 h-6 text-purple-400"></i>
|
| 184 |
+
</div>
|
| 185 |
+
<h3 class="text-white font-semibold mb-2">Suporte 24/7</h3>
|
| 186 |
+
<p class="text-gray-400 text-sm">Sempre disponível</p>
|
| 187 |
+
</div>
|
| 188 |
+
</div>
|
| 189 |
+
|
| 190 |
+
<!-- Location -->
|
| 191 |
+
<div class="pt-12">
|
| 192 |
+
<div class="inline-flex items-center gap-2 text-gray-400">
|
| 193 |
+
<i data-lucide="map-pin" class="w-5 h-5"></i>
|
| 194 |
+
<span>Localizado em Luanda, Angola 🇦🇴</span>
|
| 195 |
+
</div>
|
| 196 |
+
</div>
|
| 197 |
+
|
| 198 |
+
</div>
|
| 199 |
+
</div>
|
| 200 |
+
</section>
|
| 201 |
+
|
| 202 |
+
<?php include 'components/footer.php'; ?>
|
| 203 |
+
|
| 204 |
+
<!-- SCRIPTS -->
|
| 205 |
+
<script src="https://unpkg.com/lucide@latest"></script>
|
| 206 |
+
<script>
|
| 207 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 208 |
+
// Initialize Lucide icons
|
| 209 |
+
lucide.createIcons();
|
| 210 |
+
|
| 211 |
+
// Fade in animations on scroll
|
| 212 |
+
const observerOptions = {
|
| 213 |
+
threshold: 0.1,
|
| 214 |
+
rootMargin: '0px 0px -50px 0px'
|
| 215 |
+
};
|
| 216 |
+
|
| 217 |
+
const observer = new IntersectionObserver((entries) => {
|
| 218 |
+
entries.forEach(entry => {
|
| 219 |
+
if (entry.isIntersecting) {
|
| 220 |
+
entry.target.style.opacity = '1';
|
| 221 |
+
entry.target.style.transform = 'translateY(0)';
|
| 222 |
+
}
|
| 223 |
+
});
|
| 224 |
+
}, observerOptions);
|
| 225 |
+
|
| 226 |
+
// Observe all cards and sections
|
| 227 |
+
document.querySelectorAll('.group, section > div > div').forEach((el, index) => {
|
| 228 |
+
el.style.opacity = '0';
|
| 229 |
+
el.style.transform = 'translateY(20px)';
|
| 230 |
+
el.style.transition = `opacity 0.6s ease ${index * 0.1}s, transform 0.6s ease ${index * 0.1}s`;
|
| 231 |
+
observer.observe(el);
|
| 232 |
+
});
|
| 233 |
+
|
| 234 |
+
// Add click tracking (optional)
|
| 235 |
+
document.querySelectorAll('a[href^="mailto:"], a[href*="whatsapp"], a[href*="twitter"]').forEach(link => {
|
| 236 |
+
link.addEventListener('click', function(e) {
|
| 237 |
+
const channel = this.href.includes('mailto') ? 'Email' :
|
| 238 |
+
this.href.includes('whatsapp') ? 'WhatsApp' : 'Twitter';
|
| 239 |
+
console.log(`Usuário clicou em: ${channel}`);
|
| 240 |
+
});
|
| 241 |
+
});
|
| 242 |
+
});
|
| 243 |
+
</script>
|
| 244 |
+
|
| 245 |
+
<style>
|
| 246 |
+
/* Gradient animation */
|
| 247 |
+
@keyframes gradient-shift {
|
| 248 |
+
0%, 100% {
|
| 249 |
+
background-position: 0% 50%;
|
| 250 |
+
}
|
| 251 |
+
50% {
|
| 252 |
+
background-position: 100% 50%;
|
| 253 |
+
}
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
.bg-linear-to-r,
|
| 257 |
+
.bg-linear-to-br {
|
| 258 |
+
background-size: 200% 200%;
|
| 259 |
+
animation: gradient-shift 8s ease infinite;
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
/* Pulse animation for background orbs */
|
| 263 |
+
@keyframes pulse-slow {
|
| 264 |
+
0%, 100% {
|
| 265 |
+
opacity: 0.3;
|
| 266 |
+
transform: scale(1);
|
| 267 |
+
}
|
| 268 |
+
50% {
|
| 269 |
+
opacity: 0.5;
|
| 270 |
+
transform: scale(1.1);
|
| 271 |
+
}
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
.animate-pulse {
|
| 275 |
+
animation: pulse-slow 8s ease-in-out infinite;
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
/* Smooth hover transitions */
|
| 279 |
+
.group {
|
| 280 |
+
will-change: transform;
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
/* Custom scrollbar */
|
| 284 |
+
::-webkit-scrollbar {
|
| 285 |
+
width: 10px;
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
::-webkit-scrollbar-track {
|
| 289 |
+
background: #0f172a;
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
::-webkit-scrollbar-thumb {
|
| 293 |
+
background: linear-gradient(180deg, #06b6d4, #3b82f6);
|
| 294 |
+
border-radius: 5px;
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
::-webkit-scrollbar-thumb:hover {
|
| 298 |
+
background: linear-gradient(180deg, #0891b2, #2563eb);
|
| 299 |
+
}
|
| 300 |
+
</style>
|
database.sql
ADDED
|
Binary file (44.4 kB). View file
|
|
|
dev.sh
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
+
# SoftEdge Corporation - Development Script
|
| 4 |
+
# This script sets up the development environment for React integration
|
| 5 |
+
|
| 6 |
+
echo "🚀 Starting SoftEdge Corporation Development Environment"
|
| 7 |
+
echo "======================================================"
|
| 8 |
+
|
| 9 |
+
# Check if Node.js is installed
|
| 10 |
+
if ! command -v node &> /dev/null; then
|
| 11 |
+
echo "❌ Node.js is not installed. Please install Node.js first."
|
| 12 |
+
exit 1
|
| 13 |
+
fi
|
| 14 |
+
|
| 15 |
+
# Check if npm is installed
|
| 16 |
+
if ! command -v npm &> /dev/null; then
|
| 17 |
+
echo "❌ npm is not installed. Please install npm first."
|
| 18 |
+
exit 1
|
| 19 |
+
fi
|
| 20 |
+
|
| 21 |
+
echo "✅ Node.js version: $(node --version)"
|
| 22 |
+
echo "✅ npm version: $(npm --version)"
|
| 23 |
+
|
| 24 |
+
# Install dependencies
|
| 25 |
+
echo ""
|
| 26 |
+
echo "📦 Installing dependencies..."
|
| 27 |
+
npm install
|
| 28 |
+
|
| 29 |
+
if [ $? -ne 0 ]; then
|
| 30 |
+
echo "❌ Failed to install dependencies"
|
| 31 |
+
exit 1
|
| 32 |
+
fi
|
| 33 |
+
|
| 34 |
+
echo "✅ Dependencies installed successfully"
|
| 35 |
+
|
| 36 |
+
# Build React app
|
| 37 |
+
echo ""
|
| 38 |
+
echo "🔨 Building React application..."
|
| 39 |
+
npm run build
|
| 40 |
+
|
| 41 |
+
if [ $? -ne 0 ]; then
|
| 42 |
+
echo "❌ Failed to build React application"
|
| 43 |
+
exit 1
|
| 44 |
+
fi
|
| 45 |
+
|
| 46 |
+
echo "✅ React application built successfully"
|
| 47 |
+
|
| 48 |
+
# Start development server (optional)
|
| 49 |
+
echo ""
|
| 50 |
+
echo "💡 Development environment ready!"
|
| 51 |
+
echo ""
|
| 52 |
+
echo "To start the development server, run:"
|
| 53 |
+
echo " npm run dev"
|
| 54 |
+
echo ""
|
| 55 |
+
echo "To build for production:"
|
| 56 |
+
echo " npm run build"
|
| 57 |
+
echo ""
|
| 58 |
+
echo "The built files are in the 'dist/' directory and can be served by your PHP application."
|
feedback.php
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
// Autoload Composer dependencies
|
| 3 |
+
require_once __DIR__ . '/vendor/autoload.php';
|
| 4 |
+
|
| 5 |
+
// Load environment variables if .env exists
|
| 6 |
+
if (file_exists(__DIR__ . '/.env')) {
|
| 7 |
+
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
|
| 8 |
+
$dotenv->load();
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
// Generate CSRF token for the form (must be before any output)
|
| 12 |
+
if (session_status() === PHP_SESSION_NONE) {
|
| 13 |
+
session_start();
|
| 14 |
+
}
|
| 15 |
+
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
| 16 |
+
|
| 17 |
+
// PROCESSAMENTO DO ENVIO DE EMAIL
|
| 18 |
+
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
| 19 |
+
header('Content-Type: application/json');
|
| 20 |
+
header('X-Content-Type-Options: nosniff');
|
| 21 |
+
header('X-Frame-Options: DENY');
|
| 22 |
+
header('X-XSS-Protection: 1; mode=block');
|
| 23 |
+
|
| 24 |
+
try {
|
| 25 |
+
// Rate limiting - prevent spam
|
| 26 |
+
$rateLimitFile = __DIR__ . '/logs/rate_limit_' . md5($_SERVER['REMOTE_ADDR'] ?? 'unknown') . '.txt';
|
| 27 |
+
$currentTime = time();
|
| 28 |
+
|
| 29 |
+
if (file_exists($rateLimitFile)) {
|
| 30 |
+
$lastRequest = (int)file_get_contents($rateLimitFile);
|
| 31 |
+
if ($currentTime - $lastRequest < 60) { // 1 minute cooldown
|
| 32 |
+
echo json_encode(['success' => false, 'error' => 'Aguarde um momento antes de enviar outra mensagem.']);
|
| 33 |
+
exit;
|
| 34 |
+
}
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
// Update rate limit
|
| 38 |
+
file_put_contents($rateLimitFile, $currentTime);
|
| 39 |
+
|
| 40 |
+
// Sanitize and validate input
|
| 41 |
+
$nome = trim($_POST['nome'] ?? '');
|
| 42 |
+
$email = trim($_POST['email'] ?? '');
|
| 43 |
+
$empresa = trim($_POST['empresa'] ?? '(não informado)');
|
| 44 |
+
$mensagem = trim($_POST['mensagem'] ?? '');
|
| 45 |
+
|
| 46 |
+
// CSRF protection (basic)
|
| 47 |
+
$csrfToken = $_POST['csrf_token'] ?? '';
|
| 48 |
+
$sessionToken = $_SESSION['csrf_token'] ?? '';
|
| 49 |
+
|
| 50 |
+
if (empty($csrfToken) || $csrfToken !== $sessionToken) {
|
| 51 |
+
echo json_encode(['success' => false, 'error' => 'Erro de segurança. Recarregue a página e tente novamente.']);
|
| 52 |
+
exit;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
// Prepare data for email service
|
| 56 |
+
$contactData = [
|
| 57 |
+
'nome' => $nome,
|
| 58 |
+
'email' => $email,
|
| 59 |
+
'empresa' => $empresa,
|
| 60 |
+
'mensagem' => $mensagem
|
| 61 |
+
];
|
| 62 |
+
|
| 63 |
+
// Use professional email service
|
| 64 |
+
$emailService = new \SoftEdge\EmailService();
|
| 65 |
+
|
| 66 |
+
if ($emailService->sendContactEmail($contactData)) {
|
| 67 |
+
echo json_encode(['success' => true]);
|
| 68 |
+
} else {
|
| 69 |
+
echo json_encode(['success' => false, 'error' => 'Erro ao enviar mensagem. Por favor, tente novamente ou entre em contato via WhatsApp.']);
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
} catch (\InvalidArgumentException $e) {
|
| 73 |
+
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
| 74 |
+
} catch (\Exception $e) {
|
| 75 |
+
error_log('Contact form error: ' . $e->getMessage());
|
| 76 |
+
echo json_encode(['success' => false, 'error' => 'Erro interno do servidor. Nossa equipe foi notificada.']);
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
exit;
|
| 80 |
+
}
|
| 81 |
+
?>
|
| 82 |
+
=======
|
| 83 |
+
<?php
|
| 84 |
+
// Autoload Composer dependencies
|
| 85 |
+
require_once __DIR__ . '/vendor/autoload.php';
|
| 86 |
+
|
| 87 |
+
// Load environment variables if .env exists
|
| 88 |
+
if (file_exists(__DIR__ . '/.env')) {
|
| 89 |
+
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
|
| 90 |
+
$dotenv->load();
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
// PROCESSAMENTO DO ENVIO DE EMAIL
|
| 94 |
+
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
| 95 |
+
header('Content-Type: application/json');
|
| 96 |
+
header('X-Content-Type-Options: nosniff');
|
| 97 |
+
header('X-Frame-Options: DENY');
|
| 98 |
+
header('X-XSS-Protection: 1; mode=block');
|
| 99 |
+
|
| 100 |
+
try {
|
| 101 |
+
// Rate limiting - prevent spam
|
| 102 |
+
$rateLimitFile = __DIR__ . '/logs/rate_limit_' . md5($_SERVER['REMOTE_ADDR'] ?? 'unknown') . '.txt';
|
| 103 |
+
$currentTime = time();
|
| 104 |
+
|
| 105 |
+
if (file_exists($rateLimitFile)) {
|
| 106 |
+
$lastRequest = (int)file_get_contents($rateLimitFile);
|
| 107 |
+
if ($currentTime - $lastRequest < 60) { // 1 minute cooldown
|
| 108 |
+
echo json_encode(['success' => false, 'error' => 'Aguarde um momento antes de enviar outra mensagem.']);
|
| 109 |
+
exit;
|
| 110 |
+
}
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
// Update rate limit
|
| 114 |
+
file_put_contents($rateLimitFile, $currentTime);
|
| 115 |
+
|
| 116 |
+
// Sanitize and validate input
|
| 117 |
+
$nome = trim($_POST['nome'] ?? '');
|
| 118 |
+
$email = trim($_POST['email'] ?? '');
|
| 119 |
+
$empresa = trim($_POST['empresa'] ?? '(não informado)');
|
| 120 |
+
$mensagem = trim($_POST['mensagem'] ?? '');
|
| 121 |
+
|
| 122 |
+
// CSRF protection (basic)
|
| 123 |
+
$csrfToken = $_POST['csrf_token'] ?? '';
|
| 124 |
+
$sessionToken = $_SESSION['csrf_token'] ?? '';
|
| 125 |
+
|
| 126 |
+
if (empty($csrfToken) || $csrfToken !== $sessionToken) {
|
| 127 |
+
echo json_encode(['success' => false, 'error' => 'Erro de segurança. Recarregue a página e tente novamente.']);
|
| 128 |
+
exit;
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
// Prepare data for email service
|
| 132 |
+
$contactData = [
|
| 133 |
+
'nome' => $nome,
|
| 134 |
+
'email' => $email,
|
| 135 |
+
'empresa' => $empresa,
|
| 136 |
+
'mensagem' => $mensagem
|
| 137 |
+
];
|
| 138 |
+
|
| 139 |
+
// Use professional email service
|
| 140 |
+
$emailService = new \SoftEdge\EmailService();
|
| 141 |
+
|
| 142 |
+
if ($emailService->sendContactEmail($contactData)) {
|
| 143 |
+
echo json_encode(['success' => true]);
|
| 144 |
+
} else {
|
| 145 |
+
echo json_encode(['success' => false, 'error' => 'Erro ao enviar mensagem. Por favor, tente novamente ou entre em contato via WhatsApp.']);
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
} catch (\InvalidArgumentException $e) {
|
| 149 |
+
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
| 150 |
+
} catch (\Exception $e) {
|
| 151 |
+
error_log('Contact form error: ' . $e->getMessage());
|
| 152 |
+
echo json_encode(['success' => false, 'error' => 'Erro interno do servidor. Nossa equipe foi notificada.']);
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
exit;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
// Generate CSRF token for the form
|
| 159 |
+
if (session_status() === PHP_SESSION_NONE) {
|
| 160 |
+
session_start();
|
| 161 |
+
}
|
| 162 |
+
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
| 163 |
+
?>
|
health.php
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
// Health Check Endpoint for Render.com
|
| 3 |
+
// This keeps the service active by preventing sleep mode
|
| 4 |
+
|
| 5 |
+
header('Content-Type: application/json');
|
| 6 |
+
header('Cache-Control: no-cache, no-store, must-revalidate');
|
| 7 |
+
header('Pragma: no-cache');
|
| 8 |
+
header('Expires: 0');
|
| 9 |
+
|
| 10 |
+
// Basic health check
|
| 11 |
+
$health = [
|
| 12 |
+
'status' => 'healthy',
|
| 13 |
+
'timestamp' => date('c'),
|
| 14 |
+
'service' => 'SoftEdge Corporation Website',
|
| 15 |
+
'version' => '2.0.0',
|
| 16 |
+
'uptime' => time() - ($_SERVER['REQUEST_TIME'] ?? time()),
|
| 17 |
+
'checks' => [
|
| 18 |
+
'database' => 'not_required',
|
| 19 |
+
'filesystem' => is_writable(__DIR__) ? 'writable' : 'read_only',
|
| 20 |
+
'php' => PHP_VERSION,
|
| 21 |
+
'memory' => memory_get_peak_usage(true) . ' bytes',
|
| 22 |
+
'server' => $_SERVER['SERVER_SOFTWARE'] ?? 'unknown'
|
| 23 |
+
]
|
| 24 |
+
];
|
| 25 |
+
|
| 26 |
+
// Check if critical files exist
|
| 27 |
+
$criticalFiles = [
|
| 28 |
+
'index.php',
|
| 29 |
+
'composer.json',
|
| 30 |
+
'vendor/autoload.php',
|
| 31 |
+
'assets/logo.jpeg'
|
| 32 |
+
];
|
| 33 |
+
|
| 34 |
+
foreach ($criticalFiles as $file) {
|
| 35 |
+
if (!file_exists(__DIR__ . '/' . $file)) {
|
| 36 |
+
$health['status'] = 'degraded';
|
| 37 |
+
$health['checks']['missing_files'][] = $file;
|
| 38 |
+
}
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
// Check if email service is configured
|
| 42 |
+
$emailConfigured = false;
|
| 43 |
+
if (file_exists(__DIR__ . '/.env')) {
|
| 44 |
+
$envContent = file_get_contents(__DIR__ . '/.env');
|
| 45 |
+
$emailConfigured = strpos($envContent, 'SMTP_HOST=') !== false;
|
| 46 |
+
}
|
| 47 |
+
$health['checks']['email_configured'] = $emailConfigured;
|
| 48 |
+
|
| 49 |
+
// Return appropriate HTTP status
|
| 50 |
+
if ($health['status'] === 'healthy') {
|
| 51 |
+
http_response_code(200);
|
| 52 |
+
} elseif ($health['status'] === 'degraded') {
|
| 53 |
+
http_response_code(200); // Still return 200 for uptime monitors
|
| 54 |
+
} else {
|
| 55 |
+
http_response_code(503);
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
echo json_encode($health, JSON_PRETTY_PRINT);
|
| 59 |
+
?>
|
index.php
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
// PHP Component - Can be called by Flask or run standalone
|
| 3 |
+
require_once __DIR__ . '/src/Bootstrap.php';
|
| 4 |
+
\SoftEdge\Env::load(__DIR__);
|
| 5 |
+
\SoftEdge\Bootstrap::init();
|
| 6 |
+
|
| 7 |
+
// If called directly (not by Flask), redirect to Flask server
|
| 8 |
+
if (!isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !isset($_GET['direct'])) {
|
| 9 |
+
header('Location: http://localhost:7860/');
|
| 10 |
+
exit;
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
// Track page visit
|
| 14 |
+
try {
|
| 15 |
+
\SoftEdge\Database::execute(
|
| 16 |
+
"INSERT INTO page_visits (page_url, page_title, ip_address, user_agent, device_type, referrer_url) VALUES (?, ?, ?, ?, ?, ?)",
|
| 17 |
+
[
|
| 18 |
+
'/',
|
| 19 |
+
'SoftEdge Corporation - Soluções em Tecnologia',
|
| 20 |
+
$_SERVER['REMOTE_ADDR'] ?? '',
|
| 21 |
+
$_SERVER['HTTP_USER_AGENT'] ?? '',
|
| 22 |
+
'desktop', // Simplified detection
|
| 23 |
+
$_SERVER['HTTP_REFERER'] ?? ''
|
| 24 |
+
]
|
| 25 |
+
);
|
| 26 |
+
} catch (Exception $e) {
|
| 27 |
+
// Log error but don't break page
|
| 28 |
+
error_log("Page visit tracking failed: " . $e->getMessage());
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
// Get dynamic stats
|
| 32 |
+
$stats = ['projects' => 0, 'contacts' => 0, 'satisfaction' => 4.9];
|
| 33 |
+
try {
|
| 34 |
+
$statsData = \SoftEdge\Database::queryOne("SELECT COUNT(*) as projects FROM projects");
|
| 35 |
+
$contactsData = \SoftEdge\Database::queryOne("SELECT COUNT(*) as contacts FROM contact_submissions");
|
| 36 |
+
$stats['projects'] = $statsData['projects'] ?? 0;
|
| 37 |
+
$stats['contacts'] = $contactsData['contacts'] ?? 0;
|
| 38 |
+
} catch (Exception $e) {
|
| 39 |
+
// Use defaults if DB fails
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
// If called with JSON request, return data for Flask
|
| 43 |
+
if (isset($_GET['json'])) {
|
| 44 |
+
header('Content-Type: application/json');
|
| 45 |
+
echo json_encode($stats);
|
| 46 |
+
exit;
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
// Otherwise, render the component HTML
|
| 50 |
+
?>
|
| 51 |
+
<!-- PHP Component: Homepage Stats -->
|
| 52 |
+
<div class="grid grid-cols-1 sm:grid-cols-3 gap-8 max-w-2xl mx-auto mt-12">
|
| 53 |
+
<div class="text-center">
|
| 54 |
+
<div class="text-4xl font-bold text-cyan-400"><?php echo number_format($stats['projects']); ?>+</div>
|
| 55 |
+
<div class="text-slate-400">Projetos Entregues</div>
|
| 56 |
+
</div>
|
| 57 |
+
<div class="text-center">
|
| 58 |
+
<div class="text-4xl font-bold text-blue-400"><?php echo number_format($stats['contacts']); ?>+</div>
|
| 59 |
+
<div class="text-slate-400">Clientes Satisfeitos</div>
|
| 60 |
+
</div>
|
| 61 |
+
<div class="text-center">
|
| 62 |
+
<div class="text-4xl font-bold text-purple-400"><?php echo $stats['satisfaction']; ?>★</div>
|
| 63 |
+
<div class="text-slate-400">Avaliação Média</div>
|
| 64 |
+
</div>
|
| 65 |
+
</div>
|
| 66 |
+
|
| 67 |
+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mt-16">
|
| 68 |
+
<!-- Desenvolvimento Web -->
|
| 69 |
+
<div class="glass-card p-8 rounded-2xl hover:scale-105 transition-transform">
|
| 70 |
+
<div class="w-16 h-16 bg-cyan-500/20 rounded-2xl flex items-center justify-center mb-6">
|
| 71 |
+
<i data-lucide="code" class="w-8 h-8 text-cyan-400"></i>
|
| 72 |
+
</div>
|
| 73 |
+
<h3 class="text-2xl font-bold text-white mb-4">Desenvolvimento Web</h3>
|
| 74 |
+
<p class="text-slate-400 leading-relaxed">
|
| 75 |
+
Aplicações web modernas e responsivas com as melhores tecnologias do mercado.
|
| 76 |
+
</p>
|
| 77 |
+
</div>
|
| 78 |
+
|
| 79 |
+
<!-- Mobile Apps -->
|
| 80 |
+
<div class="glass-card p-8 rounded-2xl hover:scale-105 transition-transform">
|
| 81 |
+
<div class="w-16 h-16 bg-blue-500/20 rounded-2xl flex items-center justify-center mb-6">
|
| 82 |
+
<i data-lucide="smartphone" class="w-8 h-8 text-blue-400"></i>
|
| 83 |
+
</div>
|
| 84 |
+
<h3 class="text-2xl font-bold text-white mb-4">Aplicativos Mobile</h3>
|
| 85 |
+
<p class="text-slate-400 leading-relaxed">
|
| 86 |
+
Apps nativos e multiplataforma para iOS e Android com experiência excepcional.
|
| 87 |
+
</p>
|
| 88 |
+
</div>
|
| 89 |
+
|
| 90 |
+
<!-- IA & Automação -->
|
| 91 |
+
<div class="glass-card p-8 rounded-2xl hover:scale-105 transition-transform">
|
| 92 |
+
<div class="w-16 h-16 bg-purple-500/20 rounded-2xl flex items-center justify-center mb-6">
|
| 93 |
+
<i data-lucide="brain" class="w-8 h-8 text-purple-400"></i>
|
| 94 |
+
</div>
|
| 95 |
+
<h3 class="text-2xl font-bold text-white mb-4">IA & Automação</h3>
|
| 96 |
+
<p class="text-slate-400 leading-relaxed">
|
| 97 |
+
Soluções de inteligência artificial e automação para otimizar processos.
|
| 98 |
+
</p>
|
| 99 |
+
</div>
|
| 100 |
+
</div>
|
keep-alive.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Keep-Alive Script for Render.com
|
| 2 |
+
// Prevents sleep mode by pinging health endpoint every 4 minutes
|
| 3 |
+
|
| 4 |
+
const https = require('https');
|
| 5 |
+
const http = require('http');
|
| 6 |
+
|
| 7 |
+
const SITE_URL = process.env.SITE_URL || 'https://softedge.onrender.com';
|
| 8 |
+
const HEALTH_ENDPOINT = '/health.php';
|
| 9 |
+
const INTERVAL_MINUTES = 4; // Ping every 4 minutes (under Render's 5-minute limit)
|
| 10 |
+
|
| 11 |
+
function pingHealthEndpoint() {
|
| 12 |
+
const url = new URL(HEALTH_ENDPOINT, SITE_URL);
|
| 13 |
+
const client = url.protocol === 'https:' ? https : http;
|
| 14 |
+
|
| 15 |
+
const options = {
|
| 16 |
+
hostname: url.hostname,
|
| 17 |
+
port: url.port,
|
| 18 |
+
path: url.pathname,
|
| 19 |
+
method: 'GET',
|
| 20 |
+
headers: {
|
| 21 |
+
'User-Agent': 'SoftEdge-KeepAlive/1.0',
|
| 22 |
+
'Accept': 'application/json'
|
| 23 |
+
}
|
| 24 |
+
};
|
| 25 |
+
|
| 26 |
+
const req = client.request(options, (res) => {
|
| 27 |
+
let data = '';
|
| 28 |
+
|
| 29 |
+
res.on('data', (chunk) => {
|
| 30 |
+
data += chunk;
|
| 31 |
+
});
|
| 32 |
+
|
| 33 |
+
res.on('end', () => {
|
| 34 |
+
try {
|
| 35 |
+
const health = JSON.parse(data);
|
| 36 |
+
console.log(`[${new Date().toISOString()}] Health check: ${health.status} - Uptime: ${health.uptime}s`);
|
| 37 |
+
} catch (e) {
|
| 38 |
+
console.log(`[${new Date().toISOString()}] Health check response received`);
|
| 39 |
+
}
|
| 40 |
+
});
|
| 41 |
+
});
|
| 42 |
+
|
| 43 |
+
req.on('error', (err) => {
|
| 44 |
+
console.error(`[${new Date().toISOString()}] Health check failed:`, err.message);
|
| 45 |
+
});
|
| 46 |
+
|
| 47 |
+
req.setTimeout(10000, () => {
|
| 48 |
+
req.destroy();
|
| 49 |
+
console.error(`[${new Date().toISOString()}] Health check timeout`);
|
| 50 |
+
});
|
| 51 |
+
|
| 52 |
+
req.end();
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
// Start the keep-alive process
|
| 56 |
+
console.log(`Starting SoftEdge Keep-Alive service`);
|
| 57 |
+
console.log(`Pinging ${SITE_URL}${HEALTH_ENDPOINT} every ${INTERVAL_MINUTES} minutes`);
|
| 58 |
+
console.log(`Press Ctrl+C to stop`);
|
| 59 |
+
|
| 60 |
+
// Initial ping
|
| 61 |
+
pingHealthEndpoint();
|
| 62 |
+
|
| 63 |
+
// Set up interval
|
| 64 |
+
const intervalMs = INTERVAL_MINUTES * 60 * 1000;
|
| 65 |
+
setInterval(pingHealthEndpoint, intervalMs);
|
| 66 |
+
|
| 67 |
+
// Handle graceful shutdown
|
| 68 |
+
process.on('SIGINT', () => {
|
| 69 |
+
console.log(`\n[${new Date().toISOString()}] SoftEdge Keep-Alive service stopped`);
|
| 70 |
+
process.exit(0);
|
| 71 |
+
});
|
| 72 |
+
|
| 73 |
+
process.on('SIGTERM', () => {
|
| 74 |
+
console.log(`\n[${new Date().toISOString()}] SoftEdge Keep-Alive service terminated`);
|
| 75 |
+
process.exit(0);
|
| 76 |
+
});
|
login.php
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
// Redirect to Flask authentication
|
| 3 |
+
header('Location: /admin');
|
| 4 |
+
exit;
|
| 5 |
+
?>
|
package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "softedge-corporation",
|
| 3 |
+
"version": "2.0.0",
|
| 4 |
+
"description": "Website institucional da SoftEdge Corporation com integração React + PHP",
|
| 5 |
+
"main": "src/react/index.js",
|
| 6 |
+
"scripts": {
|
| 7 |
+
"start": "webpack serve --mode development --open",
|
| 8 |
+
"build": "webpack --mode production",
|
| 9 |
+
"dev": "webpack --mode development --watch",
|
| 10 |
+
"full-dev": "concurrently \"npm run dev\" \"cd .. && php -S localhost:8080\"",
|
| 11 |
+
"lint": "eslint src/react --ext .js,.jsx",
|
| 12 |
+
"test": "jest",
|
| 13 |
+
"analyze": "webpack-bundle-analyzer dist/static/js/*.js"
|
| 14 |
+
},
|
| 15 |
+
"keywords": [
|
| 16 |
+
"softedge",
|
| 17 |
+
"corporation",
|
| 18 |
+
"react",
|
| 19 |
+
"php",
|
| 20 |
+
"web-development",
|
| 21 |
+
"full-stack"
|
| 22 |
+
],
|
| 23 |
+
"author": "SoftEdge Corporation",
|
| 24 |
+
"license": "MIT",
|
| 25 |
+
"dependencies": {
|
| 26 |
+
"react": "^18.2.0",
|
| 27 |
+
"react-dom": "^18.2.0",
|
| 28 |
+
"react-router-dom": "^6.8.0",
|
| 29 |
+
"axios": "^1.3.0",
|
| 30 |
+
"lucide-react": "^0.144.0",
|
| 31 |
+
"framer-motion": "^10.12.0",
|
| 32 |
+
"react-intersection-observer": "^9.5.0",
|
| 33 |
+
"react-helmet-async": "^1.3.0"
|
| 34 |
+
},
|
| 35 |
+
"devDependencies": {
|
| 36 |
+
"@babel/core": "^7.21.0",
|
| 37 |
+
"@babel/preset-env": "^7.20.0",
|
| 38 |
+
"@babel/preset-react": "^7.18.0",
|
| 39 |
+
"@babel/plugin-proposal-class-properties": "^7.18.0",
|
| 40 |
+
"@babel/plugin-proposal-object-rest-spread": "^7.20.0",
|
| 41 |
+
"babel-loader": "^9.1.0",
|
| 42 |
+
"webpack": "^5.75.0",
|
| 43 |
+
"webpack-cli": "^5.0.0",
|
| 44 |
+
"webpack-dev-server": "^4.11.0",
|
| 45 |
+
"html-webpack-plugin": "^5.5.0",
|
| 46 |
+
"mini-css-extract-plugin": "^2.7.0",
|
| 47 |
+
"css-loader": "^6.7.0",
|
| 48 |
+
"style-loader": "^3.3.0",
|
| 49 |
+
"postcss-loader": "^7.0.0",
|
| 50 |
+
"autoprefixer": "^10.4.0",
|
| 51 |
+
"cssnano": "^6.0.0",
|
| 52 |
+
"terser-webpack-plugin": "^5.3.0",
|
| 53 |
+
"css-minimizer-webpack-plugin": "^4.2.0",
|
| 54 |
+
"webpack-bundle-analyzer": "^4.7.0",
|
| 55 |
+
"concurrently": "^7.6.0",
|
| 56 |
+
"eslint": "^8.34.0",
|
| 57 |
+
"eslint-plugin-react": "^7.32.0",
|
| 58 |
+
"eslint-plugin-react-hooks": "^4.6.0",
|
| 59 |
+
"jest": "^29.4.0",
|
| 60 |
+
"@testing-library/react": "^13.4.0",
|
| 61 |
+
"@testing-library/jest-dom": "^5.16.0",
|
| 62 |
+
"postcss": "^8.4.0"
|
| 63 |
+
},
|
| 64 |
+
"browserslist": {
|
| 65 |
+
"production": [
|
| 66 |
+
">0.2%",
|
| 67 |
+
"not dead",
|
| 68 |
+
"not op_mini all"
|
| 69 |
+
],
|
| 70 |
+
"development": [
|
| 71 |
+
"last 1 chrome version",
|
| 72 |
+
"last 1 firefox version",
|
| 73 |
+
"last 1 safari version"
|
| 74 |
+
]
|
| 75 |
+
},
|
| 76 |
+
"engines": {
|
| 77 |
+
"node": ">=16.0.0",
|
| 78 |
+
"npm": ">=8.0.0"
|
| 79 |
+
},
|
| 80 |
+
"repository": {
|
| 81 |
+
"type": "git",
|
| 82 |
+
"url": "https://github.com/akira40-soft/Softedge.git"
|
| 83 |
+
},
|
| 84 |
+
"homepage": "https://softedge-corporation.up.railway.app"
|
| 85 |
+
}
|
php.ini
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
; SoftEdge Corporation - PHP Configuration
|
| 2 |
+
; This file contains PHP settings optimized for production
|
| 3 |
+
|
| 4 |
+
; Error Handling
|
| 5 |
+
display_errors = Off
|
| 6 |
+
display_startup_errors = Off
|
| 7 |
+
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
|
| 8 |
+
log_errors = On
|
| 9 |
+
error_log = /var/www/html/logs/php_errors.log
|
| 10 |
+
|
| 11 |
+
; Performance
|
| 12 |
+
max_execution_time = 300
|
| 13 |
+
max_input_time = 60
|
| 14 |
+
memory_limit = 256M
|
| 15 |
+
post_max_size = 10M
|
| 16 |
+
upload_max_filesize = 10M
|
| 17 |
+
max_file_uploads = 20
|
| 18 |
+
|
| 19 |
+
; Security
|
| 20 |
+
expose_php = Off
|
| 21 |
+
allow_url_fopen = On
|
| 22 |
+
allow_url_include = Off
|
| 23 |
+
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
|
| 24 |
+
open_basedir = /var/www/html:/tmp
|
| 25 |
+
|
| 26 |
+
; Sessions
|
| 27 |
+
session.save_path = /tmp
|
| 28 |
+
session.gc_probability = 1
|
| 29 |
+
session.gc_divisor = 1000
|
| 30 |
+
session.gc_maxlifetime = 1440
|
| 31 |
+
session.cookie_httponly = 1
|
| 32 |
+
session.cookie_secure = 1
|
| 33 |
+
session.use_only_cookies = 1
|
| 34 |
+
session.cookie_samesite = "Lax"
|
| 35 |
+
|
| 36 |
+
; File Uploads
|
| 37 |
+
file_uploads = On
|
| 38 |
+
upload_tmp_dir = /tmp
|
| 39 |
+
|
| 40 |
+
; Date/Time
|
| 41 |
+
date.timezone = "Africa/Luanda"
|
| 42 |
+
|
| 43 |
+
; Mail
|
| 44 |
+
SMTP = localhost
|
| 45 |
+
smtp_port = 25
|
| 46 |
+
mail.add_x_header = On
|
| 47 |
+
|
| 48 |
+
; Extensions
|
| 49 |
+
extension=mbstring
|
| 50 |
+
extension=exif
|
| 51 |
+
extension=pdo
|
| 52 |
+
extension=pdo_mysql
|
| 53 |
+
extension=gd
|
| 54 |
+
extension=zip
|
| 55 |
+
extension=xml
|
| 56 |
+
extension=curl
|
| 57 |
+
extension=intl
|
| 58 |
+
extension=bcmath
|
| 59 |
+
|
| 60 |
+
; OPcache (if available)
|
| 61 |
+
opcache.enable=1
|
| 62 |
+
opcache.memory_consumption=256
|
| 63 |
+
opcache.max_accelerated_files=7963
|
| 64 |
+
opcache.revalidate_freq=0
|
| 65 |
+
opcache.validate_timestamps=0
|
| 66 |
+
opcache.consistency_checks=0
|
| 67 |
+
opcache.error_log=/var/www/html/logs/opcache.log
|
projetos.php
ADDED
|
@@ -0,0 +1,444 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
require_once __DIR__ . '/src/Bootstrap.php';
|
| 3 |
+
\SoftEdge\Env::load(__DIR__);
|
| 4 |
+
\SoftEdge\Bootstrap::init();
|
| 5 |
+
include 'components/header.php';
|
| 6 |
+
?>
|
| 7 |
+
|
| 8 |
+
<!-- HERO SECTION -->
|
| 9 |
+
<section class="relative pt-32 pb-20 overflow-hidden">
|
| 10 |
+
<!-- Background -->
|
| 11 |
+
<div class="absolute inset-0 -z-10">
|
| 12 |
+
<div class="absolute inset-0 bg-linear-to-br from-slate-950 via-slate-900 to-slate-950"></div>
|
| 13 |
+
<div class="absolute inset-0 opacity-30">
|
| 14 |
+
<div class="absolute top-20 left-20 w-96 h-96 bg-purple-500/20 rounded-full blur-3xl"></div>
|
| 15 |
+
<div class="absolute bottom-20 right-20 w-96 h-96 bg-cyan-500/20 rounded-full blur-3xl"></div>
|
| 16 |
+
</div>
|
| 17 |
+
</div>
|
| 18 |
+
|
| 19 |
+
<!-- Content -->
|
| 20 |
+
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
| 21 |
+
<div class="space-y-6">
|
| 22 |
+
<div class="inline-block px-4 py-2 bg-purple-500/10 rounded-full border border-purple-500/20 mb-4">
|
| 23 |
+
<span class="text-purple-400 text-sm font-semibold uppercase tracking-wider">Portfolio</span>
|
| 24 |
+
</div>
|
| 25 |
+
|
| 26 |
+
<h1 class="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold leading-tight">
|
| 27 |
+
Projetos que
|
| 28 |
+
<span class="block bg-linear-to-r from-cyan-400 via-blue-500 to-purple-500 bg-clip-text text-transparent">
|
| 29 |
+
transformam negócios
|
| 30 |
+
</span>
|
| 31 |
+
</h1>
|
| 32 |
+
|
| 33 |
+
<p class="text-base sm:text-lg md:text-xl text-gray-300 max-w-3xl mx-auto leading-relaxed">
|
| 34 |
+
Conheça algumas das soluções que desenvolvemos e que já estão transformando negócios reais.
|
| 35 |
+
</p>
|
| 36 |
+
</div>
|
| 37 |
+
</div>
|
| 38 |
+
</section>
|
| 39 |
+
|
| 40 |
+
<!-- MAIN CONTENT -->
|
| 41 |
+
<main class="relative py-20 lg:py-32">
|
| 42 |
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
| 43 |
+
|
| 44 |
+
<!-- PROJETO DESTAQUE: AKIRA IA -->
|
| 45 |
+
<div class="mb-20 lg:mb-32">
|
| 46 |
+
<div class="relative">
|
| 47 |
+
<div class="absolute inset-0 bg-linear-to-r from-purple-500/20 via-pink-500/20 to-cyan-500/20 rounded-3xl blur-3xl"></div>
|
| 48 |
+
|
| 49 |
+
<div class="relative bg-slate-900/80 backdrop-blur-xl border border-purple-500/30 rounded-3xl overflow-hidden">
|
| 50 |
+
<!-- Badge Destaque -->
|
| 51 |
+
<div class="absolute top-6 right-6 z-10 px-4 py-2 bg-purple-500 rounded-full border border-purple-400 shadow-lg">
|
| 52 |
+
<span class="text-white text-sm font-bold uppercase tracking-wider flex items-center gap-2">
|
| 53 |
+
<i data-lucide="star" class="w-4 h-4"></i>
|
| 54 |
+
Projeto Destaque
|
| 55 |
+
</span>
|
| 56 |
+
</div>
|
| 57 |
+
|
| 58 |
+
<div class="grid lg:grid-cols-2 gap-8 lg:gap-12 p-8 lg:p-12">
|
| 59 |
+
|
| 60 |
+
<!-- Left: Info -->
|
| 61 |
+
<div class="flex flex-col justify-center space-y-6">
|
| 62 |
+
<div>
|
| 63 |
+
<div class="inline-flex items-center gap-2 px-3 py-1 bg-purple-500/20 border border-purple-500/30 rounded-full mb-4">
|
| 64 |
+
<i data-lucide="brain" class="w-4 h-4 text-purple-400"></i>
|
| 65 |
+
<span class="text-purple-400 text-xs font-semibold uppercase">Inteligência Artificial</span>
|
| 66 |
+
</div>
|
| 67 |
+
|
| 68 |
+
<h2 class="text-3xl sm:text-4xl md:text-5xl font-bold text-white mb-4">
|
| 69 |
+
AKIRA IA
|
| 70 |
+
<span class="block text-2xl sm:text-3xl text-gray-400 mt-2">🇦🇴 100% Angolana</span>
|
| 71 |
+
</h2>
|
| 72 |
+
</div>
|
| 73 |
+
|
| 74 |
+
<p class="text-gray-300 text-lg leading-relaxed">
|
| 75 |
+
Uma inteligência artificial autônoma desenvolvida inteiramente pela SoftEdge, projetada para conversar naturalmente com usuários, entender contexto e fornecer respostas precisas e humanizadas.
|
| 76 |
+
</p>
|
| 77 |
+
|
| 78 |
+
<!-- Features -->
|
| 79 |
+
<div class="space-y-3">
|
| 80 |
+
<div class="flex items-start gap-3">
|
| 81 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-purple-400 shrink-0 mt-1"></i>
|
| 82 |
+
<span class="text-gray-300">Processamento de linguagem natural (NLP)</span>
|
| 83 |
+
</div>
|
| 84 |
+
<div class="flex items-start gap-3">
|
| 85 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-purple-400 shrink-0 mt-1"></i>
|
| 86 |
+
<span class="text-gray-300">Aprendizado contínuo com conversas</span>
|
| 87 |
+
</div>
|
| 88 |
+
<div class="flex items-start gap-3">
|
| 89 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-purple-400 shrink-0 mt-1"></i>
|
| 90 |
+
<span class="text-gray-300">Integração com WhatsApp e plataformas web</span>
|
| 91 |
+
</div>
|
| 92 |
+
<div class="flex items-start gap-3">
|
| 93 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-purple-400 shrink-0 mt-1"></i>
|
| 94 |
+
<span class="text-gray-300">Personalidade única e respostas contextualizadas</span>
|
| 95 |
+
</div>
|
| 96 |
+
</div>
|
| 97 |
+
|
| 98 |
+
<!-- Tech Stack -->
|
| 99 |
+
<div>
|
| 100 |
+
<p class="text-sm text-gray-400 mb-3 font-medium">Tecnologias:</p>
|
| 101 |
+
<div class="flex flex-wrap gap-2">
|
| 102 |
+
<span class="px-4 py-2 bg-purple-500/20 border border-purple-500/30 rounded-lg text-purple-400 text-sm font-medium">Python</span>
|
| 103 |
+
<span class="px-4 py-2 bg-pink-500/20 border border-pink-500/30 rounded-lg text-pink-400 text-sm font-medium">TensorFlow</span>
|
| 104 |
+
<span class="px-4 py-2 bg-cyan-500/20 border border-cyan-500/30 rounded-lg text-cyan-400 text-sm font-medium">OpenAI API</span>
|
| 105 |
+
<span class="px-4 py-2 bg-blue-500/20 border border-blue-500/30 rounded-lg text-blue-400 text-sm font-medium">FastAPI</span>
|
| 106 |
+
</div>
|
| 107 |
+
</div>
|
| 108 |
+
</div>
|
| 109 |
+
|
| 110 |
+
<!-- Right: Main Image -->
|
| 111 |
+
<div class="relative group">
|
| 112 |
+
<div class="absolute inset-0 bg-linear-to-br from-purple-500/30 to-pink-500/30 rounded-2xl blur-xl opacity-50 group-hover:opacity-100 transition-opacity"></div>
|
| 113 |
+
<div class="relative overflow-hidden rounded-2xl border border-white/10 shadow-2xl">
|
| 114 |
+
<img src="/assets/akira.jpg"
|
| 115 |
+
alt="AKIRA IA - Interface Principal"
|
| 116 |
+
class="w-full h-auto object-cover transition-transform duration-700 group-hover:scale-105">
|
| 117 |
+
<div class="absolute inset-0 bg-linear-to-t from-black/60 to-transparent"></div>
|
| 118 |
+
<div class="absolute bottom-4 left-4 right-4">
|
| 119 |
+
<p class="text-white font-semibold text-lg">Interface Principal da AKIRA</p>
|
| 120 |
+
<p class="text-gray-300 text-sm">Conversando com usuários em tempo real</p>
|
| 121 |
+
</div>
|
| 122 |
+
</div>
|
| 123 |
+
</div>
|
| 124 |
+
</div>
|
| 125 |
+
|
| 126 |
+
<!-- Gallery Section -->
|
| 127 |
+
<div class="border-t border-white/10 p-8 lg:p-12 bg-black/20">
|
| 128 |
+
<h3 class="text-2xl font-bold text-white mb-6 flex items-center gap-3">
|
| 129 |
+
<i data-lucide="image" class="w-6 h-6 text-purple-400"></i>
|
| 130 |
+
Galeria de Conversas
|
| 131 |
+
</h3>
|
| 132 |
+
|
| 133 |
+
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
| 134 |
+
<!-- Gallery Image 1 -->
|
| 135 |
+
<div class="group relative overflow-hidden rounded-xl border border-white/10 hover:border-purple-500/50 transition-all cursor-pointer">
|
| 136 |
+
<img src="/assets/akira1.jpg"
|
| 137 |
+
alt="AKIRA IA - Conversa 1"
|
| 138 |
+
class="w-full h-48 object-cover transition-transform duration-500 group-hover:scale-110">
|
| 139 |
+
<div class="absolute inset-0 bg-black/60 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
|
| 140 |
+
<i data-lucide="maximize-2" class="w-8 h-8 text-white"></i>
|
| 141 |
+
</div>
|
| 142 |
+
</div>
|
| 143 |
+
|
| 144 |
+
<!-- Gallery Image 2 -->
|
| 145 |
+
<div class="group relative overflow-hidden rounded-xl border border-white/10 hover:border-purple-500/50 transition-all cursor-pointer">
|
| 146 |
+
<img src="/assets/akira2.jpg"
|
| 147 |
+
alt="AKIRA IA - Conversa 2"
|
| 148 |
+
class="w-full h-48 object-cover transition-transform duration-500 group-hover:scale-110">
|
| 149 |
+
<div class="absolute inset-0 bg-black/60 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
|
| 150 |
+
<i data-lucide="maximize-2" class="w-8 h-8 text-white"></i>
|
| 151 |
+
</div>
|
| 152 |
+
</div>
|
| 153 |
+
|
| 154 |
+
<!-- Gallery Image 3 -->
|
| 155 |
+
<div class="group relative overflow-hidden rounded-xl border border-white/10 hover:border-purple-500/50 transition-all cursor-pointer">
|
| 156 |
+
<img src="/assets/akira3.jpg"
|
| 157 |
+
alt="AKIRA IA - Conversa 3"
|
| 158 |
+
class="w-full h-48 object-cover transition-transform duration-500 group-hover:scale-110">
|
| 159 |
+
<div class="absolute inset-0 bg-black/60 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
|
| 160 |
+
<i data-lucide="maximize-2" class="w-8 h-8 text-white"></i>
|
| 161 |
+
</div>
|
| 162 |
+
</div>
|
| 163 |
+
|
| 164 |
+
<!-- Gallery Image 4 -->
|
| 165 |
+
<div class="group relative overflow-hidden rounded-xl border border-white/10 hover:border-purple-500/50 transition-all cursor-pointer">
|
| 166 |
+
<img src="/assets/akira4.jpg"
|
| 167 |
+
alt="AKIRA IA - Conversa 4"
|
| 168 |
+
class="w-full h-48 object-cover transition-transform duration-500 group-hover:scale-110">
|
| 169 |
+
<div class="absolute inset-0 bg-black/60 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
|
| 170 |
+
<i data-lucide="maximize-2" class="w-8 h-8 text-white"></i>
|
| 171 |
+
</div>
|
| 172 |
+
</div>
|
| 173 |
+
</div>
|
| 174 |
+
|
| 175 |
+
<p class="text-gray-400 text-sm mt-4 text-center italic">
|
| 176 |
+
Clique nas imagens para ampliar e ver detalhes das conversas
|
| 177 |
+
</p>
|
| 178 |
+
</div>
|
| 179 |
+
</div>
|
| 180 |
+
</div>
|
| 181 |
+
</div>
|
| 182 |
+
|
| 183 |
+
<!-- OUTROS PROJETOS -->
|
| 184 |
+
<div>
|
| 185 |
+
<div class="text-center mb-12 lg:mb-16">
|
| 186 |
+
<div class="inline-block px-4 py-2 bg-cyan-500/10 rounded-full border border-cyan-500/20 mb-4">
|
| 187 |
+
<span class="text-cyan-400 text-sm font-semibold uppercase tracking-wider">Mais Projetos</span>
|
| 188 |
+
</div>
|
| 189 |
+
<h2 class="text-3xl sm:text-4xl md:text-5xl font-bold text-white">
|
| 190 |
+
Outros projetos desenvolvidos
|
| 191 |
+
</h2>
|
| 192 |
+
</div>
|
| 193 |
+
|
| 194 |
+
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-8">
|
| 195 |
+
|
| 196 |
+
<!-- PROJETO 1: ERP -->
|
| 197 |
+
<div class="group relative">
|
| 198 |
+
<div class="absolute inset-0 bg-linear-to-br from-cyan-500/20 to-blue-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity"></div>
|
| 199 |
+
<div class="relative bg-linear-to-br from-cyan-600/20 to-blue-600/20 rounded-2xl overflow-hidden border border-white/10 hover:border-cyan-500/30 transition-all h-full">
|
| 200 |
+
<div class="p-8 h-80 flex flex-col justify-between">
|
| 201 |
+
<div>
|
| 202 |
+
<div class="w-14 h-14 bg-cyan-500/20 rounded-xl flex items-center justify-center mb-4">
|
| 203 |
+
<i data-lucide="layout-dashboard" class="w-7 h-7 text-cyan-400"></i>
|
| 204 |
+
</div>
|
| 205 |
+
<h3 class="text-2xl font-bold text-white mb-3">Gestão Total ERP</h3>
|
| 206 |
+
<p class="text-gray-300 leading-relaxed mb-4">
|
| 207 |
+
Sistema completo de gestão empresarial com controle financeiro, estoque e CRM integrado.
|
| 208 |
+
</p>
|
| 209 |
+
</div>
|
| 210 |
+
|
| 211 |
+
<div class="space-y-3">
|
| 212 |
+
<div class="flex flex-wrap gap-2">
|
| 213 |
+
<span class="px-3 py-1 bg-cyan-500/20 rounded-full text-cyan-400 text-xs font-medium">Laravel</span>
|
| 214 |
+
<span class="px-3 py-1 bg-blue-500/20 rounded-full text-blue-400 text-xs font-medium">Vue.js</span>
|
| 215 |
+
<span class="px-3 py-1 bg-purple-500/20 rounded-full text-purple-400 text-xs font-medium">MySQL</span>
|
| 216 |
+
</div>
|
| 217 |
+
<div class="flex items-center gap-2 text-gray-400 text-sm">
|
| 218 |
+
<i data-lucide="calendar" class="w-4 h-4"></i>
|
| 219 |
+
<span>Concluído em 2024</span>
|
| 220 |
+
</div>
|
| 221 |
+
</div>
|
| 222 |
+
</div>
|
| 223 |
+
</div>
|
| 224 |
+
</div>
|
| 225 |
+
|
| 226 |
+
<!-- PROJETO 2: E-commerce -->
|
| 227 |
+
<div class="group relative">
|
| 228 |
+
<div class="absolute inset-0 bg-linear-to-br from-purple-500/20 to-pink-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity"></div>
|
| 229 |
+
<div class="relative bg-linear-to-br from-purple-600/20 to-pink-600/20 rounded-2xl overflow-hidden border border-white/10 hover:border-purple-500/30 transition-all h-full">
|
| 230 |
+
<div class="p-8 h-80 flex flex-col justify-between">
|
| 231 |
+
<div>
|
| 232 |
+
<div class="w-14 h-14 bg-purple-500/20 rounded-xl flex items-center justify-center mb-4">
|
| 233 |
+
<i data-lucide="shopping-cart" class="w-7 h-7 text-purple-400"></i>
|
| 234 |
+
</div>
|
| 235 |
+
<h3 class="text-2xl font-bold text-white mb-3">ShopFast E-commerce</h3>
|
| 236 |
+
<p class="text-gray-300 leading-relaxed mb-4">
|
| 237 |
+
Plataforma de vendas online com checkout rápido, pagamentos integrados e painel administrativo completo.
|
| 238 |
+
</p>
|
| 239 |
+
</div>
|
| 240 |
+
|
| 241 |
+
<div class="space-y-3">
|
| 242 |
+
<div class="flex flex-wrap gap-2">
|
| 243 |
+
<span class="px-3 py-1 bg-purple-500/20 rounded-full text-purple-400 text-xs font-medium">Next.js</span>
|
| 244 |
+
<span class="px-3 py-1 bg-pink-500/20 rounded-full text-pink-400 text-xs font-medium">Stripe</span>
|
| 245 |
+
<span class="px-3 py-1 bg-green-500/20 rounded-full text-green-400 text-xs font-medium">Prisma</span>
|
| 246 |
+
</div>
|
| 247 |
+
<div class="flex items-center gap-2 text-gray-400 text-sm">
|
| 248 |
+
<i data-lucide="calendar" class="w-4 h-4"></i>
|
| 249 |
+
<span>Concluído em 2024</span>
|
| 250 |
+
</div>
|
| 251 |
+
</div>
|
| 252 |
+
</div>
|
| 253 |
+
</div>
|
| 254 |
+
</div>
|
| 255 |
+
|
| 256 |
+
<!-- PROJETO 3: Dashboard Analytics -->
|
| 257 |
+
<div class="group relative">
|
| 258 |
+
<div class="absolute inset-0 bg-linear-to-br from-green-500/20 to-emerald-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity"></div>
|
| 259 |
+
<div class="relative bg-linear-to-br from-green-600/20 to-emerald-600/20 rounded-2xl overflow-hidden border border-white/10 hover:border-green-500/30 transition-all h-full">
|
| 260 |
+
<div class="p-8 h-80 flex flex-col justify-between">
|
| 261 |
+
<div>
|
| 262 |
+
<div class="w-14 h-14 bg-green-500/20 rounded-xl flex items-center justify-center mb-4">
|
| 263 |
+
<i data-lucide="bar-chart-3" class="w-7 h-7 text-green-400"></i>
|
| 264 |
+
</div>
|
| 265 |
+
<h3 class="text-2xl font-bold text-white mb-3">DataMind Analytics</h3>
|
| 266 |
+
<p class="text-gray-300 leading-relaxed mb-4">
|
| 267 |
+
Dashboard inteligente com análise em tempo real, previsões e insights automatizados para decisões estratégicas.
|
| 268 |
+
</p>
|
| 269 |
+
</div>
|
| 270 |
+
|
| 271 |
+
<div class="space-y-3">
|
| 272 |
+
<div class="flex flex-wrap gap-2">
|
| 273 |
+
<span class="px-3 py-1 bg-green-500/20 rounded-full text-green-400 text-xs font-medium">React</span>
|
| 274 |
+
<span class="px-3 py-1 bg-yellow-500/20 rounded-full text-yellow-400 text-xs font-medium">Python</span>
|
| 275 |
+
<span class="px-3 py-1 bg-red-500/20 rounded-full text-red-400 text-xs font-medium">Redis</span>
|
| 276 |
+
</div>
|
| 277 |
+
<div class="flex items-center gap-2 text-gray-400 text-sm">
|
| 278 |
+
<i data-lucide="calendar" class="w-4 h-4"></i>
|
| 279 |
+
<span>Concluído em 2024</span>
|
| 280 |
+
</div>
|
| 281 |
+
</div>
|
| 282 |
+
</div>
|
| 283 |
+
</div>
|
| 284 |
+
</div>
|
| 285 |
+
|
| 286 |
+
<!-- PROJETO 4: App Mobile -->
|
| 287 |
+
<div class="group relative">
|
| 288 |
+
<div class="absolute inset-0 bg-linear-to-br from-orange-500/20 to-red-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity"></div>
|
| 289 |
+
<div class="relative bg-linear-to-br from-orange-600/20 to-red-600/20 rounded-2xl overflow-hidden border border-white/10 hover:border-orange-500/30 transition-all h-full">
|
| 290 |
+
<div class="p-8 h-80 flex flex-col justify-between">
|
| 291 |
+
<div>
|
| 292 |
+
<div class="w-14 h-14 bg-orange-500/20 rounded-xl flex items-center justify-center mb-4">
|
| 293 |
+
<i data-lucide="smartphone" class="w-7 h-7 text-orange-400"></i>
|
| 294 |
+
</div>
|
| 295 |
+
<h3 class="text-2xl font-bold text-white mb-3">ConnectPro Mobile</h3>
|
| 296 |
+
<p class="text-gray-300 leading-relaxed mb-4">
|
| 297 |
+
Aplicativo multiplataforma para iOS e Android com sincronização em nuvem e notificações em tempo real.
|
| 298 |
+
</p>
|
| 299 |
+
</div>
|
| 300 |
+
|
| 301 |
+
<div class="space-y-3">
|
| 302 |
+
<div class="flex flex-wrap gap-2">
|
| 303 |
+
<span class="px-3 py-1 bg-orange-500/20 rounded-full text-orange-400 text-xs font-medium">Flutter</span>
|
| 304 |
+
<span class="px-3 py-1 bg-blue-500/20 rounded-full text-blue-400 text-xs font-medium">Firebase</span>
|
| 305 |
+
</div>
|
| 306 |
+
<div class="flex items-center gap-2 text-gray-400 text-sm">
|
| 307 |
+
<i data-lucide="calendar" class="w-4 h-4"></i>
|
| 308 |
+
<span>Concluído em 2024</span>
|
| 309 |
+
</div>
|
| 310 |
+
</div>
|
| 311 |
+
</div>
|
| 312 |
+
</div>
|
| 313 |
+
</div>
|
| 314 |
+
|
| 315 |
+
<!-- PROJETO EM ANDAMENTO -->
|
| 316 |
+
<div class="sm:col-span-2 lg:col-span-2 group relative">
|
| 317 |
+
<div class="absolute inset-0 bg-linear-to-r from-blue-500/10 to-cyan-500/10 rounded-2xl blur-xl"></div>
|
| 318 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/10 rounded-2xl p-8 lg:p-12 text-center h-full flex flex-col justify-center">
|
| 319 |
+
<div class="w-16 h-16 bg-blue-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
| 320 |
+
<i data-lucide="code-2" class="w-8 h-8 text-blue-400 animate-pulse"></i>
|
| 321 |
+
</div>
|
| 322 |
+
<h3 class="text-2xl sm:text-3xl font-bold text-white mb-4">
|
| 323 |
+
Mais projetos em desenvolvimento...
|
| 324 |
+
</h3>
|
| 325 |
+
<p class="text-gray-300 text-lg mb-6 max-w-xl mx-auto">
|
| 326 |
+
Estamos trabalhando em novas soluções inovadoras. Em breve, mais projetos serão adicionados ao nosso portfolio.
|
| 327 |
+
</p>
|
| 328 |
+
<div class="flex items-center justify-center gap-2 text-gray-400">
|
| 329 |
+
<i data-lucide="clock" class="w-5 h-5"></i>
|
| 330 |
+
<span>2025 - Em andamento</span>
|
| 331 |
+
</div>
|
| 332 |
+
</div>
|
| 333 |
+
</div>
|
| 334 |
+
|
| 335 |
+
</div>
|
| 336 |
+
</div>
|
| 337 |
+
|
| 338 |
+
<!-- CTA FINAL -->
|
| 339 |
+
<div class="text-center mt-20 lg:mt-32">
|
| 340 |
+
<div class="relative">
|
| 341 |
+
<div class="absolute inset-0 bg-linear-to-r from-cyan-500/10 via-blue-500/10 to-purple-500/10 rounded-3xl blur-3xl"></div>
|
| 342 |
+
|
| 343 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/10 rounded-3xl p-8 lg:p-12">
|
| 344 |
+
<h2 class="text-3xl sm:text-4xl md:text-5xl font-bold text-white mb-6 leading-tight">
|
| 345 |
+
Quer ver seu projeto
|
| 346 |
+
<span class="block bg-linear-to-r from-cyan-400 to-blue-500 bg-clip-text text-transparent">
|
| 347 |
+
aqui no nosso portfolio?
|
| 348 |
+
</span>
|
| 349 |
+
</h2>
|
| 350 |
+
|
| 351 |
+
<p class="text-base sm:text-lg text-gray-300 max-w-2xl mx-auto mb-8 lg:mb-10">
|
| 352 |
+
Vamos criar algo incrível juntos. Entre em contato e transforme sua ideia em realidade.
|
| 353 |
+
</p>
|
| 354 |
+
|
| 355 |
+
<a href="feedback.php"
|
| 356 |
+
class="inline-flex items-center justify-center gap-3 bg-linear-to-r from-cyan-500 to-blue-600 text-white font-semibold text-lg px-10 py-4 rounded-full shadow-lg hover:shadow-cyan-500/50 hover:scale-105 transition-all duration-300 group">
|
| 357 |
+
Iniciar Meu Projeto
|
| 358 |
+
<i data-lucide="arrow-right" class="w-5 h-5 group-hover:translate-x-1 transition-transform"></i>
|
| 359 |
+
</a>
|
| 360 |
+
</div>
|
| 361 |
+
</div>
|
| 362 |
+
</div>
|
| 363 |
+
|
| 364 |
+
</div>
|
| 365 |
+
</main>
|
| 366 |
+
|
| 367 |
+
<?php include 'components/footer.php'; ?>
|
| 368 |
+
|
| 369 |
+
<!-- SCRIPTS -->
|
| 370 |
+
<script src="https://unpkg.com/lucide@latest"></script>
|
| 371 |
+
<script>
|
| 372 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 373 |
+
// Initialize Lucide icons
|
| 374 |
+
lucide.createIcons();
|
| 375 |
+
|
| 376 |
+
// Fade in animations on scroll
|
| 377 |
+
const observerOptions = {
|
| 378 |
+
threshold: 0.1,
|
| 379 |
+
rootMargin: '0px 0px -50px 0px'
|
| 380 |
+
};
|
| 381 |
+
|
| 382 |
+
const observer = new IntersectionObserver((entries) => {
|
| 383 |
+
entries.forEach(entry => {
|
| 384 |
+
if (entry.isIntersecting) {
|
| 385 |
+
entry.target.style.opacity = '1';
|
| 386 |
+
entry.target.style.transform = 'translateY(0)';
|
| 387 |
+
}
|
| 388 |
+
});
|
| 389 |
+
}, observerOptions);
|
| 390 |
+
|
| 391 |
+
// Observe all project cards
|
| 392 |
+
document.querySelectorAll('.group, section').forEach((el, index) => {
|
| 393 |
+
el.style.opacity = '0';
|
| 394 |
+
el.style.transform = 'translateY(20px)';
|
| 395 |
+
el.style.transition = `opacity 0.6s ease ${index * 0.1}s, transform 0.6s ease ${index * 0.1}s`;
|
| 396 |
+
observer.observe(el);
|
| 397 |
+
});
|
| 398 |
+
|
| 399 |
+
// Gallery lightbox effect (opcional)
|
| 400 |
+
document.querySelectorAll('[src*="akira"]').forEach(img => {
|
| 401 |
+
img.addEventListener('click', function() {
|
| 402 |
+
// Aqui você pode adicionar um lightbox modal se quiser
|
| 403 |
+
console.log('Imagem clicada:', this.src);
|
| 404 |
+
});
|
| 405 |
+
});
|
| 406 |
+
});
|
| 407 |
+
</script>
|
| 408 |
+
|
| 409 |
+
<style>
|
| 410 |
+
/* Gradient animation */
|
| 411 |
+
@keyframes gradient-shift {
|
| 412 |
+
0%, 100% {
|
| 413 |
+
background-position: 0% 50%;
|
| 414 |
+
}
|
| 415 |
+
50% {
|
| 416 |
+
background-position: 100% 50%;
|
| 417 |
+
}
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
.bg-linear-to-r,
|
| 421 |
+
.bg-linear-to-br {
|
| 422 |
+
background-size: 200% 200%;
|
| 423 |
+
animation: gradient-shift 8s ease infinite;
|
| 424 |
+
}
|
| 425 |
+
|
| 426 |
+
/* Image hover effects */
|
| 427 |
+
img {
|
| 428 |
+
will-change: transform;
|
| 429 |
+
}
|
| 430 |
+
|
| 431 |
+
/* Pulse animation for "em desenvolvimento" */
|
| 432 |
+
@keyframes pulse {
|
| 433 |
+
0%, 100% {
|
| 434 |
+
opacity: 1;
|
| 435 |
+
}
|
| 436 |
+
50% {
|
| 437 |
+
opacity: 0.5;
|
| 438 |
+
}
|
| 439 |
+
}
|
| 440 |
+
|
| 441 |
+
.animate-pulse {
|
| 442 |
+
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
| 443 |
+
}
|
| 444 |
+
</style>
|
react-demo.php
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
require_once __DIR__ . '/src/Bootstrap.php';
|
| 3 |
+
\SoftEdge\Env::load(__DIR__);
|
| 4 |
+
\SoftEdge\Bootstrap::init();
|
| 5 |
+
include 'components/header.php';
|
| 6 |
+
?>
|
| 7 |
+
|
| 8 |
+
<!-- REACT DEMO PAGE -->
|
| 9 |
+
<section class="relative min-h-screen flex items-center justify-center overflow-hidden">
|
| 10 |
+
<!-- Background -->
|
| 11 |
+
<div class="absolute inset-0 -z-10">
|
| 12 |
+
<div class="absolute inset-0 bg-linear-to-br from-slate-950 via-slate-900 to-slate-950"></div>
|
| 13 |
+
<div class="absolute inset-0 opacity-30">
|
| 14 |
+
<div class="absolute top-20 left-20 w-96 h-96 bg-cyan-500/20 rounded-full blur-3xl"></div>
|
| 15 |
+
<div class="absolute bottom-20 right-20 w-96 h-96 bg-blue-500/20 rounded-full blur-3xl"></div>
|
| 16 |
+
</div>
|
| 17 |
+
</div>
|
| 18 |
+
|
| 19 |
+
<!-- Content -->
|
| 20 |
+
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20">
|
| 21 |
+
<div class="text-center space-y-12">
|
| 22 |
+
|
| 23 |
+
<!-- Badge -->
|
| 24 |
+
<div class="inline-block px-4 py-2 bg-cyan-500/10 rounded-full border border-cyan-500/20 backdrop-blur-sm">
|
| 25 |
+
<span class="text-cyan-400 text-sm font-semibold uppercase tracking-wider">
|
| 26 |
+
⚛️ React Integration Demo
|
| 27 |
+
</span>
|
| 28 |
+
</div>
|
| 29 |
+
|
| 30 |
+
<!-- Title -->
|
| 31 |
+
<div class="space-y-6">
|
| 32 |
+
<h1 class="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold leading-tight">
|
| 33 |
+
<span class="block text-white mb-2">React + PHP</span>
|
| 34 |
+
<span class="block bg-linear-to-r from-cyan-400 via-blue-500 to-purple-500 bg-clip-text text-transparent">
|
| 35 |
+
Integração Completa
|
| 36 |
+
</span>
|
| 37 |
+
</h1>
|
| 38 |
+
|
| 39 |
+
<p class="text-base sm:text-lg md:text-xl text-gray-300 max-w-2xl mx-auto leading-relaxed">
|
| 40 |
+
Demonstração da integração perfeita entre React e PHP no SoftEdge Corporation website.
|
| 41 |
+
<br class="hidden sm:block">
|
| 42 |
+
Componentes modulares, estado compartilhado e performance otimizada.
|
| 43 |
+
</p>
|
| 44 |
+
</div>
|
| 45 |
+
|
| 46 |
+
<!-- React App Container -->
|
| 47 |
+
<div class="max-w-4xl mx-auto">
|
| 48 |
+
<div class="relative">
|
| 49 |
+
<div class="absolute inset-0 bg-linear-to-r from-cyan-500/10 via-blue-500/10 to-purple-500/10 rounded-3xl blur-3xl"></div>
|
| 50 |
+
|
| 51 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/10 rounded-3xl p-8">
|
| 52 |
+
<!-- React App will be mounted here -->
|
| 53 |
+
<div id="root" class="min-h-[400px] flex items-center justify-center">
|
| 54 |
+
<div class="text-center space-y-4">
|
| 55 |
+
<div class="w-16 h-16 bg-cyan-500/20 rounded-full flex items-center justify-center mx-auto animate-pulse">
|
| 56 |
+
<i data-lucide="loader-2" class="w-8 h-8 text-cyan-400 animate-spin"></i>
|
| 57 |
+
</div>
|
| 58 |
+
<p class="text-gray-400">Carregando aplicação React...</p>
|
| 59 |
+
</div>
|
| 60 |
+
</div>
|
| 61 |
+
|
| 62 |
+
<!-- Fallback for when React is not loaded -->
|
| 63 |
+
<noscript>
|
| 64 |
+
<div class="text-center py-8">
|
| 65 |
+
<i data-lucide="alert-triangle" class="w-16 h-16 text-yellow-400 mx-auto mb-4"></i>
|
| 66 |
+
<h3 class="text-xl font-bold text-white mb-2">JavaScript Necessário</h3>
|
| 67 |
+
<p class="text-gray-400">Esta página requer JavaScript para funcionar corretamente.</p>
|
| 68 |
+
</div>
|
| 69 |
+
</noscript>
|
| 70 |
+
</div>
|
| 71 |
+
</div>
|
| 72 |
+
</div>
|
| 73 |
+
|
| 74 |
+
<!-- Info Cards -->
|
| 75 |
+
<div class="grid sm:grid-cols-3 gap-6 lg:gap-8 mt-16 max-w-4xl mx-auto">
|
| 76 |
+
<!-- Info 1 -->
|
| 77 |
+
<div class="text-center">
|
| 78 |
+
<div class="w-12 h-12 bg-cyan-500/10 rounded-xl flex items-center justify-center mx-auto mb-4">
|
| 79 |
+
<i data-lucide="zap" class="w-6 h-6 text-cyan-400"></i>
|
| 80 |
+
</div>
|
| 81 |
+
<h3 class="text-white font-semibold mb-2">Performance</h3>
|
| 82 |
+
<p class="text-gray-400 text-sm">Componentes otimizados com lazy loading</p>
|
| 83 |
+
</div>
|
| 84 |
+
|
| 85 |
+
<!-- Info 2 -->
|
| 86 |
+
<div class="text-center">
|
| 87 |
+
<div class="w-12 h-12 bg-blue-500/10 rounded-xl flex items-center justify-center mx-auto mb-4">
|
| 88 |
+
<i data-lucide="code-2" class="w-6 h-6 text-blue-400"></i>
|
| 89 |
+
</div>
|
| 90 |
+
<h3 class="text-white font-semibold mb-2">Modular</h3>
|
| 91 |
+
<p class="text-gray-400 text-sm">Componentes reutilizáveis e manuteníveis</p>
|
| 92 |
+
</div>
|
| 93 |
+
|
| 94 |
+
<!-- Info 3 -->
|
| 95 |
+
<div class="text-center">
|
| 96 |
+
<div class="w-12 h-12 bg-purple-500/10 rounded-xl flex items-center justify-center mx-auto mb-4">
|
| 97 |
+
<i data-lucide="refresh-cw" class="w-6 h-6 text-purple-400"></i>
|
| 98 |
+
</div>
|
| 99 |
+
<h3 class="text-white font-semibold mb-2">Dinâmico</h3>
|
| 100 |
+
<p class="text-gray-400 text-sm">Estado reativo e interações fluidas</p>
|
| 101 |
+
</div>
|
| 102 |
+
</div>
|
| 103 |
+
|
| 104 |
+
<!-- Back to Home -->
|
| 105 |
+
<div class="pt-12">
|
| 106 |
+
<a href="index.php" class="inline-flex items-center gap-2 text-cyan-400 hover:text-cyan-300 transition-colors group">
|
| 107 |
+
<i data-lucide="arrow-left" class="w-5 h-5 group-hover:-translate-x-1 transition-transform"></i>
|
| 108 |
+
<span>Voltar ao início</span>
|
| 109 |
+
</a>
|
| 110 |
+
</div>
|
| 111 |
+
|
| 112 |
+
</div>
|
| 113 |
+
</div>
|
| 114 |
+
</section>
|
| 115 |
+
|
| 116 |
+
<!-- Load React App -->
|
| 117 |
+
<script>
|
| 118 |
+
// Load React app when DOM is ready
|
| 119 |
+
document.addEventListener('DOMContentLoaded', function() {
|
| 120 |
+
// Check if React bundle exists
|
| 121 |
+
fetch('/dist/main.js')
|
| 122 |
+
.then(response => {
|
| 123 |
+
if (response.ok) {
|
| 124 |
+
// Load React bundle
|
| 125 |
+
const script = document.createElement('script');
|
| 126 |
+
script.src = '/dist/main.js';
|
| 127 |
+
script.onload = function() {
|
| 128 |
+
console.log('React app loaded successfully');
|
| 129 |
+
};
|
| 130 |
+
script.onerror = function() {
|
| 131 |
+
console.error('Failed to load React app');
|
| 132 |
+
showFallback();
|
| 133 |
+
};
|
| 134 |
+
document.head.appendChild(script);
|
| 135 |
+
} else {
|
| 136 |
+
console.warn('React bundle not found, showing fallback');
|
| 137 |
+
showFallback();
|
| 138 |
+
}
|
| 139 |
+
})
|
| 140 |
+
.catch(error => {
|
| 141 |
+
console.error('Error checking React bundle:', error);
|
| 142 |
+
showFallback();
|
| 143 |
+
});
|
| 144 |
+
});
|
| 145 |
+
|
| 146 |
+
function showFallback() {
|
| 147 |
+
const root = document.getElementById('root');
|
| 148 |
+
if (root) {
|
| 149 |
+
root.innerHTML = `
|
| 150 |
+
<div class="text-center space-y-4">
|
| 151 |
+
<div class="w-16 h-16 bg-yellow-500/20 rounded-full flex items-center justify-center mx-auto">
|
| 152 |
+
<i data-lucide="alert-triangle" class="w-8 h-8 text-yellow-400"></i>
|
| 153 |
+
</div>
|
| 154 |
+
<h3 class="text-xl font-bold text-white">React App Indisponível</h3>
|
| 155 |
+
<p class="text-gray-400 text-sm">O aplicativo React não foi carregado. Execute <code class="bg-slate-800 px-2 py-1 rounded text-xs">npm run build</code> para gerar os arquivos.</p>
|
| 156 |
+
</div>
|
| 157 |
+
`;
|
| 158 |
+
}
|
| 159 |
+
}
|
| 160 |
+
</script>
|
| 161 |
+
|
| 162 |
+
<?php include 'components/footer.php'; ?>
|
| 163 |
+
|
| 164 |
+
<!-- SCRIPTS -->
|
| 165 |
+
<script src="https://unpkg.com/lucide@latest"></script>
|
| 166 |
+
<script>
|
| 167 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 168 |
+
// Initialize Lucide icons
|
| 169 |
+
lucide.createIcons();
|
| 170 |
+
});
|
| 171 |
+
</script>
|
| 172 |
+
|
| 173 |
+
<style>
|
| 174 |
+
/* Custom styles for React integration */
|
| 175 |
+
#root {
|
| 176 |
+
transition: opacity 0.3s ease;
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
#root.fade-in {
|
| 180 |
+
opacity: 1;
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
/* Loading animation */
|
| 184 |
+
@keyframes spin {
|
| 185 |
+
from { transform: rotate(0deg); }
|
| 186 |
+
to { transform: rotate(360deg); }
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
.animate-spin {
|
| 190 |
+
animation: spin 1s linear infinite;
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
/* Gradient animation */
|
| 194 |
+
@keyframes gradient-shift {
|
| 195 |
+
0%, 100% {
|
| 196 |
+
background-position: 0% 50%;
|
| 197 |
+
}
|
| 198 |
+
50% {
|
| 199 |
+
background-position: 100% 50%;
|
| 200 |
+
}
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
.bg-linear-to-r {
|
| 204 |
+
background-size: 200% 200%;
|
| 205 |
+
animation: gradient-shift 8s ease infinite;
|
| 206 |
+
}
|
| 207 |
+
</style>
|
react-fallback.html
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="pt-BR">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>SoftEdge Corporation - React Fallback</title>
|
| 7 |
+
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
|
| 8 |
+
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
|
| 9 |
+
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
| 10 |
+
<style>
|
| 11 |
+
body {
|
| 12 |
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
| 13 |
+
margin: 0;
|
| 14 |
+
padding: 20px;
|
| 15 |
+
background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #0f172a 100%);
|
| 16 |
+
color: white;
|
| 17 |
+
min-height: 100vh;
|
| 18 |
+
}
|
| 19 |
+
.container {
|
| 20 |
+
max-width: 800px;
|
| 21 |
+
margin: 0 auto;
|
| 22 |
+
background: rgba(30, 41, 59, 0.8);
|
| 23 |
+
border-radius: 12px;
|
| 24 |
+
padding: 30px;
|
| 25 |
+
backdrop-filter: blur(10px);
|
| 26 |
+
border: 1px solid rgba(148, 163, 184, 0.1);
|
| 27 |
+
}
|
| 28 |
+
.header {
|
| 29 |
+
text-align: center;
|
| 30 |
+
margin-bottom: 30px;
|
| 31 |
+
}
|
| 32 |
+
.nav {
|
| 33 |
+
display: flex;
|
| 34 |
+
gap: 10px;
|
| 35 |
+
margin-bottom: 20px;
|
| 36 |
+
flex-wrap: wrap;
|
| 37 |
+
}
|
| 38 |
+
.nav-btn {
|
| 39 |
+
padding: 8px 16px;
|
| 40 |
+
background: rgba(6, 182, 212, 0.1);
|
| 41 |
+
border: 1px solid rgba(6, 182, 212, 0.3);
|
| 42 |
+
border-radius: 6px;
|
| 43 |
+
color: #06b6d4;
|
| 44 |
+
cursor: pointer;
|
| 45 |
+
transition: all 0.3s ease;
|
| 46 |
+
}
|
| 47 |
+
.nav-btn.active {
|
| 48 |
+
background: #06b6d4;
|
| 49 |
+
color: white;
|
| 50 |
+
}
|
| 51 |
+
.content {
|
| 52 |
+
background: rgba(15, 23, 42, 0.5);
|
| 53 |
+
border-radius: 8px;
|
| 54 |
+
padding: 20px;
|
| 55 |
+
min-height: 200px;
|
| 56 |
+
}
|
| 57 |
+
.feature-grid {
|
| 58 |
+
display: grid;
|
| 59 |
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
| 60 |
+
gap: 20px;
|
| 61 |
+
margin-top: 20px;
|
| 62 |
+
}
|
| 63 |
+
.feature-card {
|
| 64 |
+
background: rgba(30, 41, 59, 0.6);
|
| 65 |
+
padding: 20px;
|
| 66 |
+
border-radius: 8px;
|
| 67 |
+
border: 1px solid rgba(148, 163, 184, 0.1);
|
| 68 |
+
text-align: center;
|
| 69 |
+
}
|
| 70 |
+
.feature-card h3 {
|
| 71 |
+
color: #06b6d4;
|
| 72 |
+
margin-bottom: 10px;
|
| 73 |
+
}
|
| 74 |
+
</style>
|
| 75 |
+
</head>
|
| 76 |
+
<body>
|
| 77 |
+
<div id="root"></div>
|
| 78 |
+
|
| 79 |
+
<script type="text/babel">
|
| 80 |
+
const { useState, useEffect } = React;
|
| 81 |
+
|
| 82 |
+
function App() {
|
| 83 |
+
const [currentSection, setCurrentSection] = useState('home');
|
| 84 |
+
const [isVisible, setIsVisible] = useState(false);
|
| 85 |
+
|
| 86 |
+
useEffect(() => {
|
| 87 |
+
setTimeout(() => setIsVisible(true), 100);
|
| 88 |
+
}, []);
|
| 89 |
+
|
| 90 |
+
const sections = [
|
| 91 |
+
{ id: 'home', label: 'Início', icon: '🏠' },
|
| 92 |
+
{ id: 'services', label: 'Serviços', icon: '⚙️' },
|
| 93 |
+
{ id: 'projects', label: 'Projetos', icon: '📁' },
|
| 94 |
+
{ id: 'about', label: 'Sobre', icon: '👥' },
|
| 95 |
+
{ id: 'contact', label: 'Contato', icon: '📧' }
|
| 96 |
+
];
|
| 97 |
+
|
| 98 |
+
const renderContent = () => {
|
| 99 |
+
switch (currentSection) {
|
| 100 |
+
case 'home':
|
| 101 |
+
return (
|
| 102 |
+
<div>
|
| 103 |
+
<h2>🚀 Bem-vindo à SoftEdge Corporation</h2>
|
| 104 |
+
<p>Transformamos ideias em soluções digitais inovadoras.</p>
|
| 105 |
+
<div className="feature-grid">
|
| 106 |
+
<div className="feature-card">
|
| 107 |
+
<h3>⚡ Performance</h3>
|
| 108 |
+
<p>Soluções otimizadas para máxima velocidade</p>
|
| 109 |
+
</div>
|
| 110 |
+
<div className="feature-card">
|
| 111 |
+
<h3>🔒 Segurança</h3>
|
| 112 |
+
<p>Proteção avançada e melhores práticas</p>
|
| 113 |
+
</div>
|
| 114 |
+
<div className="feature-card">
|
| 115 |
+
<h3>📱 Responsivo</h3>
|
| 116 |
+
<p>Experiência perfeita em todos os dispositivos</p>
|
| 117 |
+
</div>
|
| 118 |
+
</div>
|
| 119 |
+
</div>
|
| 120 |
+
);
|
| 121 |
+
|
| 122 |
+
case 'services':
|
| 123 |
+
return (
|
| 124 |
+
<div>
|
| 125 |
+
<h2>💼 Nossos Serviços</h2>
|
| 126 |
+
<div className="feature-grid">
|
| 127 |
+
<div className="feature-card">
|
| 128 |
+
<h3>💻 Desenvolvimento Web</h3>
|
| 129 |
+
<p>Sites, sistemas e aplicações web modernas</p>
|
| 130 |
+
</div>
|
| 131 |
+
<div className="feature-card">
|
| 132 |
+
<h3>📱 Apps Mobile</h3>
|
| 133 |
+
<p>Aplicativos nativos e híbridos</p>
|
| 134 |
+
</div>
|
| 135 |
+
<div className="feature-card">
|
| 136 |
+
<h3>🤖 IA & Automação</h3>
|
| 137 |
+
<p>Inteligência artificial e processos automatizados</p>
|
| 138 |
+
</div>
|
| 139 |
+
<div className="feature-card">
|
| 140 |
+
<h3>☁️ Cloud Solutions</h3>
|
| 141 |
+
<p>Migração e otimização para nuvem</p>
|
| 142 |
+
</div>
|
| 143 |
+
</div>
|
| 144 |
+
</div>
|
| 145 |
+
);
|
| 146 |
+
|
| 147 |
+
case 'projects':
|
| 148 |
+
return (
|
| 149 |
+
<div>
|
| 150 |
+
<h2>📂 Nossos Projetos</h2>
|
| 151 |
+
<div className="feature-grid">
|
| 152 |
+
<div className="feature-card">
|
| 153 |
+
<h3>AKIRA IA</h3>
|
| 154 |
+
<p>Assistente virtual inteligente</p>
|
| 155 |
+
<div style={{marginTop: '10px'}}>
|
| 156 |
+
<span style={{background: 'rgba(6, 182, 212, 0.2)', padding: '2px 8px', borderRadius: '4px', fontSize: '12px', color: '#06b6d4'}}>Python</span>
|
| 157 |
+
<span style={{background: 'rgba(168, 85, 247, 0.2)', padding: '2px 8px', borderRadius: '4px', fontSize: '12px', color: '#a855f7', marginLeft: '5px'}}>TensorFlow</span>
|
| 158 |
+
</div>
|
| 159 |
+
</div>
|
| 160 |
+
<div className="feature-card">
|
| 161 |
+
<h3>ERP Gestão Total</h3>
|
| 162 |
+
<p>Sistema completo de gestão empresarial</p>
|
| 163 |
+
<div style={{marginTop: '10px'}}>
|
| 164 |
+
<span style={{background: 'rgba(239, 68, 68, 0.2)', padding: '2px 8px', borderRadius: '4px', fontSize: '12px', color: '#ef4444'}}>Laravel</span>
|
| 165 |
+
<span style={{background: 'rgba(59, 130, 246, 0.2)', padding: '2px 8px', borderRadius: '4px', fontSize: '12px', color: '#3b82f6', marginLeft: '5px'}}>Vue.js</span>
|
| 166 |
+
</div>
|
| 167 |
+
</div>
|
| 168 |
+
<div className="feature-card">
|
| 169 |
+
<h3>E-commerce ShopFast</h3>
|
| 170 |
+
<p>Plataforma de vendas online</p>
|
| 171 |
+
<div style={{marginTop: '10px'}}>
|
| 172 |
+
<span style={{background: 'rgba(0, 0, 0, 0.2)', padding: '2px 8px', borderRadius: '4px', fontSize: '12px', color: '#ffffff'}}>Next.js</span>
|
| 173 |
+
<span style={{background: 'rgba(139, 92, 246, 0.2)', padding: '2px 8px', borderRadius: '4px', fontSize: '12px', color: '#8b5cf6', marginLeft: '5px'}}>Stripe</span>
|
| 174 |
+
</div>
|
| 175 |
+
</div>
|
| 176 |
+
</div>
|
| 177 |
+
</div>
|
| 178 |
+
);
|
| 179 |
+
|
| 180 |
+
case 'about':
|
| 181 |
+
return (
|
| 182 |
+
<div>
|
| 183 |
+
<h2>👥 Sobre Nós</h2>
|
| 184 |
+
<p>Somos uma equipe apaixonada por tecnologia, criando soluções inovadoras desde 2023.</p>
|
| 185 |
+
<div style={{marginTop: '20px'}}>
|
| 186 |
+
<h3 style={{color: '#06b6d4', marginBottom: '15px'}}>Nossa Equipe</h3>
|
| 187 |
+
<div style={{display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(150px, 1fr))', gap: '15px'}}>
|
| 188 |
+
<div style={{textAlign: 'center'}}>
|
| 189 |
+
<div style={{width: '50px', height: '50px', background: 'rgba(6, 182, 212, 0.2)', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 10px', fontSize: '20px'}}>I</div>
|
| 190 |
+
<div><strong>Isaac Quarenta</strong></div>
|
| 191 |
+
<div style={{fontSize: '14px', color: '#94a3b8'}}>CEO & Developer</div>
|
| 192 |
+
</div>
|
| 193 |
+
<div style={{textAlign: 'center'}}>
|
| 194 |
+
<div style={{width: '50px', height: '50px', background: 'rgba(168, 85, 247, 0.2)', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 10px', fontSize: '20px'}}>J</div>
|
| 195 |
+
<div><strong>José Lopes</strong></div>
|
| 196 |
+
<div style={{fontSize: '14px', color: '#94a3b8'}}>Full Stack Dev</div>
|
| 197 |
+
</div>
|
| 198 |
+
<div style={{textAlign: 'center'}}>
|
| 199 |
+
<div style={{width: '50px', height: '50px', background: 'rgba(236, 72, 153, 0.2)', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 10px', fontSize: '20px'}}>S</div>
|
| 200 |
+
<div><strong>Stefânio Costa</strong></div>
|
| 201 |
+
<div style={{fontSize: '14px', color: '#94a3b8'}}>Designer & Frontend</div>
|
| 202 |
+
</div>
|
| 203 |
+
<div style={{textAlign: 'center'}}>
|
| 204 |
+
<div style={{width: '50px', height: '50px', background: 'rgba(34, 197, 94, 0.2)', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 10px', fontSize: '20px'}}>T</div>
|
| 205 |
+
<div><strong>Tiago Rodrigues</strong></div>
|
| 206 |
+
<div style={{fontSize: '14px', color: '#94a3b8'}}>DevOps & Backend</div>
|
| 207 |
+
</div>
|
| 208 |
+
</div>
|
| 209 |
+
</div>
|
| 210 |
+
</div>
|
| 211 |
+
);
|
| 212 |
+
|
| 213 |
+
case 'contact':
|
| 214 |
+
return (
|
| 215 |
+
<div>
|
| 216 |
+
<h2>📧 Entre em Contato</h2>
|
| 217 |
+
<p>Estamos prontos para transformar sua ideia em realidade!</p>
|
| 218 |
+
<div style={{marginTop: '20px', display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '20px'}}>
|
| 219 |
+
<div style={{background: 'rgba(6, 182, 212, 0.1)', padding: '20px', borderRadius: '8px', border: '1px solid rgba(6, 182, 212, 0.2)'}}>
|
| 220 |
+
<h3 style={{color: '#06b6d4', marginBottom: '10px'}}>💬 WhatsApp</h3>
|
| 221 |
+
<p style={{fontSize: '14px', color: '#94a3b8'}}>Converse conosco em tempo real</p>
|
| 222 |
+
<a href="https://whatsapp.com/channel/0029VawQLpGHltY2Y87fR83m" target="_blank" style={{color: '#06b6d4', textDecoration: 'none'}}>Entrar no canal →</a>
|
| 223 |
+
</div>
|
| 224 |
+
<div style={{background: 'rgba(168, 85, 247, 0.1)', padding: '20px', borderRadius: '8px', border: '1px solid rgba(168, 85, 247, 0.2)'}}>
|
| 225 |
+
<h3 style={{color: '#a855f7', marginBottom: '10px'}}>📧 Email</h3>
|
| 226 |
+
<p style={{fontSize: '14px', color: '#94a3b8'}}>Envie-nos uma mensagem</p>
|
| 227 |
+
<a href="mailto:softedgecorporation@gmail.com" style={{color: '#a855f7', textDecoration: 'none'}}>Enviar email →</a>
|
| 228 |
+
</div>
|
| 229 |
+
</div>
|
| 230 |
+
</div>
|
| 231 |
+
);
|
| 232 |
+
|
| 233 |
+
default:
|
| 234 |
+
return <div><h2>Seção não encontrada</h2></div>;
|
| 235 |
+
}
|
| 236 |
+
};
|
| 237 |
+
|
| 238 |
+
return (
|
| 239 |
+
<div className={`app ${isVisible ? 'visible' : ''}`} style={{opacity: isVisible ? 1 : 0, transition: 'opacity 0.5s ease'}}>
|
| 240 |
+
<div className="container">
|
| 241 |
+
<div className="header">
|
| 242 |
+
<h1 style={{color: '#06b6d4', marginBottom: '10px'}}>🚀 SoftEdge Corporation</h1>
|
| 243 |
+
<p style={{color: '#94a3b8'}}>React + PHP Integration Demo</p>
|
| 244 |
+
</div>
|
| 245 |
+
|
| 246 |
+
<nav className="nav">
|
| 247 |
+
{sections.map(section => (
|
| 248 |
+
<button
|
| 249 |
+
key={section.id}
|
| 250 |
+
className={`nav-btn ${currentSection === section.id ? 'active' : ''}`}
|
| 251 |
+
onClick={() => setCurrentSection(section.id)}
|
| 252 |
+
>
|
| 253 |
+
<span style={{marginRight: '5px'}}>{section.icon}</span>
|
| 254 |
+
{section.label}
|
| 255 |
+
</button>
|
| 256 |
+
))}
|
| 257 |
+
</nav>
|
| 258 |
+
|
| 259 |
+
<div className="content">
|
| 260 |
+
{renderContent()}
|
| 261 |
+
</div>
|
| 262 |
+
|
| 263 |
+
<div style={{textAlign: 'center', marginTop: '30px', paddingTop: '20px', borderTop: '1px solid rgba(148, 163, 184, 0.1)'}}>
|
| 264 |
+
<p style={{color: '#94a3b8', fontSize: '14px'}}>
|
| 265 |
+
React + PHP = 💪 Potência Total • SoftEdge Corporation 2025
|
| 266 |
+
</p>
|
| 267 |
+
</div>
|
| 268 |
+
</div>
|
| 269 |
+
</div>
|
| 270 |
+
);
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
const root = ReactDOM.createRoot(document.getElementById('root'));
|
| 274 |
+
root.render(<App />);
|
| 275 |
+
</script>
|
| 276 |
+
</body>
|
| 277 |
+
</html>
|
register.php
ADDED
|
File without changes
|
render.yaml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
services:
|
| 2 |
+
- type: web
|
| 3 |
+
name: softedge-corporation
|
| 4 |
+
runtime: docker
|
| 5 |
+
dockerfilePath: ./Dockerfile
|
| 6 |
+
healthCheckPath: /health.php
|
| 7 |
+
envVars:
|
| 8 |
+
- key: PORT
|
| 9 |
+
value: 10000
|
| 10 |
+
- key: RENDER
|
| 11 |
+
value: true
|
| 12 |
+
plan: starter
|
| 13 |
+
autoDeploy: true
|
| 14 |
+
buildFilter:
|
| 15 |
+
paths:
|
| 16 |
+
- "**"
|
| 17 |
+
ignoredPaths:
|
| 18 |
+
- "logs/**"
|
| 19 |
+
- ".git/**"
|
| 20 |
+
- "README.md"
|
| 21 |
+
- "*.md"
|
| 22 |
+
disk:
|
| 23 |
+
name: softedge-data
|
| 24 |
+
mountPath: /var/www/html/logs
|
| 25 |
+
sizeGB: 1
|
requirements.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Flask==2.3.3
|
| 2 |
+
Werkzeug==2.3.7
|
| 3 |
+
gunicorn==21.2.0
|
| 4 |
+
requests==2.31.0
|
servicos.php
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
require_once __DIR__ . '/src/Bootstrap.php';
|
| 3 |
+
\SoftEdge\Env::load(__DIR__);
|
| 4 |
+
\SoftEdge\Bootstrap::init();
|
| 5 |
+
include 'components/header.php';
|
| 6 |
+
?>
|
| 7 |
+
|
| 8 |
+
<!-- HERO SECTION -->
|
| 9 |
+
<section class="relative pt-32 pb-20 overflow-hidden">
|
| 10 |
+
<!-- Background -->
|
| 11 |
+
<div class="absolute inset-0 -z-10">
|
| 12 |
+
<div class="absolute inset-0 bg-linear-to-br from-slate-950 via-slate-900 to-slate-950"></div>
|
| 13 |
+
<div class="absolute inset-0 opacity-30">
|
| 14 |
+
<div class="absolute top-20 left-20 w-96 h-96 bg-purple-500/20 rounded-full blur-3xl"></div>
|
| 15 |
+
<div class="absolute bottom-20 right-20 w-96 h-96 bg-cyan-500/20 rounded-full blur-3xl"></div>
|
| 16 |
+
</div>
|
| 17 |
+
</div>
|
| 18 |
+
|
| 19 |
+
<!-- Content -->
|
| 20 |
+
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
| 21 |
+
<div class="space-y-6">
|
| 22 |
+
<div class="inline-block px-4 py-2 bg-slate-700 border border-slate-600 mb-4">
|
| 23 |
+
<span class="text-slate-300 text-sm font-medium uppercase tracking-wide">Nossos Serviços</span>
|
| 24 |
+
</div>
|
| 25 |
+
|
| 26 |
+
<h1 class="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold leading-tight">
|
| 27 |
+
Transformamos suas ideias em
|
| 28 |
+
<span class="block text-slate-300">
|
| 29 |
+
soluções digitais
|
| 30 |
+
</span>
|
| 31 |
+
</h1>
|
| 32 |
+
|
| 33 |
+
<p class="text-base sm:text-lg md:text-xl text-slate-400 max-w-3xl mx-auto leading-relaxed">
|
| 34 |
+
Da consultoria ao desenvolvimento completo, oferecemos tudo o que você precisa para ter sucesso no mundo digital.
|
| 35 |
+
</p>
|
| 36 |
+
</div>
|
| 37 |
+
</div>
|
| 38 |
+
</section>
|
| 39 |
+
|
| 40 |
+
<!-- SERVIÇOS GRID -->
|
| 41 |
+
<main class="relative py-20 lg:py-32">
|
| 42 |
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
| 43 |
+
|
| 44 |
+
<div class="grid sm:grid-cols-2 lg:grid-cols-2 gap-6 lg:gap-8">
|
| 45 |
+
|
| 46 |
+
<!-- SERVIÇO 1 - DESENVOLVIMENTO FULL STACK -->
|
| 47 |
+
<div class="group relative">
|
| 48 |
+
<div class="absolute inset-0 bg-linear-to-br from-cyan-500/20 to-blue-500/20 rounded-3xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
| 49 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/5 rounded-3xl p-8 lg:p-10 transition-all duration-500 hover:border-cyan-500/30 h-full flex flex-col">
|
| 50 |
+
|
| 51 |
+
<!-- Icon -->
|
| 52 |
+
<div class="w-16 h-16 bg-linear-to-br from-cyan-500 to-blue-600 rounded-2xl flex items-center justify-center mb-6 shadow-lg group-hover:scale-110 transition-transform">
|
| 53 |
+
<i data-lucide="code-2" class="w-8 h-8 text-white"></i>
|
| 54 |
+
</div>
|
| 55 |
+
|
| 56 |
+
<!-- Title -->
|
| 57 |
+
<h3 class="text-2xl sm:text-3xl font-bold text-white mb-4">
|
| 58 |
+
Desenvolvimento Full Stack
|
| 59 |
+
</h3>
|
| 60 |
+
|
| 61 |
+
<!-- Description -->
|
| 62 |
+
<p class="text-gray-300 text-base leading-relaxed mb-6 grow">
|
| 63 |
+
Criamos aplicações web, mobile e desktop personalizadas para o seu negócio. Utilizamos as tecnologias mais modernas como React, Next.js, Node.js, Laravel, Flutter, PHP 8+, bancos SQL/NoSQL e muito mais.
|
| 64 |
+
</p>
|
| 65 |
+
|
| 66 |
+
<!-- Features List -->
|
| 67 |
+
<ul class="space-y-3">
|
| 68 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 69 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-cyan-400 shrink-0 mt-0.5"></i>
|
| 70 |
+
<span>APIs REST & GraphQL profissionais</span>
|
| 71 |
+
</li>
|
| 72 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 73 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-cyan-400 shrink-0 mt-0.5"></i>
|
| 74 |
+
<span>Progressive Web Apps (PWA) rápidos</span>
|
| 75 |
+
</li>
|
| 76 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 77 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-cyan-400 shrink-0 mt-0.5"></i>
|
| 78 |
+
<span>Integração com serviços externos</span>
|
| 79 |
+
</li>
|
| 80 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 81 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-cyan-400 shrink-0 mt-0.5"></i>
|
| 82 |
+
<span>Deploy automático e escalável</span>
|
| 83 |
+
</li>
|
| 84 |
+
</ul>
|
| 85 |
+
</div>
|
| 86 |
+
</div>
|
| 87 |
+
|
| 88 |
+
<!-- SERVIÇO 2 - SISTEMAS SOB MEDIDA -->
|
| 89 |
+
<div class="group relative">
|
| 90 |
+
<div class="absolute inset-0 bg-linear-to-br from-purple-500/20 to-pink-500/20 rounded-3xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
| 91 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/5 rounded-3xl p-8 lg:p-10 transition-all duration-500 hover:border-purple-500/30 h-full flex flex-col">
|
| 92 |
+
|
| 93 |
+
<!-- Icon -->
|
| 94 |
+
<div class="w-16 h-16 bg-linear-to-br from-purple-500 to-pink-600 rounded-2xl flex items-center justify-center mb-6 shadow-lg group-hover:scale-110 transition-transform">
|
| 95 |
+
<i data-lucide="layout-dashboard" class="w-8 h-8 text-white"></i>
|
| 96 |
+
</div>
|
| 97 |
+
|
| 98 |
+
<!-- Title -->
|
| 99 |
+
<h3 class="text-2xl sm:text-3xl font-bold text-white mb-4">
|
| 100 |
+
Sistemas Sob Medida
|
| 101 |
+
</h3>
|
| 102 |
+
|
| 103 |
+
<!-- Description -->
|
| 104 |
+
<p class="text-gray-300 text-base leading-relaxed mb-6 grow">
|
| 105 |
+
Desenvolvemos ERPs, CRMs, sistemas de gestão financeira, controle de estoque, portais internos e dashboards analíticos 100% personalizados para atender às necessidades específicas do seu negócio.
|
| 106 |
+
</p>
|
| 107 |
+
|
| 108 |
+
<!-- Features List -->
|
| 109 |
+
<ul class="space-y-3">
|
| 110 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 111 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-purple-400 shrink-0 mt-0.5"></i>
|
| 112 |
+
<span>Totalmente escalável e flexível</span>
|
| 113 |
+
</li>
|
| 114 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 115 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-purple-400 shrink-0 mt-0.5"></i>
|
| 116 |
+
<span>Multiplataforma (web + mobile + desktop)</span>
|
| 117 |
+
</li>
|
| 118 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 119 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-purple-400 shrink-0 mt-0.5"></i>
|
| 120 |
+
<span>Integração com ferramentas existentes</span>
|
| 121 |
+
</li>
|
| 122 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 123 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-purple-400 shrink-0 mt-0.5"></i>
|
| 124 |
+
<span>Suporte técnico 24/7 incluído</span>
|
| 125 |
+
</li>
|
| 126 |
+
</ul>
|
| 127 |
+
</div>
|
| 128 |
+
</div>
|
| 129 |
+
|
| 130 |
+
<!-- SERVIÇO 3 - CONSULTORIA & PERFORMANCE -->
|
| 131 |
+
<div class="group relative">
|
| 132 |
+
<div class="absolute inset-0 bg-linear-to-br from-green-500/20 to-emerald-500/20 rounded-3xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
| 133 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/5 rounded-3xl p-8 lg:p-10 transition-all duration-500 hover:border-green-500/30 h-full flex flex-col">
|
| 134 |
+
|
| 135 |
+
<!-- Icon -->
|
| 136 |
+
<div class="w-16 h-16 bg-linear-to-br from-green-500 to-emerald-600 rounded-2xl flex items-center justify-center mb-6 shadow-lg group-hover:scale-110 transition-transform">
|
| 137 |
+
<i data-lucide="zap" class="w-8 h-8 text-white"></i>
|
| 138 |
+
</div>
|
| 139 |
+
|
| 140 |
+
<!-- Title -->
|
| 141 |
+
<h3 class="text-2xl sm:text-3xl font-bold text-white mb-4">
|
| 142 |
+
Consultoria & Performance
|
| 143 |
+
</h3>
|
| 144 |
+
|
| 145 |
+
<!-- Description -->
|
| 146 |
+
<p class="text-gray-300 text-base leading-relaxed mb-6 grow">
|
| 147 |
+
Realizamos auditoria técnica completa, otimização de velocidade (Core Web Vitals 100), SEO técnico, migração para cloud e modernização de sistemas legados para melhorar a performance do seu negócio.
|
| 148 |
+
</p>
|
| 149 |
+
|
| 150 |
+
<!-- Features List -->
|
| 151 |
+
<ul class="space-y-3">
|
| 152 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 153 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-green-400 shrink-0 mt-0.5"></i>
|
| 154 |
+
<span>Score +95 no Google Lighthouse</span>
|
| 155 |
+
</li>
|
| 156 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 157 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-green-400 shrink-0 mt-0.5"></i>
|
| 158 |
+
<span>Redução significativa de custos de servidor</span>
|
| 159 |
+
</li>
|
| 160 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 161 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-green-400 shrink-0 mt-0.5"></i>
|
| 162 |
+
<span>Estratégia digital completa e assertiva</span>
|
| 163 |
+
</li>
|
| 164 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 165 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-green-400 shrink-0 mt-0.5"></i>
|
| 166 |
+
<span>Treinamento personalizado para sua equipe</span>
|
| 167 |
+
</li>
|
| 168 |
+
</ul>
|
| 169 |
+
</div>
|
| 170 |
+
</div>
|
| 171 |
+
|
| 172 |
+
<!-- SERVIÇO 4 - IA E AUTOMAÇÃO (NOVO!) -->
|
| 173 |
+
<div class="group relative">
|
| 174 |
+
<div class="absolute inset-0 bg-linear-to-br from-orange-500/20 to-red-500/20 rounded-3xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
| 175 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/5 rounded-3xl p-8 lg:p-10 transition-all duration-500 hover:border-orange-500/30 h-full flex flex-col">
|
| 176 |
+
|
| 177 |
+
<!-- Icon + Badge -->
|
| 178 |
+
<div class="flex items-center gap-3 mb-6">
|
| 179 |
+
<div class="w-16 h-16 bg-linear-to-br from-orange-500 to-red-600 rounded-2xl flex items-center justify-center shadow-lg group-hover:scale-110 transition-transform">
|
| 180 |
+
<i data-lucide="brain" class="w-8 h-8 text-white"></i>
|
| 181 |
+
</div>
|
| 182 |
+
<span class="px-3 py-1 bg-orange-500/20 border border-orange-500/30 rounded-full text-orange-400 text-xs font-semibold uppercase">
|
| 183 |
+
Novo
|
| 184 |
+
</span>
|
| 185 |
+
</div>
|
| 186 |
+
|
| 187 |
+
<!-- Title -->
|
| 188 |
+
<h3 class="text-2xl sm:text-3xl font-bold text-white mb-4">
|
| 189 |
+
IA & Automação
|
| 190 |
+
</h3>
|
| 191 |
+
|
| 192 |
+
<!-- Description -->
|
| 193 |
+
<p class="text-gray-300 text-base leading-relaxed mb-6 grow">
|
| 194 |
+
Desenvolvemos soluções inteligentes com Inteligência Artificial: chatbots para WhatsApp, assistentes virtuais, análise preditiva, automação de processos e modelos de IA personalizados para otimizar seu negócio.
|
| 195 |
+
</p>
|
| 196 |
+
|
| 197 |
+
<!-- Features List -->
|
| 198 |
+
<ul class="space-y-3">
|
| 199 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 200 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-orange-400 shrink-0 mt-0.5"></i>
|
| 201 |
+
<span>Chatbots inteligentes para WhatsApp Business</span>
|
| 202 |
+
</li>
|
| 203 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 204 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-orange-400 shrink-0 mt-0.5"></i>
|
| 205 |
+
<span>Assistentes virtuais com processamento de linguagem</span>
|
| 206 |
+
</li>
|
| 207 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 208 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-orange-400 shrink-0 mt-0.5"></i>
|
| 209 |
+
<span>Análise preditiva e machine learning</span>
|
| 210 |
+
</li>
|
| 211 |
+
<li class="flex items-start gap-3 text-gray-400 text-sm">
|
| 212 |
+
<i data-lucide="check-circle" class="w-5 h-5 text-orange-400 shrink-0 mt-0.5"></i>
|
| 213 |
+
<span>Automação de processos repetitivos (RPA)</span>
|
| 214 |
+
</li>
|
| 215 |
+
</ul>
|
| 216 |
+
</div>
|
| 217 |
+
</div>
|
| 218 |
+
|
| 219 |
+
</div>
|
| 220 |
+
|
| 221 |
+
<!-- SEÇÃO DE DESTAQUE -->
|
| 222 |
+
<div class="mt-20 lg:mt-32">
|
| 223 |
+
<div class="relative">
|
| 224 |
+
<div class="absolute inset-0 bg-linear-to-r from-cyan-500/10 via-purple-500/10 to-blue-500/10 rounded-3xl blur-3xl"></div>
|
| 225 |
+
|
| 226 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/10 rounded-3xl p-8 lg:p-12">
|
| 227 |
+
<div class="grid lg:grid-cols-2 gap-8 lg:gap-12 items-center">
|
| 228 |
+
|
| 229 |
+
<!-- Left Content -->
|
| 230 |
+
<div>
|
| 231 |
+
<div class="inline-block px-4 py-2 bg-cyan-500/10 rounded-full border border-cyan-500/20 mb-6">
|
| 232 |
+
<span class="text-cyan-400 text-sm font-semibold uppercase tracking-wider">Processo Transparente</span>
|
| 233 |
+
</div>
|
| 234 |
+
|
| 235 |
+
<h2 class="text-3xl sm:text-4xl md:text-5xl font-bold text-white mb-6 leading-tight">
|
| 236 |
+
Como trabalhamos com você
|
| 237 |
+
</h2>
|
| 238 |
+
|
| 239 |
+
<p class="text-gray-300 text-lg leading-relaxed mb-8">
|
| 240 |
+
Nosso processo é colaborativo e transparente. Trabalhamos lado a lado com você em cada etapa do projeto, garantindo que sua visão se torne realidade.
|
| 241 |
+
</p>
|
| 242 |
+
|
| 243 |
+
<a href="feedback.php"
|
| 244 |
+
class="inline-flex items-center gap-3 bg-linear-to-r from-cyan-500 to-blue-600 text-white font-semibold text-lg px-8 py-4 rounded-full shadow-lg hover:shadow-cyan-500/50 hover:scale-105 transition-all duration-300 group">
|
| 245 |
+
Começar Agora
|
| 246 |
+
<i data-lucide="arrow-right" class="w-5 h-5 group-hover:translate-x-1 transition-transform"></i>
|
| 247 |
+
</a>
|
| 248 |
+
</div>
|
| 249 |
+
|
| 250 |
+
<!-- Right Content - Steps -->
|
| 251 |
+
<div class="space-y-6">
|
| 252 |
+
<!-- Step 1 -->
|
| 253 |
+
<div class="flex gap-4">
|
| 254 |
+
<div class="shrink-0 w-12 h-12 bg-cyan-500/10 rounded-xl flex items-center justify-center border border-cyan-500/20">
|
| 255 |
+
<span class="text-cyan-400 font-bold text-lg">1</span>
|
| 256 |
+
</div>
|
| 257 |
+
<div>
|
| 258 |
+
<h4 class="text-white font-semibold text-lg mb-2">Consulta Inicial</h4>
|
| 259 |
+
<p class="text-gray-400 text-sm leading-relaxed">Entendemos seu negócio, objetivos e desafios para criar a melhor solução.</p>
|
| 260 |
+
</div>
|
| 261 |
+
</div>
|
| 262 |
+
|
| 263 |
+
<!-- Step 2 -->
|
| 264 |
+
<div class="flex gap-4">
|
| 265 |
+
<div class="shrink-0 w-12 h-12 bg-blue-500/10 rounded-xl flex items-center justify-center border border-blue-500/20">
|
| 266 |
+
<span class="text-blue-400 font-bold text-lg">2</span>
|
| 267 |
+
</div>
|
| 268 |
+
<div>
|
| 269 |
+
<h4 class="text-white font-semibold text-lg mb-2">Planejamento</h4>
|
| 270 |
+
<p class="text-gray-400 text-sm leading-relaxed">Criamos um roadmap detalhado com prazos, custos e entregas definidas.</p>
|
| 271 |
+
</div>
|
| 272 |
+
</div>
|
| 273 |
+
|
| 274 |
+
<!-- Step 3 -->
|
| 275 |
+
<div class="flex gap-4">
|
| 276 |
+
<div class="shrink-0 w-12 h-12 bg-purple-500/10 rounded-xl flex items-center justify-center border border-purple-500/20">
|
| 277 |
+
<span class="text-purple-400 font-bold text-lg">3</span>
|
| 278 |
+
</div>
|
| 279 |
+
<div>
|
| 280 |
+
<h4 class="text-white font-semibold text-lg mb-2">Desenvolvimento</h4>
|
| 281 |
+
<p class="text-gray-400 text-sm leading-relaxed">Construímos sua solução com código limpo, testes e validações constantes.</p>
|
| 282 |
+
</div>
|
| 283 |
+
</div>
|
| 284 |
+
|
| 285 |
+
<!-- Step 4 -->
|
| 286 |
+
<div class="flex gap-4">
|
| 287 |
+
<div class="shrink-0 w-12 h-12 bg-green-500/10 rounded-xl flex items-center justify-center border border-green-500/20">
|
| 288 |
+
<span class="text-green-400 font-bold text-lg">4</span>
|
| 289 |
+
</div>
|
| 290 |
+
<div>
|
| 291 |
+
<h4 class="text-white font-semibold text-lg mb-2">Entrega & Suporte</h4>
|
| 292 |
+
<p class="text-gray-400 text-sm leading-relaxed">Lançamos seu projeto e fornecemos suporte contínuo para garantir o sucesso.</p>
|
| 293 |
+
</div>
|
| 294 |
+
</div>
|
| 295 |
+
</div>
|
| 296 |
+
|
| 297 |
+
</div>
|
| 298 |
+
</div>
|
| 299 |
+
</div>
|
| 300 |
+
</div>
|
| 301 |
+
|
| 302 |
+
<!-- CTA FINAL -->
|
| 303 |
+
<div class="text-center mt-20 lg:mt-32">
|
| 304 |
+
<h2 class="text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-bold text-white mb-6 leading-tight">
|
| 305 |
+
Pronto para transformar
|
| 306 |
+
<span class="block text-slate-300">
|
| 307 |
+
seu negócio?
|
| 308 |
+
</span>
|
| 309 |
+
</h2>
|
| 310 |
+
|
| 311 |
+
<p class="text-lg sm:text-xl text-gray-300 max-w-2xl mx-auto mb-10">
|
| 312 |
+
Entre em contato hoje mesmo e descubra como podemos ajudar você a alcançar seus objetivos.
|
| 313 |
+
</p>
|
| 314 |
+
|
| 315 |
+
<div class="flex flex-col sm:flex-row items-center justify-center gap-4">
|
| 316 |
+
<a href="feedback.php"
|
| 317 |
+
class="inline-flex items-center justify-center gap-3 w-full sm:w-auto bg-slate-700 hover:bg-slate-600 border border-slate-600 text-slate-200 font-medium text-lg px-10 py-4 rounded-lg transition-all duration-300">
|
| 318 |
+
Iniciar Projeto
|
| 319 |
+
<i data-lucide="arrow-right" class="w-5 h-5"></i>
|
| 320 |
+
</a>
|
| 321 |
+
|
| 322 |
+
<a href="projetos.php"
|
| 323 |
+
class="inline-flex items-center justify-center gap-3 w-full sm:w-auto bg-slate-800/50 hover:bg-slate-700/50 border border-slate-600 text-slate-300 font-medium text-lg px-10 py-4 rounded-lg transition-all duration-300">
|
| 324 |
+
Ver Portfolio
|
| 325 |
+
<i data-lucide="folder-open" class="w-5 h-5"></i>
|
| 326 |
+
</a>
|
| 327 |
+
</div>
|
| 328 |
+
</div>
|
| 329 |
+
|
| 330 |
+
</div>
|
| 331 |
+
</main>
|
| 332 |
+
|
| 333 |
+
<?php include 'components/footer.php'; ?>
|
| 334 |
+
|
| 335 |
+
<!-- SCRIPTS -->
|
| 336 |
+
<script src="https://unpkg.com/lucide@latest"></script>
|
| 337 |
+
<script>
|
| 338 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 339 |
+
// Initialize Lucide icons
|
| 340 |
+
lucide.createIcons();
|
| 341 |
+
|
| 342 |
+
// Fade in animations on scroll
|
| 343 |
+
const observerOptions = {
|
| 344 |
+
threshold: 0.1,
|
| 345 |
+
rootMargin: '0px 0px -50px 0px'
|
| 346 |
+
};
|
| 347 |
+
|
| 348 |
+
const observer = new IntersectionObserver((entries) => {
|
| 349 |
+
entries.forEach(entry => {
|
| 350 |
+
if (entry.isIntersecting) {
|
| 351 |
+
entry.target.style.opacity = '1';
|
| 352 |
+
entry.target.style.transform = 'translateY(0)';
|
| 353 |
+
}
|
| 354 |
+
});
|
| 355 |
+
}, observerOptions);
|
| 356 |
+
|
| 357 |
+
// Observe all service cards and sections
|
| 358 |
+
document.querySelectorAll('.group, section').forEach((el, index) => {
|
| 359 |
+
el.style.opacity = '0';
|
| 360 |
+
el.style.transform = 'translateY(20px)';
|
| 361 |
+
el.style.transition = `opacity 0.6s ease ${index * 0.1}s, transform 0.6s ease ${index * 0.1}s`;
|
| 362 |
+
observer.observe(el);
|
| 363 |
+
});
|
| 364 |
+
});
|
| 365 |
+
</script>
|
| 366 |
+
|
| 367 |
+
<style>
|
| 368 |
+
/* Gradient animation */
|
| 369 |
+
@keyframes gradient-shift {
|
| 370 |
+
0%, 100% {
|
| 371 |
+
background-position: 0% 50%;
|
| 372 |
+
}
|
| 373 |
+
50% {
|
| 374 |
+
background-position: 100% 50%;
|
| 375 |
+
}
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
.bg-linear-to-r,
|
| 379 |
+
.bg-linear-to-br {
|
| 380 |
+
background-size: 200% 200%;
|
| 381 |
+
animation: gradient-shift 8s ease infinite;
|
| 382 |
+
}
|
| 383 |
+
|
| 384 |
+
/* Smooth hover transitions */
|
| 385 |
+
.group {
|
| 386 |
+
will-change: transform;
|
| 387 |
+
}
|
| 388 |
+
</style>
|
sobre.php
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
require_once __DIR__ . '/src/Bootstrap.php';
|
| 3 |
+
\SoftEdge\Env::load(__DIR__);
|
| 4 |
+
\SoftEdge\Bootstrap::init();
|
| 5 |
+
include 'components/header.php';
|
| 6 |
+
?>
|
| 7 |
+
|
| 8 |
+
<!-- HERO SECTION -->
|
| 9 |
+
<section class="relative min-h-[90vh] flex items-center justify-center overflow-hidden">
|
| 10 |
+
<!-- Background -->
|
| 11 |
+
<div class="absolute inset-0 -z-10">
|
| 12 |
+
<div class="absolute inset-0 bg-linear-to-br from-slate-950 via-slate-900 to-slate-950"></div>
|
| 13 |
+
<div class="absolute inset-0 opacity-30">
|
| 14 |
+
<div class="absolute top-20 left-20 w-96 h-96 bg-cyan-500/20 rounded-full blur-3xl"></div>
|
| 15 |
+
<div class="absolute bottom-20 right-20 w-96 h-96 bg-blue-500/20 rounded-full blur-3xl"></div>
|
| 16 |
+
</div>
|
| 17 |
+
</div>
|
| 18 |
+
|
| 19 |
+
<!-- Content -->
|
| 20 |
+
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
| 21 |
+
<div class="space-y-8">
|
| 22 |
+
<h1 class="text-5xl sm:text-6xl md:text-7xl lg:text-8xl font-bold leading-tight">
|
| 23 |
+
Do sonho<br>
|
| 24 |
+
<span class="text-slate-300">
|
| 25 |
+
à realidade lógica
|
| 26 |
+
</span>
|
| 27 |
+
</h1>
|
| 28 |
+
|
| 29 |
+
<p class="text-lg sm:text-xl md:text-2xl text-slate-400 max-w-3xl mx-auto leading-relaxed">
|
| 30 |
+
Começamos com uma ideia simples.<br class="hidden sm:block">
|
| 31 |
+
Hoje criamos softwares que as pessoas amam usar.
|
| 32 |
+
</p>
|
| 33 |
+
</div>
|
| 34 |
+
</div>
|
| 35 |
+
|
| 36 |
+
<!-- Scroll indicator -->
|
| 37 |
+
<div class="absolute bottom-8 left-1/2 -translate-x-1/2 animate-bounce">
|
| 38 |
+
<i data-lucide="chevron-down" class="w-8 h-8 text-white/40"></i>
|
| 39 |
+
</div>
|
| 40 |
+
</section>
|
| 41 |
+
|
| 42 |
+
<!-- MAIN CONTENT -->
|
| 43 |
+
<main class="relative py-20 lg:py-32">
|
| 44 |
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
| 45 |
+
|
| 46 |
+
<!-- NOSSA HISTÓRIA -->
|
| 47 |
+
<div class="grid lg:grid-cols-2 gap-12 lg:gap-20 items-center mb-32">
|
| 48 |
+
|
| 49 |
+
<!-- Texto -->
|
| 50 |
+
<div class="space-y-8">
|
| 51 |
+
<div class="inline-block px-4 py-2 bg-cyan-500/10 rounded-full border border-cyan-500/20 mb-4">
|
| 52 |
+
<span class="text-cyan-400 text-sm font-semibold uppercase tracking-wider">Nossa História</span>
|
| 53 |
+
</div>
|
| 54 |
+
|
| 55 |
+
<div class="space-y-6 text-gray-300 text-base sm:text-lg leading-relaxed">
|
| 56 |
+
<p>
|
| 57 |
+
Tudo começou em <span class="text-cyan-400 font-semibold">2023</span>, quando quatro amigos decidiram que o mundo precisava de softwares mais <span class="text-white font-medium">humanos</span>.
|
| 58 |
+
</p>
|
| 59 |
+
|
| 60 |
+
<p>
|
| 61 |
+
<span class="text-white font-bold text-xl">Isaac Quarenta</span> <span class="text-gray-400 text-sm">(CEO)</span> juntou forças com os co-fundadores
|
| 62 |
+
<span class="text-cyan-300 font-medium">José Lopes</span>,
|
| 63 |
+
<span class="text-blue-300 font-medium">Stefânio Costa</span> e
|
| 64 |
+
<span class="text-purple-300 font-medium">Tiago Rodrigues</span>.
|
| 65 |
+
</p>
|
| 66 |
+
|
| 67 |
+
<p>
|
| 68 |
+
Juntos criaram a <span class="bg-linear-to-r from-cyan-400 to-blue-500 bg-clip-text text-transparent font-bold text-xl">SoftEdge</span> — uma empresa que transforma ideias em experiências digitais e softwares légitmos.
|
| 69 |
+
</p>
|
| 70 |
+
|
| 71 |
+
<div class="pt-6 mt-8 border-t border-white/10">
|
| 72 |
+
<p class="text-xl sm:text-2xl font-semibold text-cyan-400 leading-relaxed">
|
| 73 |
+
Começamos com um sonho.<br>
|
| 74 |
+
Hoje desenvolvemos realidades lógicas e softwares mais amáveis.
|
| 75 |
+
</p>
|
| 76 |
+
</div>
|
| 77 |
+
</div>
|
| 78 |
+
</div>
|
| 79 |
+
|
| 80 |
+
<!-- Imagem da Equipe -->
|
| 81 |
+
<div class="relative">
|
| 82 |
+
<div class="relative group">
|
| 83 |
+
<!-- Card Container -->
|
| 84 |
+
<div class="relative overflow-hidden rounded-3xl bg-linear-to-br from-cyan-500/10 to-blue-500/10 p-1 transition-all duration-500 hover:scale-[1.02]">
|
| 85 |
+
<div class="relative overflow-hidden rounded-3xl bg-slate-900/80 backdrop-blur-xl">
|
| 86 |
+
|
| 87 |
+
<!-- Image -->
|
| 88 |
+
<div class="relative aspect-square overflow-hidden">
|
| 89 |
+
<img src="/assets/placeholder.svg"
|
| 90 |
+
alt="Equipe SoftEdge Corporation - Isaac, José, Stefânio e Tiago"
|
| 91 |
+
class="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110">
|
| 92 |
+
|
| 93 |
+
<!-- Overlay Gradient -->
|
| 94 |
+
<div class="absolute inset-0 bg-linear-to-t from-slate-900 via-slate-900/40 to-transparent"></div>
|
| 95 |
+
|
| 96 |
+
<!-- Text Overlay -->
|
| 97 |
+
<div class="absolute bottom-0 left-0 right-0 p-8 text-center">
|
| 98 |
+
<h3 class="text-2xl sm:text-3xl font-bold text-white mb-2">Nossa Equipe</h3>
|
| 99 |
+
<p class="text-gray-300 text-sm sm:text-base">Isaac • José • Stefâncio • Tiago</p>
|
| 100 |
+
</div>
|
| 101 |
+
</div>
|
| 102 |
+
</div>
|
| 103 |
+
</div>
|
| 104 |
+
|
| 105 |
+
<!-- Decorative Elements -->
|
| 106 |
+
<div class="absolute -top-4 -right-4 w-24 h-24 bg-cyan-500/20 rounded-full blur-2xl"></div>
|
| 107 |
+
<div class="absolute -bottom-4 -left-4 w-24 h-24 bg-blue-500/20 rounded-full blur-2xl"></div>
|
| 108 |
+
</div>
|
| 109 |
+
</div>
|
| 110 |
+
</div>
|
| 111 |
+
|
| 112 |
+
<!-- NÚMEROS IMPACTANTES -->
|
| 113 |
+
<div class="mb-32">
|
| 114 |
+
<div class="text-center mb-16">
|
| 115 |
+
<div class="inline-block px-4 py-2 bg-cyan-500/10 rounded-full border border-cyan-500/20 mb-4">
|
| 116 |
+
<span class="text-cyan-400 text-sm font-semibold uppercase tracking-wider">Nossos Números</span>
|
| 117 |
+
</div>
|
| 118 |
+
<h2 class="text-3xl sm:text-4xl md:text-5xl font-bold text-white">
|
| 119 |
+
Resultados que inspiram
|
| 120 |
+
</h2>
|
| 121 |
+
</div>
|
| 122 |
+
|
| 123 |
+
<div class="grid grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8">
|
| 124 |
+
<!-- Stat 1 -->
|
| 125 |
+
<div class="relative group">
|
| 126 |
+
<div class="absolute inset-0 bg-linear-to-br from-cyan-500/20 to-blue-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
| 127 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/5 rounded-2xl p-8 text-center transition-all duration-500 hover:border-cyan-500/30">
|
| 128 |
+
<div class="text-4xl sm:text-5xl md:text-6xl font-bold bg-linear-to-br from-cyan-400 to-cyan-600 bg-clip-text text-transparent mb-3">
|
| 129 |
+
70+
|
| 130 |
+
</div>
|
| 131 |
+
<p class="text-gray-300 text-sm sm:text-base">Projetos entregues</p>
|
| 132 |
+
</div>
|
| 133 |
+
</div>
|
| 134 |
+
|
| 135 |
+
<!-- Stat 2 -->
|
| 136 |
+
<div class="relative group">
|
| 137 |
+
<div class="absolute inset-0 bg-linear-to-br from-blue-500/20 to-purple-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
| 138 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/5 rounded-2xl p-8 text-center transition-all duration-500 hover:border-blue-500/30">
|
| 139 |
+
<div class="text-4xl sm:text-5xl md:text-6xl font-bold bg-linear-to-br from-blue-400 to-blue-600 bg-clip-text text-transparent mb-3">
|
| 140 |
+
4.9★
|
| 141 |
+
</div>
|
| 142 |
+
<p class="text-gray-300 text-sm sm:text-base">Satisfação média</p>
|
| 143 |
+
</div>
|
| 144 |
+
</div>
|
| 145 |
+
|
| 146 |
+
<!-- Stat 3 -->
|
| 147 |
+
<div class="relative group">
|
| 148 |
+
<div class="absolute inset-0 bg-linear-to-br from-purple-500/20 to-pink-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
| 149 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/5 rounded-2xl p-8 text-center transition-all duration-500 hover:border-purple-500/30">
|
| 150 |
+
<div class="text-4xl sm:text-5xl md:text-6xl font-bold bg-linear-to-br from-purple-400 to-purple-600 bg-clip-text text-transparent mb-3">
|
| 151 |
+
24/7
|
| 152 |
+
</div>
|
| 153 |
+
<p class="text-gray-300 text-sm sm:text-base">Suporte dedicado</p>
|
| 154 |
+
</div>
|
| 155 |
+
</div>
|
| 156 |
+
|
| 157 |
+
<!-- Stat 4 -->
|
| 158 |
+
<div class="relative group">
|
| 159 |
+
<div class="absolute inset-0 bg-linear-to-br from-green-500/20 to-emerald-500/20 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
| 160 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/5 rounded-2xl p-8 text-center transition-all duration-500 hover:border-green-500/30">
|
| 161 |
+
<div class="text-4xl sm:text-5xl md:text-6xl font-bold bg-linear-to-br from-green-400 to-green-600 bg-clip-text text-transparent mb-3">
|
| 162 |
+
100%
|
| 163 |
+
</div>
|
| 164 |
+
<p class="text-gray-300 text-sm sm:text-base">Código limpo</p>
|
| 165 |
+
</div>
|
| 166 |
+
</div>
|
| 167 |
+
</div>
|
| 168 |
+
</div>
|
| 169 |
+
|
| 170 |
+
<!-- CTA SECTION -->
|
| 171 |
+
<div class="relative">
|
| 172 |
+
<!-- Background -->
|
| 173 |
+
<div class="absolute inset-0 bg-linear-to-r from-cyan-500/10 via-blue-500/10 to-purple-500/10 rounded-3xl blur-3xl"></div>
|
| 174 |
+
|
| 175 |
+
<!-- Content -->
|
| 176 |
+
<div class="relative bg-slate-900/60 backdrop-blur-xl border border-white/10 rounded-3xl p-12 lg:p-16 text-center">
|
| 177 |
+
<h2 class="text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-bold text-white mb-6 leading-tight">
|
| 178 |
+
Pronto para criar algo<br class="hidden sm:block">
|
| 179 |
+
<span class="bg-linear-to-r from-cyan-400 to-blue-500 bg-clip-text text-transparent">
|
| 180 |
+
incrível juntos?
|
| 181 |
+
</span>
|
| 182 |
+
</h2>
|
| 183 |
+
|
| 184 |
+
<p class="text-gray-300 text-lg max-w-2xl mx-auto mb-10">
|
| 185 |
+
Vamos transformar sua ideia em realidade. Entre em contato e descubra como podemos ajudar.
|
| 186 |
+
</p>
|
| 187 |
+
|
| 188 |
+
<a href="feedback.php"
|
| 189 |
+
class="inline-flex items-center gap-3 bg-slate-700 hover:bg-slate-600 border border-slate-600 text-slate-200 font-medium text-lg px-8 py-4 rounded-lg transition-all duration-300">
|
| 190 |
+
Falar conosco
|
| 191 |
+
<i data-lucide="arrow-right" class="w-5 h-5"></i>
|
| 192 |
+
</a>
|
| 193 |
+
</div>
|
| 194 |
+
</div>
|
| 195 |
+
|
| 196 |
+
</div>
|
| 197 |
+
</main>
|
| 198 |
+
|
| 199 |
+
<?php include 'components/footer.php'; ?>
|
| 200 |
+
|
| 201 |
+
<!-- SCRIPTS -->
|
| 202 |
+
<script src="https://unpkg.com/lucide@latest"></script>
|
| 203 |
+
<script>
|
| 204 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 205 |
+
// Initialize Lucide icons
|
| 206 |
+
lucide.createIcons();
|
| 207 |
+
|
| 208 |
+
// Smooth scroll behavior
|
| 209 |
+
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
| 210 |
+
anchor.addEventListener('click', function (e) {
|
| 211 |
+
e.preventDefault();
|
| 212 |
+
const target = document.querySelector(this.getAttribute('href'));
|
| 213 |
+
if (target) {
|
| 214 |
+
target.scrollIntoView({
|
| 215 |
+
behavior: 'smooth',
|
| 216 |
+
block: 'start'
|
| 217 |
+
});
|
| 218 |
+
}
|
| 219 |
+
});
|
| 220 |
+
});
|
| 221 |
+
|
| 222 |
+
// Intersection Observer for fade-in animations
|
| 223 |
+
const observerOptions = {
|
| 224 |
+
threshold: 0.1,
|
| 225 |
+
rootMargin: '0px 0px -100px 0px'
|
| 226 |
+
};
|
| 227 |
+
|
| 228 |
+
const observer = new IntersectionObserver((entries) => {
|
| 229 |
+
entries.forEach(entry => {
|
| 230 |
+
if (entry.isIntersecting) {
|
| 231 |
+
entry.target.style.opacity = '1';
|
| 232 |
+
entry.target.style.transform = 'translateY(0)';
|
| 233 |
+
}
|
| 234 |
+
});
|
| 235 |
+
}, observerOptions);
|
| 236 |
+
|
| 237 |
+
// Observe all sections
|
| 238 |
+
document.querySelectorAll('section, main > div > div').forEach(el => {
|
| 239 |
+
el.style.opacity = '0';
|
| 240 |
+
el.style.transform = 'translateY(30px)';
|
| 241 |
+
el.style.transition = 'opacity 0.8s ease, transform 0.8s ease';
|
| 242 |
+
observer.observe(el);
|
| 243 |
+
});
|
| 244 |
+
});
|
| 245 |
+
</script>
|
| 246 |
+
|
| 247 |
+
<style>
|
| 248 |
+
/* Smooth scrolling */
|
| 249 |
+
html {
|
| 250 |
+
scroll-behavior: smooth;
|
| 251 |
+
}
|
| 252 |
+
|
| 253 |
+
/* Image hover effects */
|
| 254 |
+
img {
|
| 255 |
+
will-change: transform;
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
/* Gradient animation */
|
| 259 |
+
@keyframes gradient-shift {
|
| 260 |
+
0%, 100% {
|
| 261 |
+
background-position: 0% 50%;
|
| 262 |
+
}
|
| 263 |
+
50% {
|
| 264 |
+
background-position: 100% 50%;
|
| 265 |
+
}
|
| 266 |
+
}
|
| 267 |
+
|
| 268 |
+
.bg-linear-to-r {
|
| 269 |
+
background-size: 200% 200%;
|
| 270 |
+
animation: gradient-shift 8s ease infinite;
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
/* Custom scrollbar */
|
| 274 |
+
::-webkit-scrollbar {
|
| 275 |
+
width: 10px;
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
::-webkit-scrollbar-track {
|
| 279 |
+
background: #0f172a;
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
::-webkit-scrollbar-thumb {
|
| 283 |
+
background: linear-gradient(180deg, #06b6d4, #3b82f6);
|
| 284 |
+
border-radius: 5px;
|
| 285 |
+
}
|
| 286 |
+
|
| 287 |
+
::-webkit-scrollbar-thumb:hover {
|
| 288 |
+
background: linear-gradient(180deg, #0891b2, #2563eb);
|
| 289 |
+
}
|
| 290 |
+
</style>
|
test-react.php
ADDED
|
File without changes
|
test.html
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="pt-BR">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>SoftEdge Corporation - Test</title>
|
| 7 |
+
<style>
|
| 8 |
+
body {
|
| 9 |
+
font-family: Arial, sans-serif;
|
| 10 |
+
background: linear-gradient(135deg, #0f172a, #1e293b);
|
| 11 |
+
color: white;
|
| 12 |
+
margin: 0;
|
| 13 |
+
padding: 0;
|
| 14 |
+
min-height: 100vh;
|
| 15 |
+
display: flex;
|
| 16 |
+
align-items: center;
|
| 17 |
+
justify-content: center;
|
| 18 |
+
}
|
| 19 |
+
.container {
|
| 20 |
+
text-align: center;
|
| 21 |
+
max-width: 600px;
|
| 22 |
+
padding: 2rem;
|
| 23 |
+
}
|
| 24 |
+
.logo {
|
| 25 |
+
font-size: 3rem;
|
| 26 |
+
margin-bottom: 1rem;
|
| 27 |
+
}
|
| 28 |
+
.status {
|
| 29 |
+
background: rgba(34, 197, 94, 0.1);
|
| 30 |
+
border: 1px solid #22c55e;
|
| 31 |
+
border-radius: 0.5rem;
|
| 32 |
+
padding: 1rem;
|
| 33 |
+
margin: 1rem 0;
|
| 34 |
+
}
|
| 35 |
+
</style>
|
| 36 |
+
</head>
|
| 37 |
+
<body>
|
| 38 |
+
<div class="container">
|
| 39 |
+
<div class="logo">🚀</div>
|
| 40 |
+
<h1>SoftEdge Corporation</h1>
|
| 41 |
+
<p>Website em funcionamento!</p>
|
| 42 |
+
<div class="status">
|
| 43 |
+
<strong>✅ Status: Online</strong><br>
|
| 44 |
+
<small>Deployed successfully on Hugging Face Spaces</small>
|
| 45 |
+
</div>
|
| 46 |
+
<p>Se você está vendo esta página, o deployment está funcionando corretamente.</p>
|
| 47 |
+
</div>
|
| 48 |
+
</body>
|
| 49 |
+
</html>
|
webpack.config.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const path = require('path');
|
| 2 |
+
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
| 3 |
+
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
| 4 |
+
const TerserPlugin = require('terser-webpack-plugin');
|
| 5 |
+
|
| 6 |
+
const isProduction = process.env.NODE_ENV === 'production';
|
| 7 |
+
|
| 8 |
+
module.exports = {
|
| 9 |
+
mode: isProduction ? 'production' : 'development',
|
| 10 |
+
entry: './src/react/index.js',
|
| 11 |
+
|
| 12 |
+
output: {
|
| 13 |
+
path: path.resolve(__dirname, 'dist'),
|
| 14 |
+
filename: (pathData) => {
|
| 15 |
+
return pathData.chunk.name === 'main'
|
| 16 |
+
? 'static/js/bundle.js'
|
| 17 |
+
: 'static/js/[name].[contenthash:8].js';
|
| 18 |
+
},
|
| 19 |
+
chunkFilename: 'static/js/chunk.[id].[contenthash:8].js',
|
| 20 |
+
publicPath: '/',
|
| 21 |
+
clean: true,
|
| 22 |
+
},
|
| 23 |
+
|
| 24 |
+
module: {
|
| 25 |
+
rules: [
|
| 26 |
+
{
|
| 27 |
+
test: /\.(js|jsx)$/,
|
| 28 |
+
exclude: /node_modules/,
|
| 29 |
+
use: {
|
| 30 |
+
loader: 'babel-loader',
|
| 31 |
+
options: {
|
| 32 |
+
presets: [
|
| 33 |
+
['@babel/preset-env', {
|
| 34 |
+
targets: {
|
| 35 |
+
browsers: ['> 0.25%', 'not dead'],
|
| 36 |
+
},
|
| 37 |
+
modules: false,
|
| 38 |
+
}],
|
| 39 |
+
['@babel/preset-react', {
|
| 40 |
+
runtime: 'automatic',
|
| 41 |
+
}],
|
| 42 |
+
],
|
| 43 |
+
plugins: [
|
| 44 |
+
'@babel/plugin-proposal-class-properties',
|
| 45 |
+
'@babel/plugin-proposal-object-rest-spread',
|
| 46 |
+
],
|
| 47 |
+
},
|
| 48 |
+
},
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
test: /\.css$/i,
|
| 52 |
+
use: [
|
| 53 |
+
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
|
| 54 |
+
{
|
| 55 |
+
loader: 'css-loader',
|
| 56 |
+
options: {
|
| 57 |
+
importLoaders: 1,
|
| 58 |
+
modules: {
|
| 59 |
+
auto: true,
|
| 60 |
+
localIdentName: isProduction
|
| 61 |
+
? '[hash:base64:8]'
|
| 62 |
+
: '[name]__[local]__[hash:base64:4]',
|
| 63 |
+
},
|
| 64 |
+
},
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
loader: 'postcss-loader',
|
| 68 |
+
options: {
|
| 69 |
+
postcssOptions: {
|
| 70 |
+
plugins: [
|
| 71 |
+
'autoprefixer',
|
| 72 |
+
isProduction && 'cssnano',
|
| 73 |
+
].filter(Boolean),
|
| 74 |
+
},
|
| 75 |
+
},
|
| 76 |
+
},
|
| 77 |
+
],
|
| 78 |
+
},
|
| 79 |
+
{
|
| 80 |
+
test: /\.(png|jpe?g|gif|svg|webp)$/i,
|
| 81 |
+
type: 'asset/resource',
|
| 82 |
+
generator: {
|
| 83 |
+
filename: 'static/media/[name].[hash:8][ext]',
|
| 84 |
+
},
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
| 88 |
+
type: 'asset/resource',
|
| 89 |
+
generator: {
|
| 90 |
+
filename: 'static/fonts/[name].[hash:8][ext]',
|
| 91 |
+
},
|
| 92 |
+
},
|
| 93 |
+
],
|
| 94 |
+
},
|
| 95 |
+
|
| 96 |
+
plugins: [
|
| 97 |
+
...(isProduction ? [
|
| 98 |
+
new MiniCssExtractPlugin({
|
| 99 |
+
filename: 'static/css/[name].[contenthash:8].css',
|
| 100 |
+
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
|
| 101 |
+
}),
|
| 102 |
+
] : []),
|
| 103 |
+
],
|
| 104 |
+
|
| 105 |
+
optimization: {
|
| 106 |
+
minimize: isProduction,
|
| 107 |
+
minimizer: [
|
| 108 |
+
new TerserPlugin({
|
| 109 |
+
terserOptions: {
|
| 110 |
+
compress: {
|
| 111 |
+
drop_console: isProduction,
|
| 112 |
+
drop_debugger: isProduction,
|
| 113 |
+
},
|
| 114 |
+
},
|
| 115 |
+
}),
|
| 116 |
+
new CssMinimizerPlugin(),
|
| 117 |
+
],
|
| 118 |
+
splitChunks: {
|
| 119 |
+
chunks: 'all',
|
| 120 |
+
cacheGroups: {
|
| 121 |
+
vendor: {
|
| 122 |
+
test: /[\\/]node_modules[\\/]/,
|
| 123 |
+
name: 'vendor',
|
| 124 |
+
chunks: 'all',
|
| 125 |
+
enforce: true,
|
| 126 |
+
},
|
| 127 |
+
},
|
| 128 |
+
},
|
| 129 |
+
},
|
| 130 |
+
|
| 131 |
+
resolve: {
|
| 132 |
+
extensions: ['.js', '.jsx', '.json'],
|
| 133 |
+
alias: {
|
| 134 |
+
'@': path.resolve(__dirname, 'src/react'),
|
| 135 |
+
'@components': path.resolve(__dirname, 'src/react/components'),
|
| 136 |
+
'@utils': path.resolve(__dirname, 'src/react/utils'),
|
| 137 |
+
'@assets': path.resolve(__dirname, 'src/react/assets'),
|
| 138 |
+
},
|
| 139 |
+
},
|
| 140 |
+
|
| 141 |
+
devServer: {
|
| 142 |
+
static: {
|
| 143 |
+
directory: path.join(__dirname, 'dist'),
|
| 144 |
+
},
|
| 145 |
+
compress: true,
|
| 146 |
+
port: 3000,
|
| 147 |
+
hot: true,
|
| 148 |
+
open: true,
|
| 149 |
+
historyApiFallback: true,
|
| 150 |
+
proxy: {
|
| 151 |
+
'/api': {
|
| 152 |
+
target: 'http://localhost:8080',
|
| 153 |
+
changeOrigin: true,
|
| 154 |
+
secure: false,
|
| 155 |
+
},
|
| 156 |
+
},
|
| 157 |
+
headers: {
|
| 158 |
+
'Access-Control-Allow-Origin': '*',
|
| 159 |
+
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
|
| 160 |
+
'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization',
|
| 161 |
+
},
|
| 162 |
+
},
|
| 163 |
+
|
| 164 |
+
devtool: isProduction ? 'source-map' : 'eval-cheap-module-source-map',
|
| 165 |
+
|
| 166 |
+
performance: {
|
| 167 |
+
hints: isProduction ? 'warning' : false,
|
| 168 |
+
maxEntrypointSize: 512000,
|
| 169 |
+
maxAssetSize: 512000,
|
| 170 |
+
},
|
| 171 |
+
|
| 172 |
+
stats: {
|
| 173 |
+
colors: true,
|
| 174 |
+
children: false,
|
| 175 |
+
chunks: false,
|
| 176 |
+
chunkModules: false,
|
| 177 |
+
modules: false,
|
| 178 |
+
reasons: false,
|
| 179 |
+
errorDetails: true,
|
| 180 |
+
assets: true,
|
| 181 |
+
version: false,
|
| 182 |
+
timings: true,
|
| 183 |
+
},
|
| 184 |
+
};
|