refactor: rename project to gallery

This commit is contained in:
2024-08-11 20:46:04 +03:00
parent 3785b8ce5d
commit 72fd378c40
48 changed files with 117 additions and 92 deletions

View File

@@ -0,0 +1,87 @@
import datetime
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from gallery.sketch.weather.api import WeatherApi
from gallery.sketch.weather.mock import WEATHER_MOCK_DATA
from gallery.sketch.weather.model import WeatherResponse
from ..util import TagType, TagUtil
from .filters import cloudness_icon, wind_direction_icon
def mount(app: FastAPI):
base_dir = Path(__file__).parent
app.mount("/static", StaticFiles(directory=base_dir / "static"), name="static")
templates = Jinja2Templates(directory=base_dir / "templates")
templates.env.filters["wind_direction_icon"] = wind_direction_icon
templates.env.filters["cloudness_icon"] = cloudness_icon
def build_weather_response(request: Request, response: WeatherResponse):
return templates.TemplateResponse(
request=request,
name="weather.html",
context={
"tag_util": TagUtil,
"datetime": datetime,
"response": response,
},
)
@app.get("/", response_class=RedirectResponse)
async def get_weather_root():
return RedirectResponse("weather")
@app.get("/weather", response_class=HTMLResponse)
async def get_weather_list(request: Request):
weather_api: WeatherApi = request.app.state.weather_api
locations = await weather_api.get_locations()
return templates.TemplateResponse(
request=request,
name="index.html",
context={
"locations": locations,
},
)
@app.get("/weather/{location}", response_class=RedirectResponse)
async def get_weather_default(location: str):
return RedirectResponse(f"{location}/tag/today")
@app.get("/weather/{location}/day/mock", response_class=HTMLResponse)
async def get_weather_day_mock(request: Request):
response = WEATHER_MOCK_DATA.get_response("day")
return build_weather_response(request, response)
@app.get("/weather/{location}/days/mock", response_class=HTMLResponse)
async def get_weather_days_mock(request: Request):
response = WEATHER_MOCK_DATA.get_response("days")
return build_weather_response(request, response)
@app.get("/weather/{location}/day/{date}", response_class=HTMLResponse)
async def get_weather_day(request: Request, location: str, date: datetime.date):
weather_api: WeatherApi = request.app.state.weather_api
response = await weather_api.get_day(location, date)
return build_weather_response(request, response)
@app.get("/weather/{location}/days/{days}", response_class=HTMLResponse)
async def get_weather_days(request: Request, location: str, days: int):
weather_api: WeatherApi = request.app.state.weather_api
response = await weather_api.get_days(location, days)
return build_weather_response(request, response)
@app.get("/weather/{location}/tag/{tag}", response_class=HTMLResponse)
async def get_weather_tag(request: Request, location: str, tag: str):
tag_value = TagUtil.parse_tag(tag)
weather_api: WeatherApi = request.app.state.weather_api
if tag_value.type == TagType.DAY:
response = await weather_api.get_day(location, tag_value.date)
elif tag_value.type == TagType.DAYS:
response = await weather_api.get_days(location, tag_value.days)
else:
raise ValueError(tag)
return build_weather_response(request, response)

View File

@@ -0,0 +1,39 @@
from gallery.sketch.weather.model import Cloudness, Precipitation, Sky, WindDirection
def wind_direction_icon(wind_direction: WindDirection) -> str:
return {
WindDirection.N: "⬇️",
WindDirection.NO: "↙️",
WindDirection.O: "⬅️",
WindDirection.SO: "↖️",
WindDirection.S: "⬆️",
WindDirection.SW: "↗️",
WindDirection.W: "➡️",
WindDirection.NW: "↘️",
WindDirection.CALM: "",
}.get(wind_direction, wind_direction)
def cloudness_icon(sky: Sky) -> list[str]:
main_icon = ""
if sky.thunder:
if sky.cloudness == Cloudness.CLEAR:
main_icon = "🌩️"
if sky.precipitation == Precipitation.NO:
main_icon = ""
else:
main_icon = "⛈️"
elif sky.precipitation == Precipitation.NO:
main_icon = {
Cloudness.CLEAR: "☀️",
Cloudness.PARTLY_CLOUDY: "🌤️",
Cloudness.CLOUDY: "",
Cloudness.MAINLY_CLOUDY: "☁️",
}[sky.cloudness]
else:
main_icon = "🌧️"
icons = [main_icon]
if sky.fog:
icons.append("🌫️")
return icons

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

View File

@@ -0,0 +1,116 @@
body {
font-size: 1.5rem;
}
.app-container {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-items: center;
}
h3 {
margin: 0.5rem 0;
}
a.button {
text-decoration: none;
color: inherit;
}
.button.disabled {
pointer-events: none;
cursor: default;
color: gray;
filter: grayscale(100%);
}
table {
/* width: 100%; */
table-layout: fixed;
border-collapse: collapse;
}
table,
th,
td {
/* border: 1px solid rgba(0, 0, 0, 0.2); */
text-align: center;
}
td {
padding: 0.1rem 0.4rem;
}
.header {
font-size: 1rem;
text-align: left;
padding-top: 0.25rem;
}
.date {
font-size: 1.5rem;
background: rgba(0, 0, 0, 0.1);
}
.date.now {
background: rgba(0, 128, 255, 0.2);
}
.date .value a {
all: unset;
cursor: pointer;
}
.cloudness {
vertical-align: top;
}
.cloudness .icon {
font-size: 1rem;
}
.cloudness .icon:first-child {
font-size: 2rem;
}
.temperature {
padding: 0;
}
.temperature .value {
padding: 0.1rem 0.4rem;
}
.temperature .value.positive {
color: orangered;
}
.temperature .value.negative {
color: blue;
}
.wind .direction {
font-size: 1rem;
}
.wind .gust {
font-size: 1rem;
}
.precipitation .value {
color: blue;
}
.pressure {
padding: 0;
}
.pressure .value {
padding: 0.1rem 0.4rem;
color: blueviolet;
}
.humidity .value {
color: blue;
}

