diff --git a/backend/main.py b/backend/main.py
new file mode 100644
index 0000000..d1b5f22
--- /dev/null
+++ b/backend/main.py
@@ -0,0 +1,49 @@
+from fastapi import FastAPI, File, UploadFile
+from fastapi.middleware.cors import CORSMiddleware
+
+from typing import Annotated
+
+import dotenv
+import os
+
+import asyncio
+import uvicorn
+
+
+dotenv.load_dotenv()
+disable_docs = os.getenv("DISABLE_DOCS", "true").lower() == "true"
+app: FastAPI = FastAPI(title="This OR That",
+ summary="OpenAPI schema for \"This OR That\" project!",
+ version="0.1",
+ contact={"GitHub": "https://github.com/IgorVolochay/thisORthat"},
+ docs_url=None if disable_docs else "/docs",
+ redoc_url=None if disable_docs else "/redoc",
+ openapi_url=None if disable_docs else "/openapi.json")
+
+
+origins = ["*"]
+
+app.add_middleware(
+ CORSMiddleware,
+ allow_origins=origins,
+ allow_credentials=True,
+ allow_methods=["*"],
+ allow_headers=["*"],
+)
+
+@app.get("/")
+def root():
+ return "Hello!"
+
+@app.post("/upload_file")
+@app.post("/upload_file")
+async def create_file(file: Annotated[bytes, File()]):
+ return {"file_size": len(file)}
+
+async def main():
+ config = uvicorn.Config("main:app", port=5000, log_level="debug")
+ server = uvicorn.Server(config)
+ await server.serve()
+
+if __name__ == "__main__":
+ asyncio.run(main())
\ No newline at end of file
diff --git a/backend/pyproject.toml b/backend/pyproject.toml
new file mode 100644
index 0000000..9f799ca
--- /dev/null
+++ b/backend/pyproject.toml
@@ -0,0 +1,12 @@
+[project]
+name = "drop-me-files-analog"
+version = "0.1.0"
+description = ""
+readme = "README.md"
+requires-python = ">=3.11"
+dependencies = [
+ "dotenv>=0.9.9",
+ "fastapi>=0.121.1",
+ "python-multipart>=0.0.20",
+ "uvicorn>=0.38.0",
+]
diff --git a/frontend/index.html b/frontend/index.html
new file mode 100644
index 0000000..6786f81
--- /dev/null
+++ b/frontend/index.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+ Аналог DropMeFiles
+
+
+
+ Аналог DropMeFiles
+
+
+
+
+
diff --git a/frontend/script.js b/frontend/script.js
new file mode 100644
index 0000000..6f6a61f
--- /dev/null
+++ b/frontend/script.js
@@ -0,0 +1,77 @@
+const fileInput = document.getElementById('fileInput');
+const dropzone = document.getElementById('dropzone');
+const uploadButton = document.getElementById('uploadButton');
+const uploadForm = document.getElementById('uploadForm');
+const statusDiv = document.getElementById('status');
+
+const updateButtonState = () => {
+ uploadButton.disabled = !fileInput.files || fileInput.files.length === 0;
+};
+
+const setStatus = (message, type = '') => {
+ statusDiv.textContent = message;
+ statusDiv.className = type ? `status ${type}` : 'status';
+};
+
+dropzone.addEventListener('dragover', (event) => {
+ event.preventDefault();
+ dropzone.classList.add('dragover');
+});
+
+dropzone.addEventListener('dragleave', () => {
+ dropzone.classList.remove('dragover');
+});
+
+dropzone.addEventListener('drop', (event) => {
+ event.preventDefault();
+ dropzone.classList.remove('dragover');
+
+ if (event.dataTransfer?.files?.length) {
+ fileInput.files = event.dataTransfer.files;
+ updateButtonState();
+ }
+});
+
+fileInput.addEventListener('change', () => {
+ updateButtonState();
+});
+
+uploadForm.addEventListener('submit', async (event) => {
+ event.preventDefault();
+
+ if (!fileInput.files || fileInput.files.length === 0) {
+ setStatus('Выберите файлов для загрузки.', 'error');
+ return;
+ }
+
+ const formData = new FormData();
+ Array.from(fileInput.files).forEach((file) => {
+ formData.append('files', file);
+ });
+
+ uploadButton.disabled = true;
+ dropzone.classList.remove('dragover');
+ setStatus('Загрузка...', '');
+
+ try {
+ const response = await fetch('http://192.168.0.132:5000/upload_file', {
+ method: 'POST',
+ body: formData
+ });
+
+ if (!response.ok) {
+ throw new Error(`Ошибка сервера: ${response.status}`);
+ }
+
+ const data = await response.text();
+ setStatus(`Путь к файлу: ${data}`, 'success');
+ fileInput.value = '';
+ } catch (error) {
+ setStatus(`Не удалось загрузить файлы: ${error.message}`, 'error');
+ } finally {
+ uploadButton.disabled = false;
+ }
+});
+
+updateButtonState();
+
diff --git a/frontend/style.css b/frontend/style.css
new file mode 100644
index 0000000..3036f50
--- /dev/null
+++ b/frontend/style.css
@@ -0,0 +1,110 @@
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ font-family: Arial, sans-serif;
+ background: radial-gradient(circle at top, #f7f7fb, #eff1f8);
+ color: #111827;
+ padding: 24px;
+}
+
+h1 {
+ font-size: clamp(32px, 4vw, 48px);
+ margin-bottom: 32px;
+ text-align: center;
+}
+
+.upload-container {
+ width: min(640px, 100%);
+ background: #ffffffdd;
+ border-radius: 20px;
+ box-shadow: 0 20px 45px -20px rgba(15, 23, 42, 0.65);
+ padding: 32px;
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+ backdrop-filter: blur(8px);
+}
+
+.dropzone {
+ border: 2px dashed #6366f1;
+ border-radius: 16px;
+ padding: 48px 24px;
+ text-align: center;
+ transition: all 0.2s ease;
+ background: rgba(99, 102, 241, 0.04);
+ cursor: pointer;
+ position: relative;
+}
+
+.dropzone.dragover {
+ background: rgba(99, 102, 241, 0.12);
+ transform: translateY(-2px);
+ box-shadow: 0 14px 28px -24px rgba(99, 102, 241, 0.65);
+}
+
+.dropzone input[type="file"] {
+ position: absolute;
+ inset: 0;
+ opacity: 0;
+ cursor: pointer;
+}
+
+.dropzone p {
+ margin: 8px 0;
+ color: #4b5563;
+ font-size: 16px;
+}
+
+.dropzone p.strong {
+ font-weight: 600;
+ color: #1f2937;
+ font-size: 18px;
+}
+
+button {
+ background: linear-gradient(135deg, #6366f1, #8b5cf6);
+ color: white;
+ border: none;
+ border-radius: 12px;
+ padding: 14px 20px;
+ font-size: 16px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+}
+
+button:hover:not(:disabled) {
+ transform: translateY(-1px);
+ box-shadow: 0 16px 32px -24px rgba(99, 102, 241, 0.8);
+}
+
+button:disabled {
+ background: #cbd5f5;
+ cursor: not-allowed;
+ box-shadow: none;
+}
+
+.status {
+ min-height: 24px;
+ font-size: 15px;
+ color: #374151;
+ line-height: 1.5;
+ word-break: break-all;
+}
+
+.status.error {
+ color: #dc2626;
+}
+
+.status.success {
+ color: #166534;
+}
+