improve tempalte

This commit is contained in:
Evgenii Alekseev 2019-09-10 01:32:32 +03:00
parent 5ce870714c
commit 59051dee7a
15 changed files with 368 additions and 36 deletions

View File

@ -106,3 +106,4 @@ Service which allows to manage savage loot distribution easy.
* `host`: address to bind, string, required.
* `port`: port to bind, int, required.
* `templates`: path to directory with jinja templates, string, required.

View File

@ -16,6 +16,7 @@ from service.api.views.html.index import IndexHtmlView
from service.api.views.html.loot import LootHtmlView
from service.api.views.html.loot_suggest import LootSuggestHtmlView
from service.api.views.html.player import PlayerHtmlView
from service.api.views.html.static import StaticHtmlView
def setup_routes(app: Application) -> None:
@ -33,6 +34,7 @@ def setup_routes(app: Application) -> None:
# html routes
app.router.add_get('/', IndexHtmlView)
app.router.add_get('/static/{resource_id}', StaticHtmlView)
app.router.add_get('/party', PlayerHtmlView)
app.router.add_post('/party', PlayerHtmlView)

View File

@ -18,7 +18,7 @@ from service.models.player import Player, PlayerId
class PlayerBaseView(View):
def player_add(self, job: Job, nick: str, link: Optional[str], priority: int) -> PlayerId:
player = Player(job, nick, BiS(), [], link, priority)
player = Player(job, nick, BiS(), [], link, int(priority))
player_id = player.player_id
self.request.app['party'].set_player(player)

View File

@ -31,6 +31,7 @@ class LootSuggestHtmlView(LootBaseView, PlayerBaseView):
async def post(self) -> Union[Dict[str, Any], Response]:
data = await self.request.post()
error = None
item_values: Dict[str, Any] = {}
players: List[PlayerIdWithCounters] = []
required = ['piece']
@ -40,20 +41,22 @@ class LootSuggestHtmlView(LootBaseView, PlayerBaseView):
try:
piece = Piece.get({'piece': data.get('piece'), 'is_tome': data.get('is_tome', False)})
players = self.loot_put(piece)
item_values = {'piece': piece.name, 'is_tome': piece.is_tome}
except Exception as e:
self.request.app.logger.exception('could not manage loot')
error = repr(e)
return {
'item': item_values,
'pieces': Piece.available() + [upgrade.name for upgrade in Upgrade],
'request_error': error,
'suggest': [
{
'player': player.pretty_name,
'loot_count_bis': player.loot_count_bis,
'loot_count_bis': player.loot_count_total_bis,
'loot_count': player.loot_count,
}
for player in players
],
'request_error': error
]
}

View File

@ -38,7 +38,7 @@ class PlayerHtmlView(PlayerBaseView):
{
'job': player.job.name,
'nick': player.nick,
'loot_count_bis': player.loot_count_bis,
'loot_count_bis': player.loot_count_total_bis,
'loot_count': player.loot_count,
'priority': player.priority
}

View File

@ -0,0 +1,22 @@
# Copyright (c) 2019 Evgeniy Alekseev.
#
# This file is part of ffxivbis
# (see https://github.com/arcan1s/ffxivbis).
#
# License: 3-clause BSD, see https://opensource.org/licenses/BSD-3-Clause
#
import os
from aiohttp.web import HTTPNotFound, Response, View
class StaticHtmlView(View):
async def get(self) -> Response:
resource_name = self.request.match_info['resource_id']
resource_path = os.path.join(self.request.app['templates_root'], 'static', resource_name)
if not os.path.exists(resource_path) or os.path.isdir(resource_path):
return HTTPNotFound()
with open(resource_path) as resource_file:
return Response(text=resource_file.read(), content_type='text/css')

View File

@ -41,7 +41,9 @@ def setup_service(config: Configuration, database: Database, loot: LootSelector,
app.logger.info('setup routes')
setup_routes(app)
if config.has_option('web', 'templates'):
aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader(config.get('web', 'templates')))
templates_root = app['templates_root'] = config.get('web', 'templates')
app['static_root_url'] = '/static'
aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader(templates_root))
app.logger.info('setup configuration')
app['config'] = config

View File

