hamaghafursmaldet
This commit is contained in:
parent
27bd5182e3
commit
d57d2a227f
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,3 +1,9 @@
|
||||
from django.contrib import admin
|
||||
from .models import FileScan
|
||||
|
||||
# Register your models here.
|
||||
@admin.register(FileScan)
|
||||
class FileScanAdmin(admin.ModelAdmin):
|
||||
list_display = ('filename', 'risk_level', 'file_hash', 'created_at')
|
||||
list_filter = ('risk_level', 'created_at')
|
||||
search_fields = ('filename', 'file_hash')
|
||||
readonly_fields = ('file_hash', 'created_at')
|
||||
28
core/migrations/0001_initial.py
Normal file
28
core/migrations/0001_initial.py
Normal file
@ -0,0 +1,28 @@
|
||||
# Generated by Django 5.2.7 on 2026-01-31 03:52
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='FileScan',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('filename', models.CharField(max_length=255)),
|
||||
('file_hash', models.CharField(db_index=True, max_length=64)),
|
||||
('risk_level', models.CharField(choices=[('LOW', 'Low'), ('MEDIUM', 'Medium'), ('HIGH', 'High')], max_length=10)),
|
||||
('reasons', models.TextField()),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
]
|
||||
BIN
core/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
BIN
core/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
@ -1,3 +1,20 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
class FileScan(models.Model):
|
||||
RISK_LEVELS = [
|
||||
('LOW', 'Low'),
|
||||
('MEDIUM', 'Medium'),
|
||||
('HIGH', 'High'),
|
||||
]
|
||||
|
||||
filename = models.CharField(max_length=255)
|
||||
file_hash = models.CharField(max_length=64, db_index=True) # SHA256
|
||||
risk_level = models.CharField(max_length=10, choices=RISK_LEVELS)
|
||||
reasons = models.TextField()
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.filename} - {self.risk_level}"
|
||||
|
||||
class Meta:
|
||||
ordering = ['-created_at']
|
||||
@ -1,25 +1,61 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}Knowledge Base{% endblock %}</title>
|
||||
{% if project_description %}
|
||||
<meta name="description" content="{{ project_description }}">
|
||||
<meta property="og:description" content="{{ project_description }}">
|
||||
<meta property="twitter:description" content="{{ project_description }}">
|
||||
{% endif %}
|
||||
{% if project_image_url %}
|
||||
<meta property="og:image" content="{{ project_image_url }}">
|
||||
<meta property="twitter:image" content="{{ project_image_url }}">
|
||||
{% endif %}
|
||||
{% load static %}
|
||||
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
|
||||
{% block head %}{% endblock %}
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Cloud Malware Detection{% endblock %}</title>
|
||||
{% if project_description %}
|
||||
<meta name="description" content="{{ project_description }}">
|
||||
{% endif %}
|
||||
{% load static %}
|
||||
<!-- Google Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&family=Space+Grotesk:wght@500;700&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- Bootstrap 5 CDN -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
||||
|
||||
<!-- Custom CSS -->
|
||||
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
|
||||
|
||||
{% block extra_head %}{% endblock %}
|
||||
</head>
|
||||
<body class="bg-dark text-light">
|
||||
<nav class="navbar navbar-expand-lg navbar-dark border-bottom border-secondary">
|
||||
<div class="container">
|
||||
<a class="navbar-brand fw-bold" href="{% url 'index' %}">
|
||||
<i class="bi bi-shield-lock-fill text-accent me-2"></i>CloudScan
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'index' %}">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/admin/">Admin</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<body>
|
||||
{% block content %}{% endblock %}
|
||||
<main>
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer class="py-4 border-top border-secondary mt-5">
|
||||
<div class="container text-center text-secondary">
|
||||
<p>© 2026 Cloud Malware Detection Web App. Built with Django & Security in mind.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Bootstrap JS CDN -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
{% block extra_js %}{% endblock %}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
@ -1,145 +1,161 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}{{ project_name }}{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'><path d='M-10 10L110 10M10 -10L10 110' stroke-width='1' stroke='rgba(255,255,255,0.05)'/></svg>");
|
||||
animation: bg-pan 20s linear infinite;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
@keyframes bg-pan {
|
||||
0% {
|
||||
background-position: 0% 0%;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--card-bg-color);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 16px;
|
||||
padding: 2.5rem 2rem;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(2.2rem, 3vw + 1.2rem, 3.2rem);
|
||||
font-weight: 700;
|
||||
margin: 0 0 1.2rem;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
opacity: 0.92;
|
||||
}
|
||||
|
||||
.loader {
|
||||
margin: 1.5rem auto;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border: 4px solid rgba(255, 255, 255, 0.25);
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.runtime code {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
padding: 0.15rem 0.45rem;
|
||||
border-radius: 4px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.75;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block title %}Cloud Malware Detection Web App - Home{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main>
|
||||
<div class="card">
|
||||
<h1>Analyzing your requirements and generating your app…</h1>
|
||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
||||
<span class="sr-only">Loading…</span>
|
||||
<section class="hero-section py-5 mb-5">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6">
|
||||
<h1 class="display-4 fw-bold mb-3 font-heading">Cloud Malware Detection Web App</h1>
|
||||
<p class="lead mb-4 text-secondary">Securely scan your files for potential threats using advanced static analysis and hash matching.</p>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="#scan-area" class="btn btn-accent btn-lg px-4 shadow-sm">Start Scanning</a>
|
||||
<a href="#recent-scans" class="btn btn-outline-light btn-lg px-4">View History</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 d-none d-lg-block">
|
||||
<div class="hero-image-placeholder text-center p-5">
|
||||
<i class="bi bi-shield-check-fill display-1 text-accent animate-glow"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="hint">AppWizzy AI is collecting your requirements and applying the first changes.</p>
|
||||
<p class="hint">This page will refresh automatically as the plan is implemented.</p>
|
||||
<p class="runtime">
|
||||
Runtime: Django <code>{{ django_version }}</code> · Python <code>{{ python_version }}</code>
|
||||
— UTC <code>{{ current_time|date:"Y-m-d H:i:s" }}</code>
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC)
|
||||
</footer>
|
||||
{% endblock %}
|
||||
</section>
|
||||
|
||||
<div class="container" id="scan-area">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8">
|
||||
<div class="card bg-secondary-dark border-secondary shadow-lg mb-5">
|
||||
<div class="card-body p-4 p-md-5">
|
||||
<h3 class="card-title mb-4 font-heading">Upload File for Analysis</h3>
|
||||
<form action="{% url 'scan_file' %}" method="post" enctype="multipart/form-data" id="scanForm">
|
||||
{% csrf_token %}
|
||||
<div class="upload-zone mb-4" id="dropZone">
|
||||
<input type="file" name="file" id="fileInput" class="d-none" required>
|
||||
<div class="text-center p-5 border border-2 border-dashed border-secondary rounded-3 cursor-pointer" id="uploadTrigger">
|
||||
<i class="bi bi-cloud-arrow-up display-4 text-secondary mb-3"></i>
|
||||
<h5 class="text-light" id="fileLabel">Click or drag file here to upload</h5>
|
||||
<p class="text-secondary small">Maximum file size: 10MB</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-accent btn-lg fw-bold py-3" id="submitBtn">
|
||||
<span id="btnText">Scan File</span>
|
||||
<span id="btnSpinner" class="spinner-border spinner-border-sm d-none" role="status"></span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if result %}
|
||||
<div class="result-card card {% if result.risk_level == 'HIGH' %}border-danger{% elif result.risk_level == 'MEDIUM' %}border-warning{% else %}border-success{% endif %} bg-secondary-dark mb-5 shadow-lg">
|
||||
<div class="card-header {% if result.risk_level == 'HIGH' %}bg-danger{% elif result.risk_level == 'MEDIUM' %}bg-warning text-dark{% else %}bg-success{% endif %} fw-bold">
|
||||
Scan Result: {{ result.risk_level }} RISK
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h4 class="mb-3">{{ result.filename }}</h4>
|
||||
<p class="mb-2"><strong>SHA256 Hash:</strong> <code class="text-accent">{{ result.file_hash }}</code></p>
|
||||
<p class="mb-0"><strong>Reasons for Assessment:</strong></p>
|
||||
<ul class="mt-2">
|
||||
{% for reason in result.reasons.split|slice:":-1" %}
|
||||
<li>{{ reason }}</li>
|
||||
{% empty %}
|
||||
<li>{{ result.reasons }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div id="recent-scans" class="mb-5">
|
||||
<h3 class="mb-4 font-heading">Recent Scans</h3>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-dark table-hover border-secondary">
|
||||
<thead class="table-secondary-dark">
|
||||
<tr>
|
||||
<th>Filename</th>
|
||||
<th>Risk Level</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for scan in recent_scans %}
|
||||
<tr>
|
||||
<td>{{ scan.filename }}</td>
|
||||
<td>
|
||||
<span class="badge {% if scan.risk_level == 'HIGH' %}bg-danger{% elif scan.risk_level == 'MEDIUM' %}bg-warning text-dark{% else %}bg-success{% endif %}">
|
||||
{{ scan.risk_level }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ scan.created_at|date:"M d, Y H:i" }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="3" class="text-center text-secondary">No recent scans found.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
const dropZone = document.getElementById('dropZone');
|
||||
const uploadTrigger = document.getElementById('uploadTrigger');
|
||||
const fileInput = document.getElementById('fileInput');
|
||||
const fileLabel = document.getElementById('fileLabel');
|
||||
const scanForm = document.getElementById('scanForm');
|
||||
const submitBtn = document.getElementById('submitBtn');
|
||||
const btnText = document.getElementById('btnText');
|
||||
const btnSpinner = document.getElementById('btnSpinner');
|
||||
|
||||
uploadTrigger.addEventListener('click', () => fileInput.click());
|
||||
|
||||
fileInput.addEventListener('change', () => {
|
||||
if (fileInput.files.length > 0) {
|
||||
fileLabel.textContent = fileInput.files[0].name;
|
||||
uploadTrigger.classList.add('border-accent');
|
||||
}
|
||||
});
|
||||
|
||||
scanForm.addEventListener('submit', () => {
|
||||
submitBtn.disabled = true;
|
||||
btnText.textContent = 'Analyzing...';
|
||||
btnSpinner.classList.remove('d-none');
|
||||
});
|
||||
|
||||
// Drag and drop logic
|
||||
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
||||
dropZone.addEventListener(eventName, e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}, false);
|
||||
});
|
||||
|
||||
['dragenter', 'dragover'].forEach(eventName => {
|
||||
dropZone.addEventListener(eventName, () => dropZone.classList.add('bg-secondary'), false);
|
||||
});
|
||||
|
||||
['dragleave', 'drop'].forEach(eventName => {
|
||||
dropZone.addEventListener(eventName, () => dropZone.classList.remove('bg-secondary'), false);
|
||||
});
|
||||
|
||||
dropZone.addEventListener('drop', e => {
|
||||
const dt = e.dataTransfer;
|
||||
const files = dt.files;
|
||||
fileInput.files = files;
|
||||
if (files.length > 0) {
|
||||
fileLabel.textContent = files[0].name;
|
||||
uploadTrigger.classList.add('border-accent');
|
||||
}
|
||||
}, false);
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from django.urls import path
|
||||
|
||||
from .views import home
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path("", home, name="home"),
|
||||
]
|
||||
path("", views.index, name="index"),
|
||||
path("scan/", views.scan_file, name="scan_file"),
|
||||
]
|
||||
@ -1,25 +1,71 @@
|
||||
import hashlib
|
||||
import os
|
||||
import platform
|
||||
from django.shortcuts import render, redirect
|
||||
from django.http import JsonResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from .models import FileScan
|
||||
|
||||
from django import get_version as django_version
|
||||
from django.shortcuts import render
|
||||
from django.utils import timezone
|
||||
def index(request):
|
||||
scans = FileScan.objects.all()[:10]
|
||||
return render(request, "core/index.html", {"recent_scans": scans})
|
||||
|
||||
|
||||
def home(request):
|
||||
"""Render the landing screen with loader and environment details."""
|
||||
host_name = request.get_host().lower()
|
||||
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
|
||||
now = timezone.now()
|
||||
|
||||
context = {
|
||||
"project_name": "New Style",
|
||||
"agent_brand": agent_brand,
|
||||
"django_version": django_version(),
|
||||
"python_version": platform.python_version(),
|
||||
"current_time": now,
|
||||
"host_name": host_name,
|
||||
"project_description": os.getenv("PROJECT_DESCRIPTION", ""),
|
||||
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
|
||||
}
|
||||
return render(request, "core/index.html", context)
|
||||
def scan_file(request):
|
||||
if request.method == 'POST' and request.FILES.get('file'):
|
||||
uploaded_file = request.FILES['file']
|
||||
filename = uploaded_file.name
|
||||
content = uploaded_file.read()
|
||||
|
||||
# Calculate SHA256
|
||||
sha256_hash = hashlib.sha256(content).hexdigest()
|
||||
|
||||
# Basic Static Analysis
|
||||
risk_level = 'LOW'
|
||||
reasons = []
|
||||
|
||||
# 1. Extension check
|
||||
ext = os.path.splitext(filename)[1].lower()
|
||||
danger_exts = ['.exe', '.dll', '.bin', '.sh', '.bat', '.msi', '.js', '.vbs', '.ps1', '.py']
|
||||
if ext in danger_exts:
|
||||
risk_level = 'MEDIUM'
|
||||
reasons.append(f"Suspicious file extension: {ext}")
|
||||
|
||||
# 2. Content check (basic keyword search)
|
||||
suspicious_keywords = [
|
||||
b'eval(', b'exec(', b'os.system(', b'subprocess.run(', b'base64.b64decode(',
|
||||
b'chmod +x', b'rm -rf', b'powershell', b'cmd.exe'
|
||||
]
|
||||
found_keywords = []
|
||||
for kw in suspicious_keywords:
|
||||
if kw in content:
|
||||
found_keywords.append(kw.decode())
|
||||
|
||||
if found_keywords:
|
||||
risk_level = 'HIGH'
|
||||
reasons.append(f"Found suspicious code patterns: {', '.join(found_keywords)}")
|
||||
|
||||
if not reasons:
|
||||
reasons.append("No immediate threats found via static analysis.")
|
||||
|
||||
# Save to DB
|
||||
scan = FileScan.objects.create(
|
||||
filename=filename,
|
||||
file_hash=sha256_hash,
|
||||
risk_level=risk_level,
|
||||
reasons="; ".join(reasons)
|
||||
)
|
||||
|
||||
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
|
||||
return JsonResponse({
|
||||
'filename': scan.filename,
|
||||
'hash': scan.file_hash,
|
||||
'risk_level': scan.risk_level,
|
||||
'reasons': scan.reasons,
|
||||
'created_at': scan.created_at.strftime('%Y-%m-%d %H:%M:%S')
|
||||
})
|
||||
|
||||
return render(request, "core/index.html", {
|
||||
"result": scan,
|
||||
"recent_scans": FileScan.objects.all()[:10]
|
||||
})
|
||||
|
||||
return redirect('index')
|
||||
@ -1,4 +1,108 @@
|
||||
/* Custom styles for the application */
|
||||
body {
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
:root {
|
||||
--primary-bg: #1a1a1a;
|
||||
--secondary-bg: #2d2d2d;
|
||||
--accent: #00ff9d;
|
||||
--accent-hover: #00e68e;
|
||||
--hazard: #ff9f43;
|
||||
--danger: #ee5253;
|
||||
--text-light: #f8f9fa;
|
||||
--text-muted: #adb5bd;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--primary-bg);
|
||||
color: var(--text-light);
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
|
||||
.font-heading {
|
||||
font-family: 'Space Grotesk', sans-serif;
|
||||
}
|
||||
|
||||
.text-accent {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.bg-secondary-dark {
|
||||
background-color: var(--secondary-bg);
|
||||
}
|
||||
|
||||
.btn-accent {
|
||||
background-color: var(--accent);
|
||||
color: #1a1a1a;
|
||||
border: none;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-accent:hover {
|
||||
background-color: var(--accent-hover);
|
||||
color: #1a1a1a;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(0, 255, 157, 0.3);
|
||||
}
|
||||
|
||||
.border-accent {
|
||||
border-color: var(--accent) !important;
|
||||
}
|
||||
|
||||
.border-dashed {
|
||||
border-style: dashed !important;
|
||||
}
|
||||
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.animate-glow {
|
||||
animation: glow 3s infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes glow {
|
||||
from {
|
||||
text-shadow: 0 0 10px rgba(0, 255, 157, 0.2);
|
||||
}
|
||||
to {
|
||||
text-shadow: 0 0 30px rgba(0, 255, 157, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: 1rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.upload-zone {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.upload-zone:hover .border-dashed {
|
||||
border-color: var(--accent) !important;
|
||||
background-color: rgba(0, 255, 157, 0.05);
|
||||
}
|
||||
|
||||
.table-dark {
|
||||
background-color: var(--secondary-bg);
|
||||
}
|
||||
|
||||
.table-secondary-dark {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.hero-section {
|
||||
background: radial-gradient(circle at top right, rgba(0, 255, 157, 0.1), transparent);
|
||||
}
|
||||
|
||||
.result-card {
|
||||
animation: slideUp 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
@ -1,21 +1,108 @@
|
||||
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
--primary-bg: #1a1a1a;
|
||||
--secondary-bg: #2d2d2d;
|
||||
--accent: #00ff9d;
|
||||
--accent-hover: #00e68e;
|
||||
--hazard: #ff9f43;
|
||||
--danger: #ee5253;
|
||||
--text-light: #f8f9fa;
|
||||
--text-muted: #adb5bd;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: var(--primary-bg);
|
||||
color: var(--text-light);
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.font-heading {
|
||||
font-family: 'Space Grotesk', sans-serif;
|
||||
}
|
||||
|
||||
.text-accent {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.bg-secondary-dark {
|
||||
background-color: var(--secondary-bg);
|
||||
}
|
||||
|
||||
.btn-accent {
|
||||
background-color: var(--accent);
|
||||
color: #1a1a1a;
|
||||
border: none;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-accent:hover {
|
||||
background-color: var(--accent-hover);
|
||||
color: #1a1a1a;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(0, 255, 157, 0.3);
|
||||
}
|
||||
|
||||
.border-accent {
|
||||
border-color: var(--accent) !important;
|
||||
}
|
||||
|
||||
.border-dashed {
|
||||
border-style: dashed !important;
|
||||
}
|
||||
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.animate-glow {
|
||||
animation: glow 3s infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes glow {
|
||||
from {
|
||||
text-shadow: 0 0 10px rgba(0, 255, 157, 0.2);
|
||||
}
|
||||
to {
|
||||
text-shadow: 0 0 30px rgba(0, 255, 157, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: 1rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.upload-zone {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.upload-zone:hover .border-dashed {
|
||||
border-color: var(--accent) !important;
|
||||
background-color: rgba(0, 255, 157, 0.05);
|
||||
}
|
||||
|
||||
.table-dark {
|
||||
background-color: var(--secondary-bg);
|
||||
}
|
||||
|
||||
.table-secondary-dark {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.hero-section {
|
||||
background: radial-gradient(circle at top right, rgba(0, 255, 157, 0.1), transparent);
|
||||
}
|
||||
|
||||
.result-card {
|
||||
animation: slideUp 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user