modified: .gitignore

modified:   README.md
	modified:   index.html
	new file:   input.css
	new file:   output.css
	modified:   package-lock.json
	modified:   package.json
	new file:   postcss.config.js
	modified:   script.js
	new file:   tailwind.config.js
This commit is contained in:
Fovway 2025-10-08 12:57:03 +07:00
parent 096dac61aa
commit 2d947941b5
10 changed files with 4238 additions and 646 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
node_modules/ node_modules/
apikey.txt

126
README.md
View File

@ -1,57 +1,127 @@
# Weather App # Weather App v1.0.0
Приложение для просмотра погоды. Приложение для просмотра погоды с интерактивным интерфейсом и поддержкой тем.
## Описание ## Описание
Это веб-приложение, которое отображает текущую погоду и почасовой прогноз с использованием API WeatherAPI.com. Интерфейс построен на Tailwind CSS для современного дизайна. Это веб-приложение отображает текущую погоду, почасовой и недельный прогноз с использованием API WeatherAPI.com. Современный адаптивный интерфейс построен на Tailwind CSS с поддержкой светлой и темной тем.
## Функциональность ## Функциональность
- Отображение текущей погоды (температура, влажность, ветер) - **Текущая погода**: температура, влажность, скорость ветра, описание условий
- Таймлапс погоды на день - **Таймлапс**: почасовой прогноз погоды на день с визуализацией
- Адаптивный дизайн - **Недельный прогноз**: погода на 7 дней вперед
- Выбор городов - **Интерактивные графики**: температура и осадки с помощью Chart.js
- **Адаптивный дизайн**: корректное отображение на всех устройствах
- **Выбор городов**: предустановленный список российских городов
- **Система тем**: светлая, темная и автоматическая (по системным настройкам)
- **Анимации**: плавные переходы и hover-эффекты
## Технологии ## Технологии
- Node.js ### Backend
- Express
- Tailwind CSS
- HTML5
- JavaScript
- Swiper.js (для слайдера)
- Chart.js (для графиков)
- Lucide Icons (для иконок)
- Google Fonts (Inter)
## Установка - **Node.js** v8+ (устаревшая версия, рекомендуется обновить до LTS)
- **Express.js** v4.17.1 - веб-сервер
### Frontend
- **HTML5** - семантическая разметка
- **JavaScript** (Vanilla) - клиентская логика
- **Tailwind CSS** v3.4.16 - утилитарный CSS фреймворк
- **PostCSS** v8.5.6 - обработка CSS
- **Autoprefixer** v10.4.21 - вендорные префиксы
### Библиотеки и CDN
- **Lucide Icons** - современные SVG иконки
- **Swiper.js** v11 - слайдер для таймлапса
- **Chart.js** - построение графиков
- **Google Fonts** (Inter) - шрифты
### Стилизация
- CSS переменные для тематизации
- Плавные анимации переходов
- Цветовые схемы для разных погодных условий
## Установка и запуск
### Системные требования
- **Node.js** v8+ (⚠️ устаревшая версия, рекомендуется использовать LTS версию Node.js 18+)
- **npm** для управления пакетами
### Установка
1. **Клонируйте репозиторий:**
1. Клонируйте репозиторий:
```bash ```bash
git clone <url> git clone <repository-url>
cd weather-app cd weather-app
``` ```
2. Установите зависимости: 2. **Установите зависимости:**
```bash ```bash
npm install npm install
``` ```
3. Запустите сервер: 3. **Соберите CSS (если необходимо):**
```bash
npm run build-css
```
4. **Запустите сервер:**
```bash ```bash
npm start npm start
``` ```
4. Откройте http://localhost:3000 в браузере. 5. **Откройте браузер:**
Перейдите по адресу http://localhost:3000
## Структура проекта ### Доступные скрипты
- `server.js` - сервер на Express - `npm start` - запуск сервера разработки
- `index.html` - главная страница - `npm run build-css` - сборка Tailwind CSS из `input.css` в `output.css`
- `script.js` - клиентский JavaScript - `npm run watch-css` - автоматическая пересборка CSS при изменениях
- `package.json` - конфигурация
## API и внешние сервисы
- **WeatherAPI.com** - источник данных о погоде
- **Google Fonts API** - загрузка шрифтов Inter
- **CDN сервисы** для библиотек JavaScript (jsDelivr, unpkg)
## Разработчик
Разработано: **Fovway**
Контакты:
- Email: [admin@fovway.ru](mailto:admin@fovway.ru)
## Рекомендации
### Обновление Node.js
Текущая конфигурация требует Node.js v8, но рекомендуется использовать актуальную LTS версию (18+) для повышения безопасности и производительности.
### Настройка API ключа
Для полноценной работы приложения необходимо:
1. Зарегистрироваться на [WeatherAPI.com](https://weatherapi.com)
2. Получить бесплатный API ключ
3. Добавить ключ в переменные окружения или конфигурацию сервера(server.js - const API_KEY = "API_KEY_HERE";)
### Производительность
- Приложение использует CDN для внешних библиотек, что обеспечивает быструю загрузку
- CSS собирается с помощью Tailwind CSS для оптимального размера файлов
- Используйте `npm run watch-css` во время разработки для автоматической пересборки стилей
## Лицензия ## Лицензия
MIT MIT

View File

@ -1,201 +1,496 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ru"> <html lang="ru">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Погода</title> <title>Погода</title>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><defs><style>.a{fill:%233b82f6;}.b{fill:%23ffffff;}</style></defs><circle class='a' cx='16' cy='16' r='12'/><circle class='b' cx='16' cy='16' r='8'/><path class='a' d='M16,4V6M16,26V28M28,16H26M6,16H4M22.5,9.5l-1.5,1.5M8.5,22.5l-1.5,1.5M22.5,22.5l-1.5-1.5M8.5,9.5l-1.5-1.5' stroke='%233b82f6' stroke-width='1.5' fill='none'/><ellipse class='a' cx='20' cy='24' rx='8' ry='4' opacity='0.7'/></svg>"> <link
<script src="https://cdn.tailwindcss.com"></script> rel="icon"
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> type="image/svg+xml"
href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><defs><style>.a{fill:%233b82f6;}.b{fill:%23ffffff;}</style></defs><circle class='a' cx='16' cy='16' r='12'/><circle class='b' cx='16' cy='16' r='8'/><path class='a' d='M16,4V6M16,26V28M28,16H26M6,16H4M22.5,9.5l-1.5,1.5M8.5,22.5l-1.5,1.5M22.5,22.5l-1.5-1.5M8.5,9.5l-1.5-1.5' stroke='%233b82f6' stroke-width='1.5' fill='none'/><ellipse class='a' cx='20' cy='24' rx='8' ry='4' opacity='0.7'/></svg>"
/>
<link rel="stylesheet" href="output.css" />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap"
rel="stylesheet"
/>
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script> <script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
<!-- Swiper CSS --> <!-- Swiper CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css"> <link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css"
/>
<!-- Chart.js --> <!-- Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style> <style>
body { font-family: 'Inter', sans-serif; } :root {
.swiper-slide { height: auto; } --theme-bg: linear-gradient(to bottom right, #dbeafe, #ffffff, #e0e7ff);
.timelapse-container { padding-top: 12px; padding-bottom: 12px; } --theme-text: #1e293b;
.timelapse-item { transition: all 0.3s ease; } --theme-text-secondary: #64748b;
.timelapse-item:hover { transform: translateY(-4px); box-shadow: 0 10px 25px rgba(0,0,0,0.1); } --theme-card-bg: #ffffff;
--theme-border: #e2e8f0;
--theme-shadow: rgba(0, 0, 0, 0.1);
}
/* Стили для графиков */ [data-theme="dark"] {
--theme-bg: linear-gradient(to bottom right, #1e293b, #0f172a, #1e3a8a);
--theme-text: #f8fafc;
--theme-text-secondary: #cbd5e1;
--theme-card-bg: #1e293b;
--theme-border: #334155;
--theme-shadow: rgba(0, 0, 0, 0.3);
}
body {
font-family: "Inter", sans-serif;
background: var(--theme-bg);
color: var(--theme-text);
min-height: 100vh;
transition: background 0.3s ease, color 0.3s ease;
}
/* Динамические элементы с поддержкой темы */
.dynamic-card {
transition: all 0.3s ease;
}
.dynamic-card.dark-theme {
background: #1e293b;
border-color: #334155;
}
.dynamic-card.light-theme {
background: #ffffff;
border-color: #e2e8f0;
}
.swiper-slide {
height: auto;
}
.timelapse-container {
padding-top: 12px;
padding-bottom: 12px;
}
/* Стили для графиков */
.chart-container {
position: relative;
height: 300px;
width: 100%;
}
.chart-container canvas {
max-height: 300px;
width: 100% !important;
height: 100% !important;
}
@media (max-width: 1024px) {
.chart-container { .chart-container {
position: relative; height: 250px;
height: 300px;
width: 100%;
} }
}
.chart-container canvas { @media (max-width: 768px) {
max-height: 300px; .chart-container {
width: 100% !important; height: 200px;
height: 100% !important;
} }
}
@media (max-width: 1024px) { /* Анимации для переключения темы */
.chart-container { * {
height: 250px; transition: background-color 0.3s ease, color 0.3s ease,
} border-color 0.3s ease;
} }
@media (max-width: 768px) { /* Стили для переключателя темы */
.chart-container { .theme-button {
height: 200px; transition: all 0.2s ease;
} }
}
.theme-button.active {
background-color: #3b82f6;
color: white;
}
.theme-button.active i {
color: white;
}
/* Стили для кнопок темы */
#theme-light,
#theme-auto,
#theme-dark {
transition: all 0.2s ease;
}
#theme-light:hover,
#theme-auto:hover,
#theme-dark:hover {
background-color: #f1f5f9;
transform: scale(1.05);
}
.dark #theme-light:hover,
.dark #theme-auto:hover,
.dark #theme-dark:hover {
background-color: #334155;
}
/* Поддержка тем через data-theme атрибут */
[data-theme="dark"] {
@apply dark;
}
/* Глобальные стили для темной темы */
[data-theme="dark"] * {
transition: background-color 0.3s ease, color 0.3s ease,
border-color 0.3s ease;
}
/* Плавные переходы для карточек */
.weather-card {
transition: all 0.3s ease;
}
.weather-card:hover {
transform: translateY(-2px);
}
/* Цветные стили для погодных иконок */
.weather-icon.sun {
color: #f59e0b;
}
.weather-icon.sun-dark {
color: #fbbf24;
}
.weather-icon.cloud {
color: #6b7280;
}
.weather-icon.cloud-dark {
color: #9ca3af;
}
.weather-icon.rain {
color: #3b82f6;
}
.weather-icon.rain-dark {
color: #60a5fa;
}
.weather-icon.snow {
color: #06b6d4;
}
.weather-icon.snow-dark {
color: #67e8f9;
}
.weather-icon.thunder {
color: #8b5cf6;
}
.weather-icon.thunder-dark {
color: #a78bfa;
}
.weather-icon.fog {
color: #9ca3af;
}
.weather-icon.fog-dark {
color: #d1d5db;
opacity: 0.7;
}
.weather-icon.wind {
color: #10b981;
}
.weather-icon.wind-dark {
color: #34d399;
}
.weather-icon.drizzle {
color: #06b6d4;
}
.weather-icon.drizzle-dark {
color: #22d3ee;
}
.weather-icon.hail {
color: #6366f1;
}
.weather-icon.hail-dark {
color: #818cf8;
}
</style> </style>
</head> </head>
<body class="bg-gradient-to-br from-blue-50 via-white to-indigo-50 min-h-screen"> <body class="min-h-screen">
<div class="container mx-auto max-w-7xl px-4 py-8"> <div class="container mx-auto max-w-7xl px-4 py-8">
<!-- Header --> <!-- Header -->
<header class="text-center mb-12"> <header class="text-center mb-12">
<div class="flex items-center justify-center gap-3 mb-4"> <div class="flex items-center justify-center gap-3 mb-4">
<div class="p-3 bg-blue-500 rounded-full"> <div class="p-3 bg-blue-500 rounded-full">
<i data-lucide="cloud-sun" class="w-8 h-8 text-white"></i> <i data-lucide="cloud-sun" class="w-8 h-8 text-white"></i>
</div> </div>
<h1 class="text-4xl md:text-5xl font-bold text-gray-800">Погода</h1> <h1
</div> class="text-4xl md:text-5xl font-bold"
<p class="text-gray-600 text-lg">Узнайте погоду в вашем городе</p> style="color: var(--theme-text)"
<div class="mt-4 flex items-center justify-center gap-2 text-gray-700"> >
<i data-lucide="calendar" class="w-5 h-5"></i> Погода
<span class="font-medium" id="current-date">Загрузка...</span> </h1>
</div> </div>
</header> <p class="text-lg" style="color: var(--theme-text-secondary)">
Узнайте погоду в вашем городе
<!-- City Selector --> </p>
<div class="bg-white rounded-2xl shadow-xl p-8 mb-12 border border-gray-100"> <div
<div class="flex flex-col md:flex-row items-center gap-6"> class="mt-4 flex items-center justify-center gap-2"
<div class="flex items-center gap-3 text-gray-700"> style="color: var(--theme-text)"
<i data-lucide="map-pin" class="w-5 h-5"></i> >
<label for="city" class="font-medium text-lg">Выберите город:</label> <i data-lucide="calendar" class="w-5 h-5"></i>
</div> <span class="font-medium" id="current-date">Загрузка...</span>
<select id="city" class="flex-1 px-6 py-3 border-2 border-gray-200 rounded-xl focus:border-blue-500 focus:ring-2 focus:ring-blue-200 transition-all duration-200 bg-white text-gray-700 font-medium min-w-[200px]">
<option value="Moscow">Москва</option>
<option value="Saint Petersburg">Санкт-Петербург</option>
<option value="Novosibirsk">Новосибирск</option>
<option value="Yekaterinburg">Екатеринбург</option>
<option value="Nizhny Novgorod">Нижний Новгород</option>
<option value="Kazan">Казань</option>
<option value="Chelyabinsk">Челябинск</option>
<option value="Omsk">Омск</option>
<option value="Samara">Самара</option>
<option value="Rostov-on-Don">Ростов-на-Дону</option>
</select>
<button id="get-weather" class="px-8 py-3 bg-blue-500 hover:bg-blue-600 text-white font-semibold rounded-xl transition-all duration-200 transform hover:scale-105 shadow-lg hover:shadow-xl flex items-center gap-2">
<i data-lucide="search" class="w-5 h-5"></i>
Выбрать
</button>
</div>
</div> </div>
<!-- Weather Info --> <!-- Theme Toggle -->
<div class="weather-info"> <div class="mt-6 flex items-center justify-center gap-4">
<!-- Current Weather Section --> <div
<div id="current-weather" class="hidden bg-white rounded-2xl shadow-xl p-8 mb-8 border border-gray-100"> class="flex items-center gap-2 bg-gray-100 dark:bg-gray-700 rounded-lg p-1"
<div class="text-center"> >
<h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center justify-center gap-2"> <button
<i data-lucide="thermometer" class="w-6 h-6"></i> id="theme-light"
Текущая погода class="p-2 rounded-md transition-all duration-200 dark:text-gray-300"
</h2> title="Светлая тема"
<div class="grid grid-cols-1 md:grid-cols-3 gap-6"> >
<div class="text-center"> <i
<div class="flex items-center justify-center gap-2 mb-2"> data-lucide="sun"
<i data-lucide="thermometer" class="w-5 h-5 text-blue-500"></i> class="w-5 h-5 text-gray-600 dark:text-gray-300"
<p class="text-4xl font-bold text-blue-500" id="current-temp">--°C</p> ></i>
</div> </button>
<p class="text-gray-600" id="current-desc">Загрузка...</p> <button
</div> id="theme-auto"
<div class="text-center"> class="p-2 rounded-md transition-all duration-200 dark:text-gray-300"
<div class="flex items-center justify-center gap-2 mb-2"> title="Системная тема"
<i data-lucide="droplets" class="w-5 h-5 text-blue-500"></i> >
<div> <i
<p class="text-lg text-gray-600">Влажность</p> data-lucide="monitor"
<p class="text-2xl font-semibold text-gray-800" id="current-humidity">--%</p> class="w-5 h-5 text-gray-600 dark:text-gray-300"
</div> ></i>
</div> </button>
</div> <button
<div class="text-center"> id="theme-dark"
<div class="flex items-center justify-center gap-2 mb-2"> class="p-2 rounded-md transition-all duration-200 dark:text-gray-300"
<i data-lucide="wind" class="w-5 h-5 text-blue-500"></i> title="Темная тема"
<div> >
<p class="text-lg text-gray-600">Ветер</p> <i
<p class="text-2xl font-semibold text-gray-800" id="current-wind">-- км/ч</p> data-lucide="moon"
</div> class="w-5 h-5 text-gray-600 dark:text-gray-300"
</div> ></i>
</div> </button>
</div> </div>
</div>
</div>
<!-- Timelapse Section -->
<div class="timelapse-weather bg-white rounded-2xl shadow-xl p-8 border border-gray-100">
<h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center gap-2">
<i data-lucide="clock" class="w-6 h-6"></i>
Погода на весь день
</h2>
<div class="swiper timelapse-container">
<div id="timelapse-container" class="swiper-wrapper"></div>
</div>
</div>
<!-- Weekly Weather Section -->
<div class="weekly-weather bg-white rounded-2xl shadow-xl p-8 border border-gray-100 mt-8">
<h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center gap-2">
<i data-lucide="calendar-days" class="w-6 h-6"></i>
Погода на неделю
</h2>
<div class="grid grid-cols-1 md:grid-cols-7 gap-4" id="weekly-container">
<!-- Карточки недельного прогноза будут добавлены сюда -->
</div>
</div>
<!-- Charts Section -->
<div class="charts-section bg-white rounded-2xl shadow-xl p-8 border border-gray-100 mt-8">
<h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center gap-2">
<i data-lucide="bar-chart-3" class="w-6 h-6"></i>
Графики погоды
</h2>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<!-- Temperature Chart -->
<div class="chart-container">
<h3 class="text-lg font-semibold text-gray-700 mb-4 flex items-center gap-2">
<i data-lucide="thermometer" class="w-5 h-5 text-blue-500"></i>
Температура (°C)
</h3>
<canvas id="temperatureChart"></canvas>
</div>
<!-- Precipitation Chart -->
<div class="chart-container">
<h3 class="text-lg font-semibold text-gray-700 mb-4 flex items-center gap-2">
<i data-lucide="cloud-rain" class="w-5 h-5 text-blue-500"></i>
Осадки (мм)
</h3>
<canvas id="precipitationChart"></canvas>
</div>
</div>
</div>
</div> </div>
</header>
<!-- City Selector -->
<div class="weather-card rounded-2xl shadow-xl p-8 mb-12">
<div class="flex flex-col md:flex-row items-center gap-6">
<div
class="flex items-center gap-3"
style="color: var(--theme-text-secondary)"
>
<i data-lucide="map-pin" class="w-5 h-5 text-blue-500"></i>
<label
for="city"
class="font-medium text-lg"
style="color: var(--theme-text-secondary)"
>Выберите город:</label
>
</div>
<select
id="city"
class="flex-1 px-6 py-3 border-2 border-gray-200 rounded-xl focus:border-blue-500 focus:ring-2 focus:ring-blue-200 transition-all duration-200 bg-white text-gray-700 font-medium min-w-[200px]"
>
<option value="Moscow">Москва</option>
<option value="Saint Petersburg">Санкт-Петербург</option>
<option value="Novosibirsk">Новосибирск</option>
<option value="Yekaterinburg">Екатеринбург</option>
<option value="Nizhny Novgorod">Нижний Новгород</option>
<option value="Kazan">Казань</option>
<option value="Chelyabinsk">Челябинск</option>
<option value="Omsk">Омск</option>
<option value="Samara">Самара</option>
<option value="Rostov-on-Don">Ростов-на-Дону</option>
</select>
<button
id="get-weather"
class="px-8 py-3 bg-blue-500 hover:bg-blue-600 text-white font-semibold rounded-xl transition-all duration-200 transform hover:scale-105 shadow-lg hover:shadow-xl flex items-center gap-2"
>
<i data-lucide="search" class="w-5 h-5"></i>
Выбрать
</button>
</div>
</div>
<!-- Weather Info -->
<div class="weather-info">
<!-- Current Weather Section -->
<div
id="current-weather"
class="hidden weather-card rounded-2xl shadow-xl p-8 mb-8"
>
<div class="text-center">
<h2
class="text-2xl font-bold mb-6 flex items-center justify-center gap-2"
style="color: var(--theme-text)"
>
<i data-lucide="thermometer" class="w-6 h-6 text-blue-500"></i>
Текущая погода
</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="text-center">
<div class="flex items-center justify-center gap-2 mb-2">
<i
data-lucide="thermometer"
class="w-5 h-5 text-blue-500"
></i>
<p class="text-4xl font-bold text-blue-500" id="current-temp">
--°C
</p>
</div>
<p
class="text-lg"
id="current-desc"
style="color: var(--theme-text-secondary)"
>
Загрузка...
</p>
</div>
<div class="text-center">
<div class="flex items-center justify-center gap-2 mb-2">
<i data-lucide="droplets" class="w-5 h-5 text-blue-500"></i>
<div>
<p
class="text-lg"
style="color: var(--theme-text-secondary)"
>
Влажность
</p>
<p
class="text-2xl font-semibold"
id="current-humidity"
style="color: var(--theme-text)"
>
--%
</p>
</div>
</div>
</div>
<div class="text-center">
<div class="flex items-center justify-center gap-2 mb-2">
<i data-lucide="wind" class="w-5 h-5 text-blue-500"></i>
<div>
<p
class="text-lg"
style="color: var(--theme-text-secondary)"
>
Ветер
</p>
<p
class="text-2xl font-semibold"
id="current-wind"
style="color: var(--theme-text)"
>
-- км/ч
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Timelapse Section -->
<div class="timelapse-weather weather-card rounded-2xl shadow-xl p-8">
<h2
class="text-2xl font-bold mb-6 flex items-center gap-2"
style="color: var(--theme-text)"
>
<i data-lucide="clock" class="w-6 h-6 text-blue-500"></i>
Погода на весь день
</h2>
<div class="swiper timelapse-container">
<div id="timelapse-container" class="swiper-wrapper"></div>
</div>
</div>
<!-- Weekly Weather Section -->
<div class="weekly-weather weather-card rounded-2xl shadow-xl p-8 mt-8">
<h2
class="text-2xl font-bold mb-6 flex items-center gap-2"
style="color: var(--theme-text)"
>
<i data-lucide="calendar-days" class="w-6 h-6 text-blue-500"></i>
Погода на неделю
</h2>
<div
class="grid grid-cols-1 md:grid-cols-7 gap-4"
id="weekly-container"
>
<!-- Карточки недельного прогноза будут добавлены сюда -->
</div>
</div>
<!-- Charts Section -->
<div class="charts-section weather-card rounded-2xl shadow-xl p-8 mt-8">
<h2
class="text-2xl font-bold mb-6 flex items-center gap-2"
style="color: var(--theme-text)"
>
<i data-lucide="bar-chart-3" class="w-6 h-6 text-blue-500"></i>
Графики погоды
</h2>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<!-- Temperature Chart -->
<div class="chart-container">
<h3
class="text-lg font-semibold text-gray-700 mb-4 flex items-center gap-2"
>
<i data-lucide="thermometer" class="w-5 h-5 text-blue-500"></i>
Температура (°C)
</h3>
<canvas id="temperatureChart"></canvas>
</div>
<!-- Precipitation Chart -->
<div class="chart-container">
<h3
class="text-lg font-semibold text-gray-700 mb-4 flex items-center gap-2"
>
<i data-lucide="cloud-rain" class="w-5 h-5 text-blue-500"></i>
Осадки (мм)
</h3>
<canvas id="precipitationChart"></canvas>
</div>
</div>
</div>
</div>
</div> </div>
<!-- Footer --> <!-- Footer -->
<footer class="mt-8 mb-8 text-center"> <footer class="mt-8 mb-8 text-center">
<div class="text-gray-500 text-sm"> <div class="text-sm" style="color: var(--theme-text-secondary)">
<p class="mb-1">Разработано: <span class="font-medium">Fovway</span></p> <p class="mb-1">
<p> Разработано:
<i data-lucide="mail" class="w-3 h-3 inline mr-1"></i> <span class="font-medium" style="color: var(--theme-text)"
<a href="mailto:admin@fovway.ru" class="hover:text-blue-500 transition-colors duration-200"> >Fovway</span
admin@fovway.ru >
</a> </p>
</p> <p>
</div> <i data-lucide="mail" class="w-3 h-3 inline mr-1"></i>
<a
href="mailto:admin@fovway.ru"
class="transition-colors duration-200 text-blue-500 hover:text-blue-600"
>
admin@fovway.ru
</a>
</p>
</div>
</footer> </footer>
<script src="script.js"></script> <script src="script.js"></script>
<!-- Swiper JS --> <!-- Swiper JS -->
<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
<script> <script>
lucide.createIcons(); lucide.createIcons();
</script> </script>
</body> </body>
</html> </html>