@ -45,6 +45,7 @@ class PlayerIdWithCounters(PlayerId):
loot_count: int
loot_count_bis: int
loot_count_total: int
loot_count_total_bis: int
@dataclass
@ -67,8 +68,9 @@ class Player:
return PlayerId(self.job, self.nick)
def player_id_with_counters(self, piece: Union[Piece, Upgrade, None]) -> PlayerIdWithCounters:
return PlayerIdWithCounters(self.job, self.nick, self.priority, self.loot_count(piece),
self.loot_count_bis(piece), self.loot_count_total(piece))
return PlayerIdWithCounters(self.job, self.nick, self.priority,
abs(self.loot_count(piece)), abs(self.loot_count_bis(piece)),
abs(self.loot_count_total(piece)), abs(self.loot_count_total_bis(piece)))
# ordering methods
def is_required(self, piece: Union[Piece, Upgrade, None]) -> bool:
@ -89,14 +91,19 @@ class Player:
def loot_count(self, piece: Union[Piece, Upgrade, None]) -> int:
if piece is None:
return len(self.loot)
return self.loot.count(piece)
return -self.loot_count_total(piece)
return -self.loot.count(piece)
def loot_count_bis(self, _: Union[Piece, Upgrade, None]) -> int:
return len([piece for piece in self.loot if self.bis.has_piece(piece)])
def loot_count_bis(self, piece: Union[Piece, Upgrade, None]) -> int:
if piece is None:
return -self.loot_count_total_bis(piece)
return -len([piece for piece in self.loot if self.bis.has_piece(piece)])
def loot_count_total(self, _: Union[Piece, Upgrade, None]) -> int:
return len(self.loot)
return -len(self.loot)
def loot_count_total_bis(self, _: Union[Piece, Upgrade, None]) -> int:
return len([piece for piece in self.bis.pieces if not piece.is_tome])
def loot_priority(self, _: Union[Piece, Upgrade, None]) -> int:
return self.priority

View File

@ -1,8 +1,9 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Best in slot</title>
{% include "style.jinja2" %}
<link href="{{ static('styles.css') }}" rel="stylesheet" type="text/css">
</head>
<body>
<h2>best in slot</h2>
@ -24,7 +25,7 @@
<input name="is_tome" id="is_tome" title="is tome" type="checkbox"/>
<input name="action" id="action" type="hidden" value="add"/>
<input name="method" id="method" type="hidden" value="post"/>
<button>add</button>
<input name="add" id="add" type="button" value="add"/>
</form>
<form action="/bis" method="post">
<select name="player" id="player" title="player">
@ -34,7 +35,7 @@
</select>
<input name="bis" id="bis" placeholder="player bis link" title="bis" type="text"/>
<input name="method" id="method" type="hidden" value="put"/>
<button>add</button>
<input name="add" id="add" type="button" value="add"/>
</form>
<table id="result">
@ -52,8 +53,11 @@
<td>{{ item.is_tome|e }}</td>
<td>
<form action="/bis" method="post">
<input name="player" id="player" type="hidden" value="{{ item.player|e }}"/>
<input name="piece" id="piece" type="hidden" value="{{ item.piece|e }}"/>
<input name="is_tome" id="is_tome" type="hidden" value="{{ item.is_tome|e }}"/>
<input name="action" id="action" type="hidden" value="remove"/>
<button>remove</button>
<input name="remove" id="remove" type="button" value="x"/>
</form>
</td>
</tr>

View File

@ -1,14 +1,17 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>FFXIV loot helper</title>
<link href="{{ static('styles.css') }}" rel="stylesheet" type="text/css">
</head>
<body>
<center>
<a href="/party" title="party"><h2>party</h2></a>
<a href="/bis" title="bis management"><h2>bis</h2></a>
<a href="/loot" title="loot management"><h2>loot</h2></a>
<a href="/suggest" title="suggest loot"><h2>suggest</h2></a>
<h2><a href="/party" title="party">party</a></h2>
<h2><a href="/bis" title="bis management">bis</a></h2>
<h2><a href="/loot" title="loot management">loot</a></h2>
<h2><a href="/suggest" title="suggest loot">suggest</a></h2>
</center>
</body>
</html>

