-#include "render.h"
-#include "config.h"
-#include "auth.h"
-#include "fs.h"
-#include "utils.h"
-
-extern query_params_t g_params;
-
-void buffer_init(buffer_t *buf) {
- buf->capacity = 65536;
- buf->data = malloc(buf->capacity);
- buf->size = 0;
-}
-
-void buffer_append(buffer_t *buf, const char *str) {
- size_t len = strlen(str);
- if (buf->size + len >= buf->capacity) {
- buf->capacity *= 2;
- buf->data = realloc(buf->data, buf->capacity);
- }
- memcpy(buf->data + buf->size, str, len);
- buf->size += len;
-}
-
-void buffer_free(buffer_t *buf) { free(buf->data); }
-
-void get_token_part(char *buf, size_t size) {
- buf[0] = '\0';
- char *query_string = getenv("QUERY_STRING");
- if (!query_string) return;
-
- char *token_start = strstr(query_string, "token=");
- if (!token_start) return;
-
- token_start += 6;
- char *token_end = strchr(token_start, '&');
- int token_len = token_end ? (int)(token_end - token_start) : (int)strlen(token_start);
- if (token_len > 0 && token_len < (int)size - 1) {
- strncpy(buf, token_start, token_len);
- buf[token_len] = '\0';
- }
-}
-
-void print_breadcrumb(buffer_t *buf, const char *display_path) {
- char token_part[256] = "";
- get_token_part(token_part, sizeof(token_part));
-
- buffer_append(buf, "\n");
- buffer_append(buf, "
🏠 Главная ");
-
- if (display_path && display_path[0]) {
- char temp_path[1024] = "";
- char encoded[2048];
- char *path_copy = strdup(display_path);
- char *token = strtok(path_copy, "/");
- while (token) {
- buffer_append(buf, " / ");
- if (temp_path[0]) strcat(temp_path, "/");
- strcat(temp_path, token);
- url_encode(temp_path, encoded, sizeof(encoded));
- char safe_token[512];
- html_escape(token, safe_token, sizeof(safe_token));
-
- buffer_append(buf, "
");
- buffer_append(buf, safe_token);
- buffer_append(buf, " ");
-
- token = strtok(NULL, "/");
- }
- free(path_copy);
- }
- buffer_append(buf, "\n
\n");
-}
-
-void print_password_form(buffer_t *buf, const char *folder_name) {
- char *remote_addr = getenv("REMOTE_ADDR");
- if (!remote_addr) remote_addr = "unknown";
-
- if (check_attempts(folder_name, remote_addr)) {
- buffer_append(buf, "\n");
- return;
- }
-
- char encoded_path[1024];
- url_encode(folder_name, encoded_path, sizeof(encoded_path));
-
- buffer_append(buf, "\n");
-}
-
-void print_content(buffer_t *buf, const char *base_path, const char *display_path) {
- fprintf(stderr, "DEBUG: print_content START, display_path='%s'\n", display_path ? display_path : "(null)");
-
- // ============================================
- // ОБЪЯВЛЯЕМ entries В НАЧАЛЕ ФУНКЦИИ
- // ============================================
- DIR *dir;
- struct dirent *entry;
- struct stat file_stat;
- char full_path[1024];
- entry_t *entries = NULL;
- int entry_count = 0, dir_count = 0, file_count = 0;
- long long total_size = 0;
- int is_recursive_search = 0;
- char *remote_addr = getenv("REMOTE_ADDR");
- if (!remote_addr) remote_addr = "unknown";
-
- char *query_string = getenv("QUERY_STRING");
- int is_root = 0;
- if (!query_string || !strstr(query_string, "path=")) {
- fprintf(stderr, "DEBUG: no path=, rendering root\n");
- is_root = 1;
- }
-
- char token_part[256] = "";
- get_token_part(token_part, sizeof(token_part));
- fprintf(stderr, "DEBUG: token_part='%s'\n", token_part);
-
- int has_valid_token = 0;
-
- if (!is_root && query_string) {
- char *token_start = strstr(query_string, "token=");
- if (token_start) {
- token_start += 6;
- char *token_end = strchr(token_start, '&');
- int token_len = token_end ? (int)(token_end - token_start) : (int)strlen(token_start);
- if (token_len > 0 && token_len < 256) {
- char token[256];
- strncpy(token, token_start, token_len);
- token[token_len] = '\0';
-
- char token_path[1024];
- if (check_token(token, token_path, sizeof(token_path))) {
- if (strcmp(token_path, display_path) == 0) {
- has_valid_token = 1;
- fprintf(stderr, "DEBUG: valid token for '%s'\n", display_path);
- }
- }
- }
- }
- }
-
- if (!is_root && !has_valid_token && display_path && display_path[0]) {
- char *last_slash = strrchr(display_path, '/');
- char *folder_name = last_slash ? last_slash + 1 : (char*)display_path;
-
- if (query_string && strstr(query_string, "error=1")) {
- fprintf(stderr, "DEBUG: error=1, showing password form\n");
- print_password_form(buf, folder_name);
- return;
- }
-
- if (is_folder_protected(folder_name)) {
- fprintf(stderr, "DEBUG: no valid token, showing password form\n");
- // Добавляем скрипт очистки localStorage
- buffer_append(buf, "\n");
- print_password_form(buf, folder_name);
- return;
- }
- }
-
- // ============================================
- // ВЫДЕЛЯЕМ ПАМЯТЬ ДЛЯ entries
- // ============================================
- entries = malloc(sizeof(entry_t) * g_config.max_entries);
- if (!entries) {
- buffer_append(buf, "Ошибка выделения памяти
");
- return;
- }
-
- if (g_params.search[0] != '\0') {
- int result_count = 0;
- search_recursive(g_config.base_path, "", g_params.search, entries, &result_count, g_config.max_entries);
- if (result_count == 0) {
- buffer_append(buf, "\n");
- buffer_append(buf, "
🔍
\n");
- buffer_append(buf, "
Ничего не найдено \n");
- buffer_append(buf, "
По запросу \"");
- char safe_search[512];
- html_escape(g_params.search, safe_search, sizeof(safe_search));
- buffer_append(buf, safe_search);
- buffer_append(buf, "\" ничего не найдено
\n");
- buffer_append(buf, "
\n");
- free(entries);
- return;
- }
- entry_count = result_count;
- is_recursive_search = 1;
- for (int i = 0; i < entry_count; i++) {
- if (entries[i].is_dir) {
- dir_count++;
- total_size += entries[i].dir_size;
- } else {
- file_count++;
- total_size += entries[i].size;
- }
- }
- } else {
- dir = opendir(base_path);
- if (!dir) {
- char alt_path[1024];
- snprintf(alt_path, sizeof(alt_path), "%s", g_config.base_path);
- if (display_path[0]) {
- char *encoded = strdup(display_path);
- url_decode_enhanced(encoded, alt_path + strlen(alt_path), sizeof(alt_path) - strlen(alt_path));
- free(encoded);
- }
- dir = opendir(alt_path);
- if (!dir) {
- buffer_append(buf, "\n");
- buffer_append(buf, "
📁
\n");
- char *display_base = strstr(base_path, "/www/");
- if (!display_base) display_base = (char*)base_path;
- buffer_append(buf, "
Ошибка открытия директории: ");
- buffer_append(buf, display_base);
- buffer_append(buf, " \n");
- buffer_append(buf, "
Папка не найдена
\n");
- buffer_append(buf, "
← Вернуться на главную
\n");
- buffer_append(buf, "
\n");
- free(entries);
- return;
- }
- }
- while ((entry = readdir(dir)) != NULL && entry_count < g_config.max_entries) {
- if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
- int hidden = 0;
- for (int i = 0; i < g_config.hidden_dirs_count; i++) {
- if (strcmp(entry->d_name, g_config.hidden_dirs[i]) == 0) { hidden = 1; break; }
- }
- for (int i = 0; i < g_config.hidden_files_count; i++) {
- if (strcmp(entry->d_name, g_config.hidden_files[i]) == 0) { hidden = 1; break; }
- }
- if (entry->d_name[0] == '.') hidden = 1;
- if (hidden) continue;
- snprintf(full_path, sizeof(full_path), "%s/%s", base_path, entry->d_name);
- if (stat(full_path, &file_stat) == 0) {
- snprintf(entries[entry_count].name, sizeof(entries[0].name), "%s", entry->d_name);
- if (S_ISDIR(file_stat.st_mode)) {
- entries[entry_count].is_dir = 1;
- entries[entry_count].size = 0;
- entries[entry_count].mtime = file_stat.st_mtime;
- entries[entry_count].file_count = count_files_in_dir(full_path);
- entries[entry_count].dir_size = get_dir_size(full_path);
- total_size += entries[entry_count].dir_size;
- if (is_folder_protected(entry->d_name)) {
- strcpy(entries[entry_count].icon, "🔒");
- entries[entry_count].is_protected = 1;
- } else {
- strcpy(entries[entry_count].icon, "📁");
- entries[entry_count].is_protected = 0;
- }
- char new_path[2048];
- snprintf(new_path, sizeof(new_path), "%s%s%s", display_path, display_path[0] ? "/" : "", entries[entry_count].name);
- url_encode(new_path, entries[entry_count].encoded_path, sizeof(entries[0].encoded_path));
- dir_count++;
- } else if (S_ISREG(file_stat.st_mode)) {
- entries[entry_count].is_dir = 0;
- entries[entry_count].size = file_stat.st_size;
- entries[entry_count].mtime = file_stat.st_mtime;
- entries[entry_count].file_count = 0;
- entries[entry_count].dir_size = 0;
- strcpy(entries[entry_count].icon, get_file_icon(entry->d_name));
- entries[entry_count].is_protected = 0;
- char encoded_filename[1024];
- url_encode(entry->d_name, encoded_filename, sizeof(encoded_filename));
- char temp_url[2048];
- snprintf(temp_url, sizeof(temp_url), "%s%s%s", display_path, display_path[0] ? "/" : "", encoded_filename);
- snprintf(entries[entry_count].file_url, sizeof(entries[0].file_url), "%s", temp_url);
- total_size += file_stat.st_size;
- file_count++;
- } else {
- continue;
- }
- entry_count++;
- }
- }
- closedir(dir);
- if (entry_count == 0) {
- buffer_append(buf, "\n");
- buffer_append(buf, "
📄
\n");
- buffer_append(buf, "
Здесь пусто \n");
- buffer_append(buf, "
В этой директории нет файлов или папок
\n");
- buffer_append(buf, "
\n");
- free(entries);
- return;
- }
- }
-
- qsort(entries, entry_count, sizeof(entry_t), compare_entries_sorted);
-
- char encoded_path[1024];
- url_encode(display_path, encoded_path, sizeof(encoded_path));
- char safe_search[512];
- html_escape(g_params.search, safe_search, sizeof(safe_search));
-
- int next_order = g_params.sort_order * -1;
- char order_str[4];
- snprintf(order_str, sizeof(order_str), "%d", next_order);
-
- char active_name[64] = "";
- char active_size[64] = "";
- char active_date[64] = "";
- if (strcmp(g_params.sort_by, "name") == 0) { strcpy(active_name, " active"); }
- else if (strcmp(g_params.sort_by, "size") == 0) { strcpy(active_size, " active"); }
- else if (strcmp(g_params.sort_by, "date") == 0) { strcpy(active_date, " active"); }
-
- char arrow[8] = "";
- if (g_params.sort_order == 1) strcpy(arrow, "🔽");
- else strcpy(arrow, "🔼");
-
- char link_with_token[512];
- if (token_part[0]) {
- snprintf(link_with_token, sizeof(link_with_token), "&%s", token_part);
- } else {
- link_with_token[0] = '\0';
- }
-
- buffer_append(buf, "\n");
-
- if (is_recursive_search) {
- buffer_append(buf, "");
- buffer_append(buf, "🔍 Результаты поиска по всему сайту: ");
- char tmp[32];
- snprintf(tmp, sizeof(tmp), "%d", entry_count);
- buffer_append(buf, tmp);
- buffer_append(buf, " файлов/папок найдено
\n");
- }
-
- buffer_append(buf, "\n");
- int has_dirs = 0;
- for (int i = 0; i < entry_count; i++) if (entries[i].is_dir) { has_dirs = 1; break; }
- if (has_dirs) {
- int display_dir_count = 0;
- for (int i = 0; i < entry_count; i++) if (entries[i].is_dir) display_dir_count++;
- char section_title[128];
- snprintf(section_title, sizeof(section_title), " 📁 Папки (%d) \n", display_dir_count);
- buffer_append(buf, section_title);
- for (int i = 0; i < entry_count; i++) {
- if (entries[i].is_dir) {
- buffer_append(buf, " \n");
- if (entries[i].is_protected) {
- buffer_append(buf, " \n");
- if (token_part[0]) {
- buffer_append(buf, "
\n");
- } else {
- buffer_append(buf, " \n");
- }
- buffer_append(buf, " 📁 \n");
- buffer_append(buf, " ");
- if (is_recursive_search) {
- char safe_url[512];
- html_escape(entries[i].file_url, safe_url, sizeof(safe_url));
- buffer_append(buf, safe_url);
- } else {
- char safe_name2[512];
- html_escape(entries[i].name, safe_name2, sizeof(safe_name2));
- buffer_append(buf, safe_name2);
- }
- buffer_append(buf, " (🔒) \n");
- buffer_append(buf, " \n");
- buffer_append(buf, "
\n");
- buffer_append(buf, " 🔑 \n");
- buffer_append(buf, " 🔗 \n");
- buffer_append(buf, " — \n");
- buffer_append(buf, "
\n");
- buffer_append(buf, "
\n");
- } else {
- buffer_append(buf, " \n");
- buffer_append(buf, "
\n");
- buffer_append(buf, " ");
- buffer_append(buf, entries[i].icon);
- buffer_append(buf, " \n");
- buffer_append(buf, " ");
- if (is_recursive_search) {
- char safe_url[512];
- html_escape(entries[i].file_url, safe_url, sizeof(safe_url));
- buffer_append(buf, safe_url);
- } else {
- char safe_name4[512];
- html_escape(entries[i].name, safe_name4, sizeof(safe_name4));
- buffer_append(buf, safe_name4);
- }
- buffer_append(buf, " \n");
- buffer_append(buf, " \n");
- buffer_append(buf, "
\n");
- buffer_append(buf, " 🔗 \n");
- if (entries[i].dir_size > 0) {
- char size_str[32];
- format_size(entries[i].dir_size, size_str);
- buffer_append(buf, " ");
- buffer_append(buf, size_str);
- buffer_append(buf, " \n");
- }
- buffer_append(buf, "
\n");
- buffer_append(buf, "
\n");
- }
- buffer_append(buf, " \n");
- }
- }
- }
- int has_files = 0;
- for (int i = 0; i < entry_count; i++) if (!entries[i].is_dir) { has_files = 1; break; }
- if (has_files) {
- int display_file_count = 0;
- for (int i = 0; i < entry_count; i++) if (!entries[i].is_dir) display_file_count++;
- char section_title[128];
- snprintf(section_title, sizeof(section_title), " 📄 Файлы (%d) \n", display_file_count);
- buffer_append(buf, section_title);
- for (int i = 0; i < entry_count; i++) {
- if (!entries[i].is_dir) {
- char size_str[32];
- char date_str[64];
- format_size(entries[i].size, size_str);
- format_date(entries[i].mtime, date_str, sizeof(date_str));
- buffer_append(buf, " \n");
- buffer_append(buf, " \n");
- char file_link[2048];
- if (is_recursive_search) {
- snprintf(file_link, sizeof(file_link), "/%s", entries[i].file_url);
- } else {
- snprintf(file_link, sizeof(file_link), "/%s", entries[i].file_url);
- }
- buffer_append(buf, "
\n");
- buffer_append(buf, " ");
- buffer_append(buf, entries[i].icon);
- buffer_append(buf, " \n");
- buffer_append(buf, " ");
- if (is_recursive_search) {
- char safe_url[512];
- html_escape(entries[i].file_url, safe_url, sizeof(safe_url));
- buffer_append(buf, safe_url);
- } else {
- char safe_name5[512];
- html_escape(entries[i].name, safe_name5, sizeof(safe_name5));
- buffer_append(buf, safe_name5);
- }
- buffer_append(buf, " \n");
- buffer_append(buf, " \n");
- buffer_append(buf, "
\n");
- if (is_previewable(entries[i].name)) {
- buffer_append(buf, " 👁 \n");
- }
- buffer_append(buf, " ⬇️ \n");
- buffer_append(buf, " 🔗 \n");
- buffer_append(buf, " ");
- buffer_append(buf, date_str);
- buffer_append(buf, " \n");
- buffer_append(buf, " ");
- buffer_append(buf, size_str);
- buffer_append(buf, " \n");
- buffer_append(buf, "
\n");
- buffer_append(buf, "
\n");
- buffer_append(buf, " \n");
- }
- }
- }
- buffer_append(buf, " \n");
- if (is_recursive_search) {
- char stats[256];
- snprintf(stats, sizeof(stats),
- "\n Найдено: папок %d | файлов %d\n
\n",
- dir_count, file_count);
- buffer_append(buf, stats);
- } else {
- char total_size_str[32];
- format_size(total_size, total_size_str);
- char stats[256];
- snprintf(stats, sizeof(stats),
- "\n Папки: %d | Файлы: %d | Общий размер: %s\n
\n",
- dir_count, file_count, total_size_str);
- buffer_append(buf, stats);
- }
- free(entries);
- fprintf(stderr, "DEBUG: print_content END\n");
-}
-
-void print_template(const char *base_path, const char *display_path) {
- FILE *file = fopen(g_config.template_path, "r");
- if (!file) {
- fprintf(stderr, "DEBUG: cannot open template: %s\n", g_config.template_path);
- printf("Error: Cannot read template\n");
- return;
- }
- fprintf(stderr, "DEBUG: template opened successfully\n");
-
- buffer_t output;
- buffer_init(&output);
- char line[4096];
- while (fgets(line, sizeof(line), file)) {
- if (strstr(line, "")) {
- print_breadcrumb(&output, display_path);
- } else if (strstr(line, "")) {
- print_content(&output, base_path, display_path);
- } else {
- buffer_append(&output, line);
- }
- }
- fclose(file);
-
- fprintf(stderr, "DEBUG: output size = %zu bytes\n", output.size);
- if (output.size == 0) {
- fprintf(stderr, "DEBUG: WARNING! output is empty!\n");
- buffer_free(&output);
- return;
- }
- fwrite(output.data, 1, output.size, stdout);
- fflush(stdout);
- fprintf(stderr, "DEBUG: fwrite done, flushed\n");
-
- buffer_free(&output);
-}
diff --git a/src/render.h b/src/render.h
deleted file mode 100644
index 0b38b6b..0000000
--- a/src/render.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef RENDER_H
-#define RENDER_H
-
-#include "fs.h"
-
-typedef struct {
- char *data;
- size_t size;
- size_t capacity;
-} buffer_t;
-
-void buffer_init(buffer_t *buf);
-void buffer_append(buffer_t *buf, const char *str);
-void buffer_free(buffer_t *buf);
-void print_template(const char *base_path, const char *display_path);
-void render_folder(buffer_t *buf, const char *base_path, const char *display_path);
-
-#endif
diff --git a/src/status.c b/src/status.c
deleted file mode 100644
index 42a82ba..0000000
--- a/src/status.c
+++ /dev/null
@@ -1,97 +0,0 @@
-// /home/romkazvo/www/cgi-bin/src/status.c
-#include
-#include
-#include
-#include
-
-long get_nginx_memory() {
- long total_kb = 0;
- char command[] = "ps -o rss= -C nginx 2>/dev/null";
-
- FILE *ps = popen(command, "r");
- if (!ps) return 0;
-
- char line[64];
- while (fgets(line, sizeof(line), ps)) {
- long kb;
- if (sscanf(line, "%ld", &kb) == 1) {
- total_kb += kb;
- }
- }
- pclose(ps);
-
- return total_kb;
-}
-
-int get_process_memory(const char *process_name, long *memory_kb) {
- char command[256];
- snprintf(command, sizeof(command), "ps -o rss= -C %s 2>/dev/null | head -1", process_name);
-
- FILE *ps = popen(command, "r");
- if (!ps) return 0;
-
- int result = fscanf(ps, "%ld", memory_kb);
- pclose(ps);
-
- return result == 1;
-}
-
-float get_cpu_load() {
- FILE *fp = fopen("/proc/loadavg", "r");
- if (!fp) return 0.0f;
-
- float load;
- fscanf(fp, "%f", &load);
- fclose(fp);
-
- return load;
-}
-
-void get_memory_usage(long *used_mb, long *total_mb) {
- FILE *fp = fopen("/proc/meminfo", "r");
- if (!fp) {
- *used_mb = 0;
- *total_mb = 0;
- return;
- }
-
- char line[128];
- long total = 0, available = 0;
-
- while (fgets(line, sizeof(line), fp)) {
- if (sscanf(line, "MemTotal: %ld kB", &total) == 1) {
- // сохраняем
- } else if (sscanf(line, "MemAvailable: %ld kB", &available) == 1) {
- break;
- }
- }
- fclose(fp);
-
- *total_mb = total / 1024;
- *used_mb = (total - available) / 1024;
-}
-
-int main() {
- printf("Content-type: text/plain; charset=utf-8\n\n");
-
- long busybox_kb = 0, nginx_kb = 0;
- get_process_memory("busybox", &busybox_kb);
- nginx_kb = get_nginx_memory();
-
- double busybox_mb = busybox_kb / 1024.0;
- double nginx_mb = nginx_kb / 1024.0;
- double total_mb = busybox_mb + nginx_mb;
-
- float cpu_load = get_cpu_load();
-
- long used_mb = 0, total_sys_mb = 0;
- get_memory_usage(&used_mb, &total_sys_mb);
-
- // Две строки
- printf("BusyBox: %.1f MB | Nginx: %.1f MB | Всего: %.1f MB\n",
- busybox_mb, nginx_mb, total_mb);
- printf("CPU Load: %.2f | Память: %ld / %ld MB (%.0f%%)",
- cpu_load, used_mb, total_sys_mb, total_sys_mb > 0 ? (float)used_mb / total_sys_mb * 100 : 0);
-
- return 0;
-}
diff --git a/src/style.c b/src/style.c
deleted file mode 100644
index 818e8c1..0000000
--- a/src/style.c
+++ /dev/null
@@ -1,36 +0,0 @@
-#include
-#include
-#include
-#include
-
-int main() {
- char css_path[1024] = "/home/romkazvo/www/cgi-bin/style.css";
- struct stat st;
-
- if (stat(css_path, &st) != 0) {
- printf("Status: 404 Not Found\n");
- printf("Content-type: text/plain\n\n");
- printf("CSS file not found\n");
- return 1;
- }
-
- printf("Content-type: text/css\n");
- printf("Cache-Control: public, max-age=3600\n\n");
-
- FILE *css_file = fopen(css_path, "r");
- if (!css_file) {
- printf("Status: 500 Internal Server Error\n");
- printf("Content-type: text/plain\n\n");
- printf("Cannot open CSS file\n");
- return 1;
- }
-
- char buffer[4096];
- size_t bytes_read;
- while ((bytes_read = fread(buffer, 1, sizeof(buffer), css_file)) > 0) {
- fwrite(buffer, 1, bytes_read, stdout);
- }
-
- fclose(css_file);
- return 0;
-}
diff --git a/src/utils.c b/src/utils.c
deleted file mode 100644
index b7caffe..0000000
--- a/src/utils.c
+++ /dev/null
@@ -1,98 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include "utils.h"
-
-char* my_strcasestr(const char *haystack, const char *needle) {
- if (!haystack || !needle || *needle == '\0') return (char*)haystack;
- size_t needle_len = strlen(needle);
- while (*haystack) {
- if (strncasecmp(haystack, needle, needle_len) == 0) return (char*)haystack;
- haystack++;
- }
- return NULL;
-}
-
-void html_escape(const char *src, char *dst, size_t dst_size) {
- if (!src || !dst || dst_size == 0) return;
- char *p = dst;
- size_t i = 0;
- while (*src && i < dst_size - 6) {
- switch (*src) {
- case '<': strcpy(p, "<"); p += 4; i += 4; break;
- case '>': strcpy(p, ">"); p += 4; i += 4; break;
- case '"': strcpy(p, """); p += 6; i += 6; break;
- case '&': strcpy(p, "&"); p += 5; i += 5; break;
- default: *p++ = *src; i++; break;
- }
- src++;
- }
- *p = '\0';
-}
-
-void format_size(long long size, char* buffer) {
- if (size < 1024) snprintf(buffer, 32, "%lld B", size);
- else if (size < 1024 * 1024) snprintf(buffer, 32, "%.1f KB", size / 1024.0);
- else if (size < 1024 * 1024 * 1024) snprintf(buffer, 32, "%.1f MB", size / (1024.0 * 1024.0));
- else snprintf(buffer, 32, "%.1f GB", size / (1024.0 * 1024.0 * 1024.0));
-}
-
-void format_date(time_t mtime, char* buffer, size_t size) {
- struct tm *tm_info = localtime(&mtime);
- strftime(buffer, size, "%d.%m.%Y", tm_info);
-}
-
-void url_encode(const char *src, char *dst, size_t dst_size) {
- static const char *hex = "0123456789ABCDEF";
- char *p = dst;
- size_t i = 0;
- while (*src && i < dst_size - 3) {
- unsigned char c = (unsigned char)*src;
- if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
- (c >= '0' && c <= '9') || strchr("-_.~", c)) {
- *p++ = c; i++;
- } else if (c == ' ') {
- *p++ = '%'; *p++ = '2'; *p++ = '0'; i += 3;
- } else {
- *p++ = '%'; *p++ = hex[(c >> 4) & 0xF]; *p++ = hex[c & 0xF]; i += 3;
- }
- src++;
- }
- *p = '\0';
-}
-
-void url_decode_enhanced(const char *src, char *dst, size_t dst_size) {
- char *p = dst;
- size_t decoded_len = 0;
- while (*src && decoded_len < dst_size - 1) {
- if (*src == '%') {
- if (src[1] && src[2] && isxdigit(src[1]) && isxdigit(src[2])) {
- char hex[3] = {src[1], src[2], '\0'};
- unsigned char c = (unsigned char)strtol(hex, NULL, 16);
- if (c >= 0x80 || c >= 0x20 || c == 0x0A || c == 0x0D) {
- *p++ = c;
- decoded_len++;
- } else {
- *p++ = '_';
- decoded_len++;
- }
- src += 3;
- } else {
- // ============================================
- // ФИКС: если % не валидный — просто пропускаем его
- // ============================================
- src++;
- }
- } else if (*src == '+') {
- *p++ = ' ';
- decoded_len++;
- src++;
- } else {
- *p++ = *src++;
- decoded_len++;
- }
- }
- *p = '\0';
-}
\ No newline at end of file
diff --git a/src/utils.h b/src/utils.h
deleted file mode 100644
index 0301302..0000000
--- a/src/utils.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef UTILS_H
-#define UTILS_H
-
-#include
-
-void url_encode(const char *src, char *dst, size_t dst_size);
-void url_decode_enhanced(const char *src, char *dst, size_t dst_size);
-void html_escape(const char *src, char *dst, size_t dst_size);
-char* my_strcasestr(const char *haystack, const char *needle);
-void format_size(long long size, char* buffer);
-void format_date(time_t mtime, char* buffer, size_t size);
-
-#endif
diff --git a/style.css b/style.css
deleted file mode 100755
index 98a550f..0000000
--- a/style.css
+++ /dev/null
@@ -1,1387 +0,0 @@
-/* ============================================
- БАЗА
- ============================================ */
-:root {
- --bg-primary: #f8f9fa;
- --bg-secondary: #ffffff;
- --bg-header: linear-gradient(135deg, #2d3436, #636e72);
- --text-primary: #2d3436;
- --text-secondary: #636e72;
- --text-muted: #b2bec3;
- --border-color: #dfe6e9;
- --border-light: #f1f2f6;
- --accent-blue: #0984e3;
- --accent-orange: #e17055;
- --accent-green: #00b894;
- --hover-bg: #f1f2f6;
- --shadow: 0 4px 12px rgba(0,0,0,0.04);
- --radius: 12px;
-}
-
-.dark-theme {
- --bg-primary: #1e1e1e;
- --bg-secondary: #2d2d2d;
- --bg-header: linear-gradient(135deg, #1e1e1e, #2d2d2d);
- --text-primary: #e0e0e0;
- --text-secondary: #b0b0b0;
- --text-muted: #6c6c6c;
- --border-color: #3d3d3d;
- --border-light: #333333;
- --accent-blue: #74b9ff;
- --accent-orange: #fdcb6e;
- --accent-green: #55efc4;
- --hover-bg: #3d3d3d;
- --shadow: 0 4px 12px rgba(0,0,0,0.2);
- --radius: 12px;
-}
-
-/* ============================================
- ТЕЛО
- ============================================ */
-body {
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- background: var(--bg-primary);
- color: var(--text-primary);
- line-height: 1.6;
- min-height: 100vh;
- transition: background 0.25s ease, color 0.25s ease;
-}
-
-body.loaded * {
- transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
-}
-
-/* ============================================
- КОНТЕЙНЕР
- ============================================ */
-.container {
- max-width: 100%;
- margin: 0 auto;
- background: var(--bg-secondary);
- min-width: 320px;
- min-height: 100vh;
- box-shadow: var(--shadow);
- transition: background 0.25s ease, box-shadow 0.25s ease;
-}
-
-@media (min-width: 768px) {
- .container {
- max-width: 1100px;
- margin: 16px auto;
- min-height: auto;
- border-radius: var(--radius);
- overflow: hidden;
- box-shadow: var(--shadow);
- }
-}
-
-/* ============================================
- ШАПКА
- ============================================ */
-.header {
- background: var(--bg-header);
- color: white;
- padding: 2rem 1.5rem;
- text-align: center;
- position: relative;
-}
-
-.header h1 {
- font-size: 2rem;
- font-weight: 700;
- margin: 0;
- letter-spacing: -0.5px;
-}
-
-.header .subtitle {
- opacity: 0.85;
- font-size: 1.05rem;
- margin-top: 0.25rem;
- font-weight: 400;
-}
-
-/* ============================================
- ОПИСАНИЕ (НЕ УВЕЛИЧИВАЕМ)
- ============================================ */
-.site-description {
- text-align: center;
- padding: 0.75rem 1.5rem;
- font-size: 1rem;
- color: var(--text-secondary);
- border-bottom: 1px solid var(--border-color);
- background: var(--bg-primary);
- font-weight: 400;
- letter-spacing: 0.2px;
-}
-
-/* ============================================
- ХЛЕБНЫЕ КРОШКИ
- ============================================ */
-.breadcrumb {
- background: var(--bg-primary);
- padding: 0.6rem 1.25rem;
- border-bottom: 1px solid var(--border-color);
- font-size: 0.85rem;
- overflow-x: auto;
- white-space: nowrap;
- -webkit-overflow-scrolling: touch;
- color: var(--text-secondary);
- display: flex;
- align-items: center;
- gap: 0.3rem;
- flex-wrap: nowrap;
-}
-
-.breadcrumb a {
- color: var(--accent-blue);
- text-decoration: none;
- font-weight: 500;
- transition: color 0.15s ease;
- padding: 0.1rem 0.2rem;
-}
-
-.breadcrumb a:hover {
- color: var(--accent-orange);
- text-decoration: underline;
-}
-
-.breadcrumb .separator {
- color: var(--text-muted);
- user-select: none;
- font-weight: 300;
- margin: 0 0.1rem;
-}
-
-/* ============================================
- ТУЛБАР
- ============================================ */
-.toolbar {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 0.5rem 1rem;
- padding: 0.6rem 1.25rem;
- background: var(--bg-secondary);
- border-bottom: 1px solid var(--border-light);
- transition: background 0.2s ease;
-}
-
-/* Поиск */
-.search-box {
- flex: 1 1 220px;
- min-width: 150px;
-}
-
-.search-box form {
- display: flex;
- gap: 0.4rem;
- align-items: center;
-}
-
-.search-box input[type="text"] {
- flex: 1;
- padding: 0.5rem 1rem;
- border: 1.5px solid var(--border-color);
- border-radius: 50px;
- background: var(--bg-primary);
- color: var(--text-primary);
- font-size: 0.85rem;
- transition: border-color 0.2s ease, box-shadow 0.2s ease;
- outline: none;
- min-width: 80px;
- height: 38px;
- box-sizing: border-box;
-}
-
-.search-box input[type="text"]:focus {
- border-color: var(--accent-blue);
- box-shadow: 0 0 0 3px rgba(9, 132, 227, 0.12);
-}
-
-.search-box button {
- padding: 0 1.2rem;
- background: var(--accent-blue);
- color: white;
- border: none;
- border-radius: 50px;
- cursor: pointer;
- font-weight: 600;
- font-size: 0.85rem;
- transition: background 0.2s ease, transform 0.15s ease;
- white-space: nowrap;
- height: 38px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- box-sizing: border-box;
-}
-
-.search-box button:hover {
- background: var(--accent-orange);
- transform: scale(1.02);
-}
-
-/* Группы настроек */
-.settings-group {
- display: flex;
- align-items: center;
- gap: 0.25rem;
- flex-wrap: wrap;
-}
-
-.settings-label {
- color: var(--text-muted);
- font-weight: 500;
- font-size: 0.7rem;
- text-transform: uppercase;
- letter-spacing: 0.3px;
- margin-right: 0.15rem;
-}
-
-/* Разделитель между группами */
-.settings-divider {
- width: 1px;
- height: 30px;
- background: var(--border-color);
- margin: 0 0.25rem;
-}
-
-@media (max-width: 768px) {
- .settings-divider {
- display: none;
- }
-}
-
-/* Кнопки вида и сортировки */
-.view-btn,
-.sort-btn {
- padding: 0 0.9rem;
- background: transparent;
- border: 1.5px solid var(--border-color);
- border-radius: 50px;
- color: var(--text-secondary);
- font-size: 0.78rem;
- cursor: pointer;
- transition: all 0.15s ease;
- font-weight: 500;
- text-decoration: none;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- height: 38px;
- line-height: 1;
- gap: 0.2rem;
- box-sizing: border-box;
- white-space: nowrap;
-}
-
-.view-btn:hover,
-.sort-btn:hover {
- background: var(--hover-bg);
- border-color: var(--accent-blue);
- color: var(--text-primary);
-}
-
-.view-btn.active,
-.sort-btn.active {
- background: var(--accent-blue);
- color: white !important;
- border-color: var(--accent-blue);
-}
-
-.view-btn .icon,
-.sort-btn .icon {
- font-size: 0.85rem;
- line-height: 1;
-}
-
-/* Скрываем старый settings-row */
-.settings-row {
- display: none !important;
-}
-
-/* ============================================
- СПИСОК ФАЙЛОВ
- ============================================ */
-ul {
- list-style: none;
- padding: 0;
- margin: 0;
-}
-
-li {
- padding: 0.6rem 1.25rem;
- border-bottom: 1px solid var(--border-light);
- display: flex;
- align-items: center;
- flex-wrap: nowrap;
- transition: background 0.15s ease;
-}
-
-li:hover {
- background: var(--hover-bg);
-}
-
-li:last-child {
- border-bottom: none;
-}
-
-li.section-title {
- color: var(--text-secondary);
- font-size: 0.8rem;
- font-weight: 600;
- padding: 0.5rem 1.25rem;
- border-bottom: 2px solid var(--border-color);
- background: var(--bg-primary);
- text-transform: uppercase;
- letter-spacing: 0.5px;
- margin-top: 0.5rem;
-}
-
-li.section-title:first-of-type {
- margin-top: 0;
-}
-
-/* ============================================
- ФАЙЛОВАЯ СТРОКА — ФИНАЛЬНЫЙ ФИКС
- ============================================ */
-.file-row {
- display: flex;
- align-items: center;
- justify-content: space-between;
- flex-grow: 1;
- min-width: 0;
- gap: 0.75rem;
- flex-wrap: nowrap;
- width: 100%;
-}
-
-.file-link,
-.dir-link {
- display: flex;
- align-items: center;
- flex: 1 1 auto;
- min-width: 0;
- gap: 0.6rem;
- overflow: hidden;
- text-decoration: none;
- color: var(--text-primary);
-}
-
-.file-link .file-name {
- font-weight: 500;
-}
-
-.dir-link .file-name {
- font-weight: 600;
-}
-
-.file-link:hover .file-name {
- color: var(--accent-blue);
-}
-
-.dir-link:hover .file-name {
- color: var(--accent-orange);
-}
-
-.file-icon {
- font-size: 1.3rem;
- flex-shrink: 0;
- width: 28px;
- min-width: 28px;
- max-width: 28px;
- text-align: center;
- line-height: 1;
-}
-
-.file-name {
- flex: 1 1 auto;
- min-width: 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- font-size: 0.92rem;
- transition: color 0.15s ease;
-}
-
-.file-controls {
- display: flex;
- align-items: center;
- gap: 0.3rem;
- flex-shrink: 0;
- flex-wrap: nowrap;
- margin-left: auto;
-}
-
-.file-meta {
- color: var(--text-muted);
- font-size: 0.75rem;
- font-weight: 500;
- white-space: nowrap;
- text-align: right;
- font-variant-numeric: tabular-nums;
- flex-shrink: 0;
-}
-
-.file-meta.date {
- min-width: 80px;
- width: 80px;
-}
-
-.file-meta.size {
- min-width: 60px;
- width: 60px;
- text-align: right;
- flex-shrink: 0;
-}
-
-/* Кнопки — фиксированный размер */
-.preview-btn,
-.copy-btn,
-.download-btn {
- background: transparent;
- border: 1px solid var(--border-color);
- border-radius: 6px;
- width: 32px;
- height: 32px;
- min-width: 32px;
- min-height: 32px;
- max-width: 32px;
- max-height: 32px;
- cursor: pointer;
- font-size: 0.8rem;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- transition: all 0.15s ease;
- opacity: 0.6;
- color: var(--text-secondary);
- padding: 0;
- box-sizing: border-box;
- flex-shrink: 0;
-}
-
-.preview-btn:hover,
-.copy-btn:hover,
-.download-btn:hover {
- opacity: 1;
- transform: scale(1.05);
-}
-
-.preview-btn:hover {
- background: var(--accent-blue);
- color: white;
- border-color: var(--accent-blue);
-}
-
-.copy-btn:hover {
- background: var(--accent-blue);
- color: white;
- border-color: var(--accent-blue);
-}
-
-.download-btn:hover {
- background: var(--accent-green);
- color: white;
- border-color: var(--accent-green);
-}
-
-/* ============================================
- СТАТИСТИКА
- ============================================ */
-.stats {
- text-align: center;
- color: var(--text-secondary);
- margin-top: 2rem;
- padding: 1rem 1.25rem;
- border-top: 1px solid var(--border-color);
- font-size: 0.9rem;
- background: var(--bg-primary);
-}
-
-.empty-state {
- text-align: center;
- padding: 3rem 1rem;
- color: var(--text-secondary);
-}
-
-.empty-state .icon {
- font-size: 3rem;
- margin-bottom: 1rem;
- opacity: 0.5;
-}
-
-/* ============================================
- ПАРОЛЬНАЯ ФОРМА
- ============================================ */
-.password-form-container {
- display: flex;
- justify-content: center;
- align-items: center;
- min-height: 400px;
- padding: 2rem;
-}
-
-.password-form {
- background: var(--bg-secondary);
- border: 1px solid var(--border-color);
- border-radius: 12px;
- padding: 2rem;
- max-width: 400px;
- width: 100%;
- text-align: center;
- box-shadow: 0 4px 20px rgba(0,0,0,0.1);
-}
-
-.password-form .lock-icon {
- font-size: 3rem;
- margin-bottom: 1rem;
- display: block;
-}
-
-.password-form h2 {
- font-size: 1.3rem;
- margin-bottom: 0.5rem;
- color: var(--text-primary);
-}
-
-.password-form p {
- color: var(--text-secondary);
- margin-bottom: 1.5rem;
- font-size: 0.95rem;
-}
-
-.password-form p strong {
- color: var(--text-primary);
- word-break: break-all;
-}
-
-.password-form form {
- display: flex;
- flex-direction: column;
- gap: 0.75rem;
-}
-
-.password-form input[type="password"] {
- padding: 0.75rem 1rem;
- border: 2px solid var(--border-color);
- border-radius: 8px;
- font-size: 1rem;
- background: var(--bg-primary);
- color: var(--text-primary);
- transition: border-color 0.2s ease;
- width: 100%;
- box-sizing: border-box;
-}
-
-.password-form input[type="password"]:focus {
- outline: none;
- border-color: var(--accent-blue);
-}
-
-.password-form button {
- padding: 0.75rem;
- background: var(--accent-blue);
- color: white;
- border: none;
- border-radius: 8px;
- font-size: 1rem;
- font-weight: 600;
- cursor: pointer;
- transition: background 0.2s ease;
-}
-
-.password-form button:hover {
- background: var(--accent-green);
-}
-
-.password-form .error-msg {
- color: #dc3545;
- font-size: 0.9rem;
- min-height: 1.5rem;
- margin: 0.25rem 0;
-}
-
-.password-form .back-link {
- display: inline-block;
- margin-top: 0.75rem;
- color: var(--text-secondary);
- text-decoration: none;
- font-size: 0.9rem;
-}
-
-.password-form .back-link:hover {
- color: var(--accent-blue);
- text-decoration: underline;
-}
-
-.protected-folder {
- position: relative;
-}
-
-/* ============================================
- МОДАЛКА
- ============================================ */
-.preview-modal {
- display: none;
- position: fixed;
- z-index: 2000;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.7);
- backdrop-filter: blur(5px);
- -webkit-backdrop-filter: blur(5px);
- overflow: auto;
-}
-
-.preview-modal.open {
- display: flex !important;
- align-items: center;
- justify-content: center;
-}
-
-.preview-content {
- background: var(--bg-secondary);
- border-radius: 12px;
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
- display: flex;
- flex-direction: column;
- overflow: hidden;
- max-width: 90vw;
- max-height: 90vh;
- width: auto;
- height: auto;
- min-width: 320px;
- min-height: 200px;
-}
-
-.preview-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 0.75rem 1rem;
- border-bottom: 1px solid var(--border-color);
- background: var(--bg-primary);
- flex-shrink: 0;
- gap: 1rem;
-}
-
-.preview-title {
- font-weight: 600;
- color: var(--text-primary);
- margin: 0;
- flex-grow: 1;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- font-size: 0.95rem;
-}
-
-.close-preview {
- background: transparent;
- color: var(--text-secondary);
- border: none;
- border-radius: 6px;
- width: 34px;
- height: 34px;
- cursor: pointer;
- font-size: 1.4rem;
- flex-shrink: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all 0.15s ease;
-}
-
-.close-preview:hover {
- background: #dc3545;
- color: white;
-}
-
-.preview-iframe {
- flex-grow: 1;
- border: none;
- background: var(--bg-secondary);
- min-height: 0;
- width: 100%;
- height: 100%;
-}
-
-.preview-image-container {
- display: flex;
- align-items: center;
- justify-content: center;
- flex-grow: 1;
- padding: 1rem;
- background: var(--bg-primary);
- overflow: hidden;
- width: 100%;
- height: 100%;
-}
-
-.preview-image {
- max-width: 100%;
- max-height: 100%;
- width: auto;
- height: auto;
- object-fit: contain;
- border-radius: 4px;
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
- display: block;
-}
-
-/* Форма пароля в модалке */
-#passwordFormContainer {
- display: flex;
- justify-content: center;
- align-items: center;
- padding: 2rem;
- flex-grow: 1;
- min-height: 300px;
-}
-
-#passwordFormContainer > div {
- background: var(--bg-secondary);
- border: 1px solid var(--border-color);
- border-radius: 12px;
- padding: 2rem;
- max-width: 400px;
- width: 100%;
- text-align: center;
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
-}
-
-/* ============================================
- ФУТЕР — НЕ УВЕЛИЧИВАЕМ
- ============================================ */
-.footer {
- background: var(--bg-primary);
- border-top: 1px solid var(--border-color);
- padding: 1.5rem 1rem;
- text-align: center;
- color: var(--text-secondary);
- font-size: 0.85rem;
-}
-
-.footer a {
- color: var(--accent-blue);
- text-decoration: none;
- font-weight: 500;
- transition: opacity 0.15s ease;
-}
-
-.footer a:hover {
- opacity: 0.7;
-}
-
-/* ============================================
- ТЕМА И СКРОЛЛ
- ============================================ */
-.theme-toggle {
- position: fixed;
- top: 12px;
- right: 12px;
- background: rgba(255,255,255,0.15);
- border: 1px solid rgba(255,255,255,0.2);
- border-radius: 50%;
- width: 48px;
- height: 48px;
- font-size: 1.3rem;
- cursor: pointer;
- z-index: 1000;
- backdrop-filter: blur(10px);
- -webkit-backdrop-filter: blur(10px);
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all 0.3s ease;
- color: white;
-}
-
-.dark-theme .theme-toggle {
- background: rgba(0,0,0,0.3);
- border-color: rgba(255,255,255,0.1);
- color: var(--text-primary);
-}
-
-.theme-toggle:hover {
- transform: scale(1.1);
- background: rgba(255,255,255,0.25);
-}
-
-.dark-theme .theme-toggle:hover {
- background: rgba(0,0,0,0.4);
-}
-
-.scroll-top {
- position: fixed;
- bottom: 20px;
- right: 20px;
- width: 48px;
- height: 48px;
- background: var(--accent-blue);
- color: white;
- border: none;
- border-radius: 50%;
- font-size: 1.3rem;
- cursor: pointer;
- opacity: 0;
- visibility: hidden;
- transition: all 0.3s ease;
- z-index: 1000;
- box-shadow: 0 2px 12px rgba(0,0,0,0.2);
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.scroll-top.visible {
- opacity: 1;
- visibility: visible;
-}
-
-.scroll-top:hover {
- background: var(--accent-green);
- transform: translateY(-2px);
- box-shadow: 0 4px 20px rgba(0,0,0,0.3);
-}
-
-/* ============================================
- УВЕДОМЛЕНИЕ
- ============================================ */
-#copyNotification {
- position: fixed;
- bottom: 80px;
- left: 50%;
- transform: translateX(-50%);
- background: var(--accent-green);
- color: white;
- padding: 12px 24px;
- border-radius: 8px;
- font-weight: 600;
- box-shadow: 0 4px 12px rgba(0,0,0,0.3);
- z-index: 3000;
- transition: opacity 0.3s;
- opacity: 1;
-}
-
-/* ============================================
- АДАПТИВ — ПЛАНШЕТЫ
- ============================================ */
-@media (max-width: 768px) {
- .header {
- padding: 1.25rem 1rem;
- }
- .header h1 {
- font-size: 1.5rem;
- }
-
- .toolbar {
- flex-direction: column;
- align-items: stretch;
- gap: 0.4rem;
- padding: 0.6rem 1rem;
- }
-
- .search-box {
- flex: 1 1 100%;
- min-width: 0;
- }
-
- .search-box form {
- flex-wrap: nowrap;
- }
-
- .search-box input[type="text"] {
- min-width: 60px;
- font-size: 0.8rem;
- padding: 0.4rem 0.8rem;
- height: 34px;
- }
-
- .search-box button {
- font-size: 0.8rem;
- padding: 0 0.9rem;
- height: 34px;
- }
-
- .settings-group {
- flex-wrap: wrap;
- justify-content: center;
- min-height: 34px;
- align-items: center;
- }
-
- .view-btn,
- .sort-btn {
- font-size: 0.75rem;
- padding: 0 0.7rem;
- height: 34px;
- }
-
- .settings-divider {
- height: 26px;
- }
-
- .file-controls {
- gap: 0.2rem;
- }
-
- .preview-btn,
- .copy-btn,
- .download-btn {
- width: 28px;
- height: 28px;
- min-width: 28px;
- min-height: 28px;
- max-width: 28px;
- max-height: 28px;
- font-size: 0.7rem;
- }
-
- .file-icon {
- font-size: 1.2rem;
- width: 24px;
- }
-
- .file-name {
- font-size: 0.85rem;
- }
-
- li {
- padding: 0.5rem 0.75rem;
- }
-
- .file-meta.date {
- min-width: 60px;
- width: 60px;
- }
-
- .file-meta.size {
- min-width: 50px;
- width: 50px;
- }
-
- .breadcrumb {
- padding: 0.5rem 0.75rem;
- font-size: 0.8rem;
- }
-
- .preview-content {
- max-width: 96vw;
- max-height: 92vh;
- min-width: auto;
- border-radius: 8px;
- }
-
- #passwordFormContainer {
- padding: 1.5rem;
- min-height: 250px;
- }
-
- #passwordFormContainer > div {
- padding: 1.5rem;
- }
-}
-
-/* ============================================
- АДАПТИВ — МОБИЛКИ (ВСЁ УВЕЛИЧЕНО)
- ============================================ */
-@media (max-width: 480px) {
- .header {
- padding: 1.25rem 0.75rem;
- }
- .header h1 {
- font-size: 1.6rem;
- }
- .header .subtitle {
- font-size: 1rem;
- }
-
- .toolbar {
- flex-direction: column;
- align-items: stretch;
- gap: 0.6rem;
- padding: 0.75rem 0.75rem;
- }
-
- .search-box {
- width: 100%;
- min-width: 0;
- }
-
- .search-box form {
- flex-wrap: nowrap;
- width: 100%;
- gap: 0.5rem;
- }
-
- .search-box input[type="text"] {
- font-size: 0.9rem;
- padding: 0.6rem 0.8rem;
- min-width: 60px;
- height: 44px;
- flex: 1;
- }
-
- .search-box button {
- font-size: 0.9rem;
- padding: 0 1rem;
- height: 44px;
- flex-shrink: 0;
- }
-
- .settings-group {
- gap: 0.3rem;
- flex-wrap: wrap;
- justify-content: center;
- min-height: 40px;
- align-items: center;
- }
-
- .settings-label {
- font-size: 0.7rem;
- flex-shrink: 0;
- }
-
- .view-btn,
- .sort-btn {
- font-size: 0.8rem;
- padding: 0 0.8rem;
- height: 38px;
- border-width: 1.5px;
- flex-shrink: 0;
- }
-
- .view-btn .icon,
- .sort-btn .icon {
- font-size: 0.85rem;
- }
-
- /* ===== ФАЙЛОВАЯ СТРОКА — ФИКС ===== */
- .file-row {
- gap: 0.3rem !important;
- flex-wrap: nowrap !important;
- }
-
- .file-link,
- .dir-link {
- gap: 0.3rem !important;
- flex: 1 1 auto !important;
- min-width: 0 !important;
- }
-
- .file-icon {
- font-size: 1.4rem !important;
- width: 32px !important;
- min-width: 32px !important;
- flex-shrink: 0 !important;
- }
-
- .file-name {
- font-size: 0.95rem !important;
- flex: 1 1 auto !important;
- min-width: 0 !important;
- overflow: hidden !important;
- text-overflow: ellipsis !important;
- white-space: nowrap !important;
- }
-
- .file-controls {
- gap: 0.3rem !important;
- flex-shrink: 0 !important;
- margin-left: auto !important;
- }
-
- .file-meta.size {
- font-size: 0.75rem !important;
- min-width: 50px !important;
- width: auto !important;
- flex-shrink: 0 !important;
- text-align: right !important;
- }
-
- .file-meta.date {
- display: none !important;
- }
-
- .preview-btn,
- .copy-btn,
- .download-btn {
- width: 38px !important;
- height: 38px !important;
- min-width: 38px !important;
- min-height: 38px !important;
- max-width: 38px !important;
- max-height: 38px !important;
- font-size: 0.9rem !important;
- flex-shrink: 0 !important;
- padding: 0 !important;
- border-width: 1.5px !important;
- margin: 0 !important;
- border-radius: 8px !important;
- }
-
- li {
- padding: 0.6rem 0.6rem !important;
- min-height: 56px !important;
- }
-
- li.section-title {
- font-size: 0.85rem;
- padding: 0.5rem 0.6rem;
- }
-
- /* ===== ХЛЕБНЫЕ КРОШКИ ===== */
- .breadcrumb {
- padding: 0.6rem 0.75rem;
- font-size: 0.9rem;
- gap: 0.3rem;
- }
- .breadcrumb a {
- padding: 0.2rem 0.3rem;
- }
-
- /* ===== СТАТИСТИКА ===== */
- .stats {
- font-size: 0.85rem;
- padding: 0.75rem 0.6rem;
- }
-
- /* ===== ТЕМА И СКРОЛЛ ===== */
- .theme-toggle {
- top: 8px;
- right: 8px;
- width: 48px;
- height: 48px;
- font-size: 1.3rem;
- }
-
- .scroll-top {
- bottom: 20px;
- right: 20px;
- width: 48px;
- height: 48px;
- font-size: 1.3rem;
- }
-
- /* ===== ФУТЕР (НЕ УВЕЛИЧИВАЕМ) ===== */
- .footer {
- padding: 1rem 0.75rem;
- font-size: 0.8rem;
- }
-
- /* ===== МОДАЛКА ===== */
- .preview-content {
- max-width: 98vw;
- max-height: 95vh;
- border-radius: 8px;
- min-height: 150px;
- }
-
- .preview-header {
- padding: 0.6rem 0.8rem;
- }
-
- .preview-title {
- font-size: 0.9rem;
- }
-
- .close-preview {
- width: 34px;
- height: 34px;
- font-size: 1.2rem;
- }
-
- .preview-image-container {
- padding: 0.5rem;
- }
-
- #passwordFormContainer {
- padding: 1rem;
- min-height: 200px;
- }
-
- #passwordFormContainer > div {
- padding: 1.5rem 1rem;
- border-radius: 8px;
- }
-
- /* ===== ФОРМА ПАРОЛЯ ===== */
- .password-form {
- padding: 1.5rem 1rem;
- }
- .password-form .lock-icon {
- font-size: 2.5rem;
- }
- .password-form h2 {
- font-size: 1.2rem;
- }
- .password-form p {
- font-size: 0.9rem;
- }
- .password-form input[type="password"] {
- font-size: 1rem;
- padding: 0.7rem 0.8rem;
- height: 48px;
- }
- .password-form button {
- font-size: 1rem;
- padding: 0.7rem;
- height: 48px;
- }
-}
-
-/* ============================================
- АДАПТИВ — ОЧЕНЬ МАЛЕНЬКИЕ ЭКРАНЫ
- ============================================ */
-@media (max-width: 360px) {
- .header h1 {
- font-size: 1.3rem;
- }
-
- .search-box input[type="text"] {
- font-size: 0.8rem;
- height: 40px;
- padding: 0.4rem 0.6rem;
- }
- .search-box button {
- font-size: 0.8rem;
- height: 40px;
- padding: 0 0.7rem;
- }
-
- .view-btn,
- .sort-btn {
- font-size: 0.7rem;
- padding: 0 0.5rem;
- height: 34px;
- }
-
- .file-icon {
- font-size: 1.2rem !important;
- width: 28px !important;
- min-width: 28px !important;
- }
-
- .file-name {
- font-size: 0.85rem !important;
- }
-
- .preview-btn,
- .copy-btn,
- .download-btn {
- width: 34px !important;
- height: 34px !important;
- min-width: 34px !important;
- min-height: 34px !important;
- max-width: 34px !important;
- max-height: 34px !important;
- font-size: 0.8rem !important;
- border-radius: 6px !important;
- }
-
- .file-meta.size {
- font-size: 0.65rem !important;
- min-width: 40px !important;
- }
-
- li {
- padding: 0.4rem 0.4rem !important;
- min-height: 48px !important;
- }
-
- .file-row {
- gap: 0.3rem !important;
- }
-
- .theme-toggle {
- width: 40px;
- height: 40px;
- font-size: 1.1rem;
- top: 6px;
- right: 6px;
- }
-
- .scroll-top {
- width: 40px;
- height: 40px;
- font-size: 1.1rem;
- bottom: 16px;
- right: 16px;
- }
-
- .password-form input[type="password"] {
- height: 42px;
- font-size: 0.9rem;
- }
- .password-form button {
- height: 42px;
- font-size: 0.9rem;
- }
-}
-
-/* ===== ФАЙЛЫ — МОБИЛКИ ===== */
-.file-row {
- gap: 0.3rem !important;
-}
-
-.file-link,
-.dir-link {
- gap: 0.3rem !important;
- flex: 1 1 auto !important;
-}
-
-.file-icon {
- font-size: 1.4rem !important;
- width: 32px !important;
- min-width: 32px !important;
- max-width: 32px !important;
- flex-shrink: 0 !important;
-}
-
-.file-name {
- font-size: 0.95rem !important;
- flex: 1 1 auto !important;
- min-width: 0 !important;
-}
-
-.file-link .file-name {
- font-weight: 500 !important;
-}
-
-.dir-link .file-name {
- font-weight: 600 !important;
-}
-
-.file-controls {
- gap: 0.3rem !important;
- flex-shrink: 0 !important;
- margin-left: auto !important;
-}
-
-.file-meta.size {
- font-size: 0.75rem !important;
- min-width: 50px !important;
- width: auto !important;
- flex-shrink: 0 !important;
-}
-
-.file-meta.date {
- display: none !important;
-}
-
-.preview-btn,
-.copy-btn,
-.download-btn {
- width: 38px !important;
- height: 38px !important;
- min-width: 38px !important;
- min-height: 38px !important;
- max-width: 38px !important;
- max-height: 38px !important;
- font-size: 0.9rem !important;
- flex-shrink: 0 !important;
-}
\ No newline at end of file
diff --git a/template.html b/template.html
deleted file mode 100644
index 8d225ae..0000000
--- a/template.html
+++ /dev/null
@@ -1,546 +0,0 @@
-
-
-
-
-
- Trashbox - личная помоечка
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 🌙
-
-
-
-
- Личный уголок для обмена файлами. Заливаю сюда то, чем хочу поделиться, без всяких лимитов и сторонних сервисов.
-
-
-
-
-
-
-
-
-
- ↑
-
-
-
-
-
-
\ No newline at end of file