16
input.css Normal file
View File

@ -0,0 +1,16 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Custom styles */
.weather-card {
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
border-color: rgb(229 231 235 / var(--tw-border-opacity, 1));
box-shadow: 0 20px 25px -5px rgba(0,0,0,0.1), 0 10px 10px -5px rgba(0,0,0,0.1);
}
.dark .weather-card {
background-color: rgb(30 41 55 / var(--tw-bg-opacity, 1));
border-color: rgb(71 85 105 / var(--tw-border-opacity, 1));
box-shadow: 0 20px 25px -5px rgba(0,0,0,0.3), 0 10px 10px -5px rgba(0,0,0,0.3);
}

1187
output.css Normal file

File diff suppressed because it is too large Load Diff

1513
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,9 @@
"description": "Weather app with timelapse", "description": "Weather app with timelapse",
"main": "server.js", "main": "server.js",
"scripts": { "scripts": {
"start": "node server.js" "start": "node server.js",
"build-css": "tailwindcss -i input.css -o output.css",
"watch-css": "tailwindcss -i input.css -o output.css --watch"
}, },
"engines": { "engines": {
"node": "8" "node": "8"
@ -13,6 +15,8 @@
"express": "^4.17.1" "express": "^4.17.1"
}, },
"devDependencies": { "devDependencies": {
"tailwindcss": "^4.1.14" "autoprefixer": "^10.4.21",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.16"
} }
} }

6
postcss.config.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

1381
script.js

File diff suppressed because it is too large Load Diff

9
tailwind.config.js Normal file
View File

@ -0,0 +1,9 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./index.html", "./script.js"],
darkMode: 'class',
theme: {
extend: {},
},
plugins: [],
}