View File

@ -1,8 +1,9 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Loot</title>
{% include "style.jinja2" %}
<link href="{{ static('styles.css') }}" rel="stylesheet" type="text/css">
</head>
<body>
<h2>Loot</h2>
@ -23,7 +24,7 @@
</select>
<input name="is_tome" id="is_tome" title="is tome" type="checkbox"/>
<input name="action" id="action" type="hidden" value="add"/>
<button>add</button>
<input name="add" id="add" type="button" value="add"/>
</form>
<table id="result">
@ -41,8 +42,11 @@
<td>{{ item.is_tome|e }}</td>
<td>
<form action="/loot" method="post">
<input name="player" id="player" type="hidden" value="{{ item.player|e }}"/>
<input name="piece" id="piece" type="hidden" value="{{ item.piece|e }}"/>
<input name="is_tome" id="is_tome" type="hidden" value="{{ item.is_tome|e }}"/>
<input name="action" id="action" type="hidden" value="remove"/>
<button>remove</button>
<input name="remove" id="remove" type="button" value="x"/>
</form>
</td>
</tr>

View File

@ -1,8 +1,9 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Suggest loot</title>
{% include "style.jinja2" %}
<link href="{{ static('styles.css') }}" rel="stylesheet" type="text/css">
</head>
<body>
<h2>suggest loot</h2>
@ -17,7 +18,7 @@
{% endfor %}
</select>
<input name="is_tome" id="is_tome" title="is tome" type="checkbox"/>
<button>suggest</button>
<input name="suggest" id="suggest" type="button" value="suggest"/>
</form>
<table id="result">
@ -25,6 +26,7 @@
<th>player</th>
<th>bis pieces looted</th>
<th>total pieces looted</th>
<th></th>
</tr>
{% for player in suggest %}
@ -32,6 +34,14 @@
<td class="include_search">{{ player.player|e }}</td>
<td>{{ player.loot_count_bis|e }}</td>
<td>{{ player.loot_count|e }}</td>
<td>
<form action="/loot" method="post">
<input name="player" id="player" type="hidden" value="{{ player.player|e }}"/>
<input name="piece" id="piece" type="hidden" value="{{ item.piece|e }}"/>
<input name="is_tome" id="is_tome" type="hidden" value="{{ item.is_tome|e }}"/>
<input name="action" id="action" type="hidden" value="remove"/>
</form>
</td>
</tr>
{% endfor %}
</table>

View File

@ -1,8 +1,9 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Party</title>
{% include "style.jinja2" %}
<link href="{{ static('styles.css') }}" rel="stylesheet" type="text/css">
</head>
<body>
<h2>party</h2>
@ -20,7 +21,7 @@
<input name="bis" id="bis" placeholder="player bis link" title="bis" type="text"/>
<input name="priority" id="priority" placeholder="player priority" title="priority" type="number" value="0"/>
<input name="action" id="action" type="hidden" value="add"/>
<button>add</button>
<input name="add" id="add" type="button" value="add"/>
</form>
<table id="result">
@ -42,8 +43,10 @@
<td>{{ player.priority|e }}</td>
<td>
<form action="/party" method="post">
<input name="nick" id="nick" type="hidden" value="{{ player.nick|e }}"/>
<input name="job" id="job" type="hidden" value="{{ player.job|e }}"/>
<input name="action" id="action" type="hidden" value="remove"/>
<button>remove</button>
<input name="remove" id="remove" type="button" value="x"/>
</form>
</td>
</tr>

277
templates/static/styles.css Normal file
View File

