feat: Add comprehensive documentation suite and reorganize project structure
- Created complete documentation in docs/ directory - Added PROJECT_OVERVIEW.md with feature highlights and getting started guide - Added ARCHITECTURE.md with system design and technical details - Added SECURITY.md with comprehensive security implementation guide - Added DEVELOPMENT.md with development workflows and best practices - Added DEPLOYMENT.md with production deployment instructions - Added API.md with complete REST API documentation - Added CONTRIBUTING.md with contribution guidelines - Added CHANGELOG.md with version history and migration notes - Reorganized all documentation files into docs/ directory for better organization - Updated README.md with proper documentation links and quick navigation - Enhanced project structure with professional documentation standards
This commit is contained in:
650
f_modules/m_backend/token_customization.php
Normal file
650
f_modules/m_backend/token_customization.php
Normal file
@@ -0,0 +1,650 @@
|
||||
<?php
|
||||
/*******************************************************************************************************************
|
||||
| EasyStream Token Customization System
|
||||
| Allows platform owners to customize their monetization token branding
|
||||
|*******************************************************************************************************************/
|
||||
|
||||
define('_ISVALID', true);
|
||||
include_once '../../f_core/config.core.php';
|
||||
|
||||
// Check admin permissions
|
||||
$logged_in = VLogin::checkBackend('token_customization');
|
||||
|
||||
$error_message = '';
|
||||
$success_message = '';
|
||||
|
||||
// Handle form submission
|
||||
if ($_POST && isset($_POST['action'])) {
|
||||
switch ($_POST['action']) {
|
||||
case 'update_token_settings':
|
||||
$result = updateTokenSettings($_POST);
|
||||
if ($result['success']) {
|
||||
$success_message = $result['message'];
|
||||
} else {
|
||||
$error_message = $result['message'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'upload_token_icon':
|
||||
$result = uploadTokenIcon($_FILES['token_icon']);
|
||||
if ($result['success']) {
|
||||
$success_message = $result['message'];
|
||||
} else {
|
||||
$error_message = $result['message'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'reset_to_defaults':
|
||||
$result = resetTokenDefaults();
|
||||
if ($result['success']) {
|
||||
$success_message = $result['message'];
|
||||
} else {
|
||||
$error_message = $result['message'];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get current token settings
|
||||
$token_settings = getTokenSettings();
|
||||
|
||||
function getTokenSettings() {
|
||||
global $class_database;
|
||||
|
||||
$defaults = [
|
||||
'token_name' => 'EasyCoins',
|
||||
'token_symbol' => 'EC',
|
||||
'token_plural' => 'EasyCoins',
|
||||
'token_description' => 'Platform currency for tips and donations',
|
||||
'token_icon' => '/f_templates/tpl_frontend/img/default-token.png',
|
||||
'token_color_primary' => '#FFD700',
|
||||
'token_color_secondary' => '#FFA500',
|
||||
'exchange_rate' => '1.00',
|
||||
'min_purchase' => '1.00',
|
||||
'max_purchase' => '1000.00',
|
||||
'enabled' => '1'
|
||||
];
|
||||
|
||||
try {
|
||||
$sql = "SELECT setting_key, setting_value FROM db_settings WHERE setting_key LIKE 'token_%'";
|
||||
$result = $class_database->execute($sql);
|
||||
|
||||
$settings = $defaults;
|
||||
while (!$result->EOF) {
|
||||
$key = str_replace('token_', '', $result->fields['setting_key']);
|
||||
$settings[$key] = $result->fields['setting_value'];
|
||||
$result->MoveNext();
|
||||
}
|
||||
|
||||
return $settings;
|
||||
} catch (Exception $e) {
|
||||
return $defaults;
|
||||
}
|
||||
}
|
||||
|
||||
function updateTokenSettings($data) {
|
||||
global $class_database;
|
||||
|
||||
try {
|
||||
$settings = [
|
||||
'token_name' => $class_filter->clr_str($data['token_name']),
|
||||
'token_symbol' => strtoupper($class_filter->clr_str($data['token_symbol'])),
|
||||
'token_plural' => $class_filter->clr_str($data['token_plural']),
|
||||
'token_description' => $class_filter->clr_str($data['token_description']),
|
||||
'token_color_primary' => $class_filter->clr_str($data['token_color_primary']),
|
||||
'token_color_secondary' => $class_filter->clr_str($data['token_color_secondary']),
|
||||
'exchange_rate' => floatval($data['exchange_rate']),
|
||||
'min_purchase' => floatval($data['min_purchase']),
|
||||
'max_purchase' => floatval($data['max_purchase']),
|
||||
'enabled' => isset($data['enabled']) ? '1' : '0'
|
||||
];
|
||||
|
||||
foreach ($settings as $key => $value) {
|
||||
$sql = "INSERT INTO db_settings (setting_key, setting_value, setting_description)
|
||||
VALUES (?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE setting_value = ?";
|
||||
|
||||
$description = ucfirst(str_replace('_', ' ', $key));
|
||||
$class_database->execute($sql, ["token_$key", $value, $description, $value]);
|
||||
}
|
||||
|
||||
return ['success' => true, 'message' => 'Token settings updated successfully!'];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return ['success' => false, 'message' => 'Error updating settings: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
function uploadTokenIcon($file) {
|
||||
if (!isset($file['tmp_name']) || $file['error'] !== UPLOAD_ERR_OK) {
|
||||
return ['success' => false, 'message' => 'No file uploaded or upload error'];
|
||||
}
|
||||
|
||||
// Validate file type
|
||||
$allowed_types = ['image/png', 'image/jpeg', 'image/gif', 'image/svg+xml'];
|
||||
if (!in_array($file['type'], $allowed_types)) {
|
||||
return ['success' => false, 'message' => 'Invalid file type. Please upload PNG, JPG, GIF, or SVG'];
|
||||
}
|
||||
|
||||
// Validate file size (max 2MB)
|
||||
if ($file['size'] > 2 * 1024 * 1024) {
|
||||
return ['success' => false, 'message' => 'File too large. Maximum size is 2MB'];
|
||||
}
|
||||
|
||||
try {
|
||||
$upload_dir = 'f_templates/tpl_frontend/img/tokens/';
|
||||
if (!is_dir($upload_dir)) {
|
||||
mkdir($upload_dir, 0755, true);
|
||||
}
|
||||
|
||||
$extension = pathinfo($file['name'], PATHINFO_EXTENSION);
|
||||
$filename = 'token_icon_' . time() . '.' . $extension;
|
||||
$filepath = $upload_dir . $filename;
|
||||
|
||||
if (move_uploaded_file($file['tmp_name'], $filepath)) {
|
||||
// Update database
|
||||
global $class_database;
|
||||
$sql = "INSERT INTO db_settings (setting_key, setting_value, setting_description)
|
||||
VALUES ('token_icon', ?, 'Token icon image path')
|
||||
ON DUPLICATE KEY UPDATE setting_value = ?";
|
||||
|
||||
$icon_path = '/' . $filepath;
|
||||
$class_database->execute($sql, [$icon_path, $icon_path]);
|
||||
|
||||
return ['success' => true, 'message' => 'Token icon uploaded successfully!'];
|
||||
} else {
|
||||
return ['success' => false, 'message' => 'Failed to upload file'];
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
return ['success' => false, 'message' => 'Upload error: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
function resetTokenDefaults() {
|
||||
global $class_database;
|
||||
|
||||
try {
|
||||
$sql = "DELETE FROM db_settings WHERE setting_key LIKE 'token_%'";
|
||||
$class_database->execute($sql);
|
||||
|
||||
return ['success' => true, 'message' => 'Token settings reset to defaults!'];
|
||||
|
||||
} catch (Exception $e) {
|
||||
return ['success' => false, 'message' => 'Error resetting settings: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Token Customization - EasyStream Admin</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
margin: 0;
|
||||
background: #f8f9fa;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||||
color: white;
|
||||
padding: 20px 0;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.header-content {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 30px 20px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
margin-bottom: 30px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
background: #f8f9fa;
|
||||
padding: 20px 30px;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 2px solid #e9ecef;
|
||||
border-radius: 8px;
|
||||
font-size: 1rem;
|
||||
transition: border-color 0.2s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 0 0 3px rgba(102,126,234,0.1);
|
||||
}
|
||||
|
||||
.color-input {
|
||||
width: 100px;
|
||||
height: 50px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 24px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #5a6fd8;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #5a6268;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #dc3545;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: #c82333;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
.token-preview {
|
||||
background: linear-gradient(135deg, var(--token-primary, #FFD700), var(--token-secondary, #FFA500));
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.token-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
margin: 0 auto 15px;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
border: 3px solid white;
|
||||
}
|
||||
|
||||
.token-name {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.token-symbol {
|
||||
font-size: 1rem;
|
||||
opacity: 0.9;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.token-description {
|
||||
font-size: 0.9rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
border: 2px dashed #e9ecef;
|
||||
border-radius: 8px;
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
transition: border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.upload-area:hover {
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
.upload-area.dragover {
|
||||
border-color: #667eea;
|
||||
background: #f8f9ff;
|
||||
}
|
||||
|
||||
.file-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.current-icon {
|
||||
max-width: 100px;
|
||||
max-height: 100px;
|
||||
border-radius: 8px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.form-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<div class="header-content">
|
||||
<h1>🪙 Token Customization</h1>
|
||||
<div>
|
||||
<a href="dashboard.php" class="btn btn-secondary">← Back to Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-error">
|
||||
<?php echo htmlspecialchars($error_message); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($success_message): ?>
|
||||
<div class="alert alert-success">
|
||||
<?php echo htmlspecialchars($success_message); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Token Preview -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
👁️ Live Preview
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="token-preview" style="--token-primary: <?php echo $token_settings['token_color_primary']; ?>; --token-secondary: <?php echo $token_settings['token_color_secondary']; ?>">
|
||||
<img src="<?php echo htmlspecialchars($token_settings['token_icon']); ?>" alt="Token Icon" class="token-icon" onerror="this.src='/f_templates/tpl_frontend/img/default-token.png'">
|
||||
<div class="token-name"><?php echo htmlspecialchars($token_settings['token_name']); ?></div>
|
||||
<div class="token-symbol"><?php echo htmlspecialchars($token_settings['token_symbol']); ?></div>
|
||||
<div class="token-description"><?php echo htmlspecialchars($token_settings['token_description']); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Token Settings -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
⚙️ Token Settings
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" id="token-settings-form">
|
||||
<input type="hidden" name="action" value="update_token_settings">
|
||||
|
||||
<div class="form-grid">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="token_name">Token Name</label>
|
||||
<input type="text" id="token_name" name="token_name" class="form-input"
|
||||
value="<?php echo htmlspecialchars($token_settings['token_name']); ?>"
|
||||
placeholder="e.g., EasyCoins" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="token_symbol">Token Symbol</label>
|
||||
<input type="text" id="token_symbol" name="token_symbol" class="form-input"
|
||||
value="<?php echo htmlspecialchars($token_settings['token_symbol']); ?>"
|
||||
placeholder="e.g., EC" maxlength="5" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="token_plural">Plural Form</label>
|
||||
<input type="text" id="token_plural" name="token_plural" class="form-input"
|
||||
value="<?php echo htmlspecialchars($token_settings['token_plural']); ?>"
|
||||
placeholder="e.g., EasyCoins" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="exchange_rate">Exchange Rate (USD)</label>
|
||||
<input type="number" id="exchange_rate" name="exchange_rate" class="form-input"
|
||||
value="<?php echo $token_settings['exchange_rate']; ?>"
|
||||
step="0.01" min="0.01" placeholder="1.00" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="min_purchase">Minimum Purchase</label>
|
||||
<input type="number" id="min_purchase" name="min_purchase" class="form-input"
|
||||
value="<?php echo $token_settings['min_purchase']; ?>"
|
||||
step="0.01" min="0.01" placeholder="1.00" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="max_purchase">Maximum Purchase</label>
|
||||
<input type="number" id="max_purchase" name="max_purchase" class="form-input"
|
||||
value="<?php echo $token_settings['max_purchase']; ?>"
|
||||
step="0.01" min="1" placeholder="1000.00" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="token_description">Description</label>
|
||||
<textarea id="token_description" name="token_description" class="form-input" rows="3"
|
||||
placeholder="Brief description of your platform currency"><?php echo htmlspecialchars($token_settings['token_description']); ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-grid">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="token_color_primary">Primary Color</label>
|
||||
<input type="color" id="token_color_primary" name="token_color_primary" class="color-input"
|
||||
value="<?php echo $token_settings['token_color_primary']; ?>">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="token_color_secondary">Secondary Color</label>
|
||||
<input type="color" id="token_color_secondary" name="token_color_secondary" class="color-input"
|
||||
value="<?php echo $token_settings['token_color_secondary']; ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" name="enabled" <?php echo $token_settings['enabled'] ? 'checked' : ''; ?>>
|
||||
Enable token system
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn">💾 Save Settings</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Token Icon Upload -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
🖼️ Token Icon
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" enctype="multipart/form-data" id="icon-upload-form">
|
||||
<input type="hidden" name="action" value="upload_token_icon">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Current Icon</label>
|
||||
<div>
|
||||
<img src="<?php echo htmlspecialchars($token_settings['token_icon']); ?>"
|
||||
alt="Current Token Icon" class="current-icon"
|
||||
onerror="this.src='/f_templates/tpl_frontend/img/default-token.png'">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="upload-area" onclick="document.getElementById('token_icon').click()">
|
||||
<div style="font-size: 3rem; margin-bottom: 15px;">📁</div>
|
||||
<div style="font-size: 1.1rem; margin-bottom: 10px;">Click to upload new token icon</div>
|
||||
<div style="color: #666; font-size: 0.9rem;">
|
||||
Supports PNG, JPG, GIF, SVG • Max 2MB • Recommended: 256x256px
|
||||
</div>
|
||||
<input type="file" id="token_icon" name="token_icon" class="file-input"
|
||||
accept="image/png,image/jpeg,image/gif,image/svg+xml"
|
||||
onchange="handleFileSelect(this)">
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px;">
|
||||
<button type="submit" class="btn">📤 Upload Icon</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reset Options -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
🔄 Reset Options
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p style="margin-bottom: 20px; color: #666;">
|
||||
Reset all token settings to default values. This action cannot be undone.
|
||||
</p>
|
||||
|
||||
<form method="POST" onsubmit="return confirm('Are you sure you want to reset all token settings to defaults?')">
|
||||
<input type="hidden" name="action" value="reset_to_defaults">
|
||||
<button type="submit" class="btn btn-danger">🔄 Reset to Defaults</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Live preview updates
|
||||
function updatePreview() {
|
||||
const preview = document.querySelector('.token-preview');
|
||||
const tokenName = document.getElementById('token_name').value;
|
||||
const tokenSymbol = document.getElementById('token_symbol').value;
|
||||
const tokenDescription = document.getElementById('token_description').value;
|
||||
const primaryColor = document.getElementById('token_color_primary').value;
|
||||
const secondaryColor = document.getElementById('token_color_secondary').value;
|
||||
|
||||
preview.style.setProperty('--token-primary', primaryColor);
|
||||
preview.style.setProperty('--token-secondary', secondaryColor);
|
||||
|
||||
preview.querySelector('.token-name').textContent = tokenName || 'Token Name';
|
||||
preview.querySelector('.token-symbol').textContent = tokenSymbol || 'SYM';
|
||||
preview.querySelector('.token-description').textContent = tokenDescription || 'Token description';
|
||||
}
|
||||
|
||||
// Add event listeners for live preview
|
||||
document.getElementById('token_name').addEventListener('input', updatePreview);
|
||||
document.getElementById('token_symbol').addEventListener('input', updatePreview);
|
||||
document.getElementById('token_description').addEventListener('input', updatePreview);
|
||||
document.getElementById('token_color_primary').addEventListener('change', updatePreview);
|
||||
document.getElementById('token_color_secondary').addEventListener('change', updatePreview);
|
||||
|
||||
// File upload handling
|
||||
function handleFileSelect(input) {
|
||||
if (input.files && input.files[0]) {
|
||||
const file = input.files[0];
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
document.querySelector('.current-icon').src = e.target.result;
|
||||
document.querySelector('.token-icon').src = e.target.result;
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
|
||||
// Drag and drop for file upload
|
||||
const uploadArea = document.querySelector('.upload-area');
|
||||
|
||||
uploadArea.addEventListener('dragover', function(e) {
|
||||
e.preventDefault();
|
||||
this.classList.add('dragover');
|
||||
});
|
||||
|
||||
uploadArea.addEventListener('dragleave', function(e) {
|
||||
e.preventDefault();
|
||||
this.classList.remove('dragover');
|
||||
});
|
||||
|
||||
uploadArea.addEventListener('drop', function(e) {
|
||||
e.preventDefault();
|
||||
this.classList.remove('dragover');
|
||||
|
||||
const files = e.dataTransfer.files;
|
||||
if (files.length > 0) {
|
||||
document.getElementById('token_icon').files = files;
|
||||
handleFileSelect(document.getElementById('token_icon'));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user