diff --git a/handlers.py b/handlers.py index 62b22b4..e17f8b3 100644 --- a/handlers.py +++ b/handlers.py @@ -58,56 +58,46 @@ class FileServerHandler(BaseHTTPRequestHandler): def handle_main_page(self): content = f""" - - - - SimpliestFS - - - -

SimpliestFS

-

EN: {CONFIG["ui"]["disclaimer"]}

-

RU: {CONFIG["ui"]["disclaimer_ru"]}

-

Contact: {CONFIG["ui"]["contact_email"]}

-

Contact (prefered): @justuser_31

-

- Register - Login - Explore Files -

-
- Note: NO ENCRYPTION, no external databases. As simple as possible. -
- - + + + + SimpliestFS + + + +

SimpliestFS

+

EN: {CONFIG["ui"]["disclaimer"]}

+

RU: {CONFIG["ui"]["disclaimer_ru"]}

+

Contact: {CONFIG["ui"]["contact_email"]}

+

Contact (prefered): @justuser_31

+

+ Register + Login + Explore Files +

+
+ Note: NO ENCRYPTION, no external databases. As simple as possible. +
+ + """ self.send_html(content) def handle_register_page(self): content = f""" - - - - Register - SimpliestFS - - - -

SimpliestFS

-

Register

-

{CONFIG["ui"]["register_info"]}

-

Back to Home

- - + + + + Register - SimpliestFS + + + +

SimpliestFS

+

Register

+

{CONFIG["ui"]["register_info"]}

+

Back to Home

+ + """ self.send_html(content) @@ -161,31 +151,24 @@ class FileServerHandler(BaseHTTPRequestHandler): def render_login_form(self, error=""): content = f""" - - - - Login - SimpliestFS - - - -

SimpliestFS

-

Login

- {f'

{error}

' if error else ""} -
- - - -
-

Back to Home

- - + + + + Login - SimpliestFS + + + +

SimpliestFS

+

Login

+ {f'

{error}

' if error else ""} +
+ + + +
+

Back to Home

+ + """ return content @@ -227,37 +210,30 @@ class FileServerHandler(BaseHTTPRequestHandler): """ content = f""" - - - - My Files - SimpliestFS - - - -

SimpliestFS

-

My Files