@ -0,0 +1,277 @@
/* in-text images */
figure.img {
float: right;
border: 0px solid #333;
padding: 0px;
margin: 5px 0px 5px 10px;
}
figure.img img {
max-width: 100%;
height: auto;
}
figure.img figcaption {
margin: 0px;
font-size: 90%;
font-style: italic;
text-align: center;
}
h1 .octicon-link, h2 .octicon-link, h3 .octicon-link, h4 .octicon-link, h5 .octicon-link, h6 .octicon-link {
display: none;
color: #222222;
vertical-align: middle;
}
h1:hover .anchor, h2:hover .anchor, h3:hover .anchor, h4:hover .anchor, h5:hover .anchor, h6:hover .anchor{
padding-left: 8px;
margin-left: -24px;
text-decoration: none;
}
h1:hover .anchor .octicon-link, h2:hover .anchor .octicon-link, h3:hover .anchor .octicon-link, h4:hover .anchor .octicon-link, h5:hover .anchor .octicon-link, h6:hover .anchor .octicon-link {
display: inline-block;
}
body {
padding: 50px;
font: 14px/1.5 "Liberation Sans", Helvetica, Arial, sans-serif;
color: #555555;
background: #eaeaea
}
h1, h2, h3, h4, h5, h6 {
color: #222222;
margin: 0 0 20px;
}
p, ul, ol, table, pre, dl {
margin: 0 0 20px;
text-align: justify;
}
h1, h2, h3 {
line-height: 1.1;
}
h1 {
font-size: 28px;
}
h2 {
color: #393939;
}
h3, h4, h5, h6 {
color: #494949;
}
a {
color: #3399cc;
font-weight: 350;
text-decoration: none;
}
a small {
font-size: 11px;
color: #777777;
margin-top: -0.6em;
display: block;
}
.wrapper {
width: 80%;
margin: 0 auto;
}
blockquote {
border-left: 1px solid #ffffff;
margin: 0;
padding: 0 0 0 20px;
font-style: italic;
}
code, pre {
font-family: "Liberation Mono", Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal;
color: #222222;
font-size: 12px;
}
pre {
padding: 8px 15px;
border-radius: 5px;
border: 1px solid #e5e5e5;
overflow-x: auto;
overflow-y: auto;
}
input, select{
box-sizing: border-box;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 5px 10px;
border-bottom: 1px solid #ffffff;
}
td {
text-align: justify;
}
dt {
color: #444444;
font-weight: 700;
}
th {
text-align: left;
color: #444444;
}
img {
max-width: 100%;
}
header {
width: 20%;
float: left;
position: fixed;
}
header ul {
list-style: none;
height: 40px;
padding: 0;
background: #eeeeee;
border-radius: 5px;
border: 1px solid #d2d2d2;
box-shadow: inset #fff 0 1px 0, inset rgba(0,0,0,0.03) 0 -1px 0;
width: 15%;
}
header li {
width: 8%;
float: left;
border-right: 1px solid #d2d2d2;
height: 40px;
}
header ul a {
line-height: 1;
font-size: 11px;
color: #999999;
display: block;
text-align: center;
padding-top: 6px;
height: 40px;
}
strong {
color: #222222;
font-weight: 700;
}
header ul li + li {
width: 8%;
border-left: 1px solid #ffffff;
}
header ul li + li + li {
width: 8%;
border-right: none;
}
header ul a strong {
font-size: 14px;
display: block;
color: #222222;
}
section {
width: 70%;
float: right;
padding-bottom: 50px;
}
small {
font-size: 11px;
}
hr {
border: 0;
background: #ffffff;
height: 1px;
margin: 0 0 20px;
}
footer {
width: 20%;
float: left;
position: fixed;
bottom: 50px;
}
@media print, screen and (max-width: 960px) {
div.wrapper {
width: auto;
margin: 0;
}
header, section, footer {
float: none;
position: static;
width: auto;
}
header {
padding-right: 320px;
}
section {
border: 1px solid #e5e5e5;
border-width: 1px 0;
padding: 20px 0;
margin: 0 0 20px;
}
header a small {
display: inline;
}
header ul {
position: absolute;
right: 50px;
top: 52px;
}
}
@media print, screen and (max-width: 720px) {
body {
word-wrap: break-word;
}
header {
padding: 0;
}
header ul, header p.view {
position: static;
}
pre, code {
word-wrap: normal;
}
}
@media print, screen and (max-width: 480px) {
body {
padding: 15px;
}
header ul {
display: none;
}
}
@media print {
body {
padding: 0.4in;
font-size: 12pt;
color: #444444;
}
}

View File

@ -1,6 +0,0 @@
<style>
table { border-collapse: collapse; }
table, th, td { border: 1px solid black; padding: 5px; }
input { margin: 5px; }
#error { color: #ff0000; }
</style>