View File

@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible"
content="ie=edge">
<title>Погода</title>
<link rel="stylesheet"
href="/static/style.css?v=1">
<link rel="icon"
href="/static/favicon.ico"
type="image/x-icon">
</head>
<body class="app-container">
<ul>
{% for location in locations %}
<li><a href="weather/{{location}}">{{location}}</a></li>
{% endfor %}
</ul>
</body>
</html>

View File

@@ -0,0 +1,177 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible"
content="ie=edge">
<title>Погода | {{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</title>
<link rel="stylesheet"
href="/static/style.css?v=1">
<link rel="icon"
href="/static/favicon.ico"
type="image/x-icon">
</head>
<body class="app-container">
<h3>
{% if response.period == 'day' %}
<a class="button {{'disabled' if response.date == datetime.date.today() else ''}}"
href="../tag/{{tag_util.create_tag('day', response.date, -1)}}">⬅️</a>
<a class="button"
href="../tag/days-10">⬆️</a>
<span>{{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
<a class="button"
href="../tag/{{tag_util.create_tag('day', response.date, 1)}}">➡️</a>
{% endif %}
{% if response.period == 'days' %}
<span>{{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
{% endif %}
</h3>
<table>
<tbody>
<!-- date -->
<tr>
{% for value in response.values %}
{% if response.period == 'day' %}
<td
class="date {{'now' if value.date < datetime.datetime.now() and value.date + datetime.timedelta(hours=3) > datetime.datetime.now() else ''}}">
<span class="value">{{value.date.strftime('%H:%M')}}</span>
</td>
{% endif %}
{% if response.period == 'days' %}
<td class="date {{'now' if value.date.date() == datetime.date.today() else ''}}">
<span class="value">
<a href="../tag/{{tag_util.create_tag('day', value.date.date())}}">
{{value.date.strftime('%a %d')}}
</a>
</span>
</td>
{% endif %}
{% endfor %}
</tr>
<!-- cloudness -->
<tr>
<td colspan="{{response.values | length}}"
class="header">
Облачность
</td>
</tr>
<tr>
{% for value in response.values %}
<td class="cloudness">
{% for icon in value.sky | cloudness_icon %}
<div class="icon">{{icon}}</div>
{% endfor %}
</td>
{% endfor %}
</tr>
<!-- temperature -->
<tr>
<td colspan="{{response.values | length}}"
class="header">
Температура, °C
</td>
</tr>
<tr>
{% for value in response.values %}
<td class="temperature">
{% for temperature in value.temperature %}
<div class="value {{'positive' if temperature > 0 else 'negative'}}"
style="background-color: rgba(255, 128, 128, {{(temperature - 10) * 0.015}});">
{{temperature}}
</div>
{% endfor %}
</td>
{% endfor %}
</tr>
<!-- wind_direction -->
<tr>
<td colspan="{{response.values | length}}"
class="header">
Направление ветра
</td>
</tr>
<tr>
{% for value in response.values %}
<td class="wind">
<span class="icon">{{value.wind_direction | wind_direction_icon}}</span>
</td>
{% endfor %}
</tr>
<!-- wind_speed -->
<tr>
<td colspan="{{response.values | length}}"
class="header">
Скорость ветра, м/с
</td>
</tr>
<tr>
{% for value in response.values %}
<td class="wind"
style="background-color: rgba(128, 128, 128, {{value.wind_speed * 0.05}});">
<span class="speed">{{value.wind_speed}}</span>
{% if value.wind_gust != value.wind_speed %}
<span class="gust">
({{value.wind_gust}})
</span>
{% endif %}
</td>
{% endfor %}
</tr>
<!-- precipitation -->
<tr>
<td colspan="{{response.values | length}}"
class="header">
Осадки, мм
</td>
</tr>
<tr>
{% for value in response.values %}
<td class="precipitation"
style="background-color: rgba(0, 128, 255, {{value.precipitation * 0.1}});">
<span class="value">{{value.precipitation or ''}}</span>
</td>
{% endfor %}
</tr>
<!-- pressure -->
<tr>
<td colspan="{{response.values | length}}"
class="header">
Давление, мм рт. ст.
</td>
</tr>
<tr>
{% for value in response.values %}
<td class="pressure">
{% for pressure in value.pressure %}
<div class="value"
style="background-color: rgba(128, 0, 255, {{(pressure - 720) * 0.008}});">
{{pressure}}</div>
{% endfor %}
</td>
{% endfor %}
</tr>
<!-- humidity -->
<tr>
<td colspan="{{response.values | length}}"
class="header">
Влажность, %
</td>
</tr>
<tr>
{% for value in response.values %}
<td class="humidity"
style="background-color: rgba(128, 128, 255, {{value.humidity * 0.005}});">
<span class="value">{{value.humidity}}</span>
</td>
{% endfor %}
</tr>
</tbody>
</table>
<script src="/static/index.js"></script>
</body>
</html>