-
- Quota: {available_mb} MB | Used: {used_mb:.2f} MB -
-
- - -
-
- {files_html if files_html else "

No files yet.

"} -

- Logout - Back to Home -

- - + + + + My Files - SimpliestFS + + + +

SimpliestFS

+

My Files

+
+ Quota: {available_mb} MB | Used: {used_mb:.2f} MB +
+
+ + +
+
+ {files_html if files_html else "

No files yet.

"} +

+ Logout + Back to Home +

+ + """ self.send_html(content) @@ -405,11 +381,7 @@ class FileServerHandler(BaseHTTPRequestHandler): Explore Files - SimpliestFS - +

SimpliestFS

@@ -448,11 +420,7 @@ class FileServerHandler(BaseHTTPRequestHandler): {username}'s Files - SimpliestFS - +

SimpliestFS

@@ -573,6 +541,41 @@ class FileServerHandler(BaseHTTPRequestHandler): database.DB_CONN.commit() self.send_html("

Account deleted

") + def handle_static_file(self): + if self.path.startswith("/static/"): + file_path = self.path[1:] # Remove leading slash + try: + with open(file_path, "r") as file: + content = file.read() + if file_path.endswith(".css"): + self.send_response(200) + self.send_header("Content-type", "text/css") + self.end_headers() + self.wfile.write(content.encode()) + else: + self.send_error(404) + except FileNotFoundError: + self.send_error(404) + return True + return False + + def handle_favicon(self): + if self.path == "/favicon.ico": + file_path = os.path.join("static", self.path[1:]) + try: + with open(file_path, "rb") as file: # Open in binary mode + content = file.read() + self.send_response(200) + self.send_header( + "Content-type", "image/x-icon" + ) # Correct MIME type + self.end_headers() + self.wfile.write(content) # Write bytes directly + except FileNotFoundError: + self.send_error(404) + return True + return False + def do_GET(self): parsed_path = urlparse(self.path) path = parsed_path.path @@ -597,6 +600,10 @@ class FileServerHandler(BaseHTTPRequestHandler): else: username = parts[0] self.handle_explore_user(username) + elif path.startswith("/static/") and not path.endswith("/"): + self.handle_static_file() + elif path == "/favicon.ico": + self.handle_favicon() else: self.send_html("

Not Found

", 404) diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..d79f055 Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..05722c8 --- /dev/null +++ b/static/style.css @@ -0,0 +1,332 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} +body { + font-family: + -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", + Arial, sans-serif; + margin: 0; + padding: 20px; + font-size: 16px; + line-height: 1.6; + color: #2c3e50; + background-color: #f8f9fa; + min-height: 100vh; +} +.container { + max-width: 900px; + margin: 0 auto; +} +h1 { + text-align: center; + margin: 30px 0; + font-size: 32px; + font-weight: 600; + color: #1a1a1a; +} +h1 a { + text-decoration: none; + color: inherit; + transition: color 0.2s; +} +h1 a:hover { + color: #4a5568; +} +h2 { + font-size: 24px; + font-weight: 500; + margin: 20px 0; + color: #2d3748; + text-align: center; +} +p { + margin: 12px 0; + color: #4a5568; +} +a { + color: #2c5282; + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +hr { + border: none; + border-top: 1px solid #e2e8f0; + margin: 30px 0; +} +.btn, +.back-btn, +.upload-btn, +.regular-button, +button[type="submit"] { + display: inline-block; + padding: 12px 24px; + background: #ffffff; + border: 1px solid #cbd5e0; + border-radius: 6px; + text-decoration: none; + color: #2d3748; + font-size: 15px; + font-weight: 500; + text-align: center; + cursor: pointer; + transition: all 0.2s; + font-family: inherit; +} +.btn:hover, +.back-btn:hover, +.upload-btn:hover, +.regular-button:hover, +button[type="submit"]:hover { + background: #f7fafc; + border-color: #a0aec0; + text-decoration: none; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); +} +.back-btn, +.upload-btn { + margin: 5px; +} +.main-page { + text-align: center; + max-width: 700px; + margin: 0 auto; +} +.main-page h1 { + font-size: 40px; + margin-bottom: 40px; +} +.main-page p { + margin: 20px auto; + max-width: 600px; + font-size: 15px; +} +.main-page .btn { + font-size: 16px; + padding: 14px 32px; + margin: 8px; + min-width: 160px; +} +.main-page .disclaimer { + margin-top: 50px; + padding: 20px; + background-color: #edf2f7; + border-radius: 8px; + border: 1px solid #cbd5e0; + font-size: 14px; + color: #4a5568; +} +.error { + color: #c53030; + background-color: #fff5f5; + padding: 12px 16px; + border-radius: 6px; + border: 1px solid #feb2b2; + margin: 20px 0; + text-align: center; +} +.quota-info { + margin: 25px 0; + padding: 12px 20px; + font-size: 14px; + color: #4a5568; + text-align: center; + background-color: #edf2f7; + border-radius: 6px; + border: 1px solid #cbd5e0; +} +.login-form { + max-width: 420px; + margin: 30px auto; + padding: 30px; + background-color: #ffffff; + border-radius: 8px; + border: 1px solid #e2e8f0; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); +} +.login-form input { + width: 100%; + padding: 14px 16px; + margin: 10px 0; + font-size: 15px; + border: 1px solid #cbd5e0; + border-radius: 6px; + background-color: #ffffff; + font-family: inherit; +} +.login-form input:focus { + outline: none; + border-color: #4299e1; + box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.1); +} +.login-form button { + width: 100%; + margin-top: 10px; +} +form[action="/upload"] { + margin: 25px 0; + padding: 20px; + background-color: #ffffff; + border-radius: 8px; + border: 1px solid #e2e8f0; + text-align: center; +} +input[type="file"] { + padding: 10px; + margin: 10px; + border: 1px solid #cbd5e0; + border-radius: 6px; + background-color: #ffffff; + cursor: pointer; +} +.files-list-item, +div[style*="margin: 5px 0"] { + margin: 12px 0 !important; + padding: 14px 16px !important; + display: flex !important; + align-items: center !important; + border: 1px solid #e2e8f0 !important; + border-radius: 6px !important; + background-color: #ffffff !important; +} +.files-list-item:hover, +div[style*="margin: 5px 0"]:hover { + background-color: #f7fafc !important; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05) !important; +} +.files-list-item span, +div[style*="margin: 5px 0"] span { + flex: 1 !important; + text-align: left !important; +} +.files-list-item a, +div[style*="margin: 5px 0"] a { + font-weight: 500; + color: #2c5282; + word-break: break-all; +} +.files-list-item form, +div[style*="margin: 5px 0"] form { + display: inline !important; + margin-left: 10px !important; +} +.files-list-item button, +div[style*="margin: 5px 0"] button { + padding: 8px 16px !important; + font-size: 14px !important; + margin: 0 !important; +} +div[style*="margin: 5px 0"] a:only-child { + display: block; + padding: 12px 16px; + font-weight: 500; +} +p a.back-btn { + display: inline-block; + margin: 10px 5px; +} + +@media (max-width: 768px) { + body { + padding: 15px; + font-size: 15px; + } + h1 { + font-size: 28px; + margin: 20px 0; + } + h2 { + font-size: 22px; + } + .main-page h1 { + font-size: 32px; + } + .btn, + .back-btn, + .upload-btn, + button[type="submit"] { + padding: 14px 20px; + font-size: 15px; + } + .main-page .btn { + width: 100%; + max-width: 300px; + display: block; + margin: 10px auto; + } + .login-form { + padding: 25px 20px; + } + form[action="/upload"] { + padding: 15px; + } + input[type="file"] { + width: 100%; + margin: 10px 0; + } + form[action="/upload"] button { + width: 100%; + margin-top: 10px; + } +} + +@media (max-width: 480px) { + body { + padding: 10px; + } + h1 { + font-size: 24px; + margin: 15px 0; + } + h2 { + font-size: 20px; + } + .main-page h1 { + font-size: 28px; + } + .main-page p { + font-size: 14px; + } + .btn, + .back-btn, + .upload-btn, + button[type="submit"] { + padding: 12px 16px; + font-size: 14px; + } + .main-page .btn { + font-size: 15px; + padding: 14px 24px; + } + .login-form { + padding: 20px 15px; + } + .files-list-item, + div[style*="margin: 5px 0"] { + flex-direction: column !important; + align-items: flex-start !important; + padding: 12px !important; + } + .files-list-item span, + div[style*="margin: 5px 0"] span { + margin-bottom: 10px !important; + width: 100% !important; + } + .files-list-item form, + div[style*="margin: 5px 0"] form { + width: 100% !important; + margin-left: 0 !important; + margin-top: 8px !important; + } + .files-list-item button, + div[style*="margin: 5px 0"] button { + width: 100% !important; + } + p a.back-btn { + display: block; + margin: 8px 0; + } +}