Add game comments and rework game models
Models are now more structured for number of players, and durations can be omitted.
This commit is contained in:
parent
497e83eca3
commit
ccd8ee9cc9
25 changed files with 547 additions and 162 deletions
|
@ -1,6 +1,7 @@
|
|||
from django.contrib import admin
|
||||
from .models import Category, Tag, Game
|
||||
from .models import Category, Tag, Game, GameComment
|
||||
|
||||
admin.site.register(Category)
|
||||
admin.site.register(Tag)
|
||||
admin.site.register(Game)
|
||||
admin.site.register(GameComment)
|
||||
|
|
76
inventory/migrations/0002_auto_20201212_2233.py
Normal file
76
inventory/migrations/0002_auto_20201212_2233.py
Normal file
|
@ -0,0 +1,76 @@
|
|||
# Generated by Django 3.1.2 on 2020-12-12 21:33
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('inventory', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='category',
|
||||
options={'ordering': ['name'], 'verbose_name': 'catégorie'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='game',
|
||||
options={'ordering': ['title'], 'verbose_name': 'jeu', 'verbose_name_plural': 'jeux'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='tag',
|
||||
options={'ordering': ['name']},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='game',
|
||||
name='illustrator',
|
||||
field=models.CharField(blank=True, max_length=256, verbose_name='illustrateur·trice'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='game',
|
||||
name='missing_elements',
|
||||
field=models.TextField(blank=True, verbose_name='pièces manquantes'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='game',
|
||||
name='nb_player_max',
|
||||
field=models.PositiveSmallIntegerField(default=20, verbose_name='nombre de joueur·se·s maximum'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='game',
|
||||
name='nb_player_min',
|
||||
field=models.PositiveSmallIntegerField(default=2, verbose_name='nombre de joueur·se·s minimum'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='game',
|
||||
name='duration',
|
||||
field=models.CharField(blank=True, max_length=256, verbose_name='durée de partie'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='game',
|
||||
name='player_range',
|
||||
field=models.CharField(blank=True, help_text='Affichage personnalisé pour le nombre de joueur·se·s', max_length=256, verbose_name='nombre de joueur·se·s'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='GameComment',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('text', models.TextField(verbose_name='texte')),
|
||||
('created_on', models.DateTimeField(auto_now_add=True, verbose_name='date de publication')),
|
||||
('modified_on', models.DateTimeField(auto_now=True, verbose_name='date de modification')),
|
||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='auteur·ice')),
|
||||
('game', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='inventory.game', verbose_name='jeu')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'commentaire sur un jeu',
|
||||
'verbose_name_plural': 'commentaires sur des jeux',
|
||||
'ordering': ['created_on'],
|
||||
},
|
||||
),
|
||||
]
|
|
@ -1,5 +1,7 @@
|
|||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ValidationError
|
||||
from autoslug import AutoSlugField
|
||||
|
||||
|
||||
|
@ -8,6 +10,7 @@ class Category(models.Model):
|
|||
slug = AutoSlugField(populate_from="name", unique=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["name"]
|
||||
verbose_name = "catégorie"
|
||||
|
||||
def __str__(self):
|
||||
|
@ -21,6 +24,9 @@ class Tag(models.Model):
|
|||
name = models.CharField(max_length=256, verbose_name="nom")
|
||||
slug = AutoSlugField(populate_from="name", unique=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["name"]
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
@ -31,27 +37,83 @@ class Tag(models.Model):
|
|||
class Game(models.Model):
|
||||
title = models.CharField(verbose_name="titre", max_length=256)
|
||||
slug = AutoSlugField(populate_from="title", unique=True)
|
||||
player_range = models.CharField(
|
||||
max_length=256, verbose_name="nombre de joueur·se·s"
|
||||
nb_player_min = models.PositiveSmallIntegerField(
|
||||
verbose_name="nombre de joueur·se·s minimum"
|
||||
)
|
||||
nb_player_max = models.PositiveSmallIntegerField(
|
||||
verbose_name="nombre de joueur·se·s maximum"
|
||||
)
|
||||
player_range = models.CharField(
|
||||
max_length=256,
|
||||
blank=True,
|
||||
help_text="Affichage personnalisé pour le nombre de joueur·se·s",
|
||||
verbose_name="nombre de joueur·se·s",
|
||||
)
|
||||
duration = models.CharField(
|
||||
max_length=256, blank=True, verbose_name="durée de partie"
|
||||
)
|
||||
duration = models.CharField(max_length=256, verbose_name="durée de partie")
|
||||
editor = models.CharField(max_length=256, blank=True, verbose_name="éditeur")
|
||||
game_designer = models.CharField(
|
||||
max_length=256, blank=True, verbose_name="game designer"
|
||||
)
|
||||
illustrator = models.CharField(
|
||||
max_length=256, blank=True, verbose_name="illustrateur·trice"
|
||||
)
|
||||
editor = models.CharField(max_length=256, blank=True, verbose_name="éditeur")
|
||||
description = models.TextField(blank=True, verbose_name="description")
|
||||
category = models.ForeignKey(
|
||||
Category, on_delete=models.RESTRICT, verbose_name="catégorie"
|
||||
)
|
||||
tags = models.ManyToManyField(Tag, blank=True, verbose_name="tags")
|
||||
image = models.ImageField(upload_to="game_img/", blank=True, verbose_name="image")
|
||||
missing_elements = models.TextField(blank=True, verbose_name="pièces manquantes")
|
||||
|
||||
class Meta:
|
||||
ordering = ["title"]
|
||||
verbose_name = "jeu"
|
||||
verbose_name_plural = "jeux"
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
def clean(self):
|
||||
if self.nb_player_min > self.nb_player_max:
|
||||
raise ValidationError(
|
||||
{
|
||||
"nb_player_max": "Le nombre de joueur·se·s maximum doit être supérieur au nombre de joueurs minimum"
|
||||
}
|
||||
)
|
||||
|
||||
def get_player_range(self):
|
||||
if self.player_range:
|
||||
return self.player_range
|
||||
elif self.nb_player_min != self.nb_player_max:
|
||||
return "{} à {} joueur·se·s".format(self.nb_player_min, self.nb_player_max)
|
||||
else:
|
||||
return "{} joueur·se·s".format(self.nb_player_min)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse("inventory:game", args=(self.slug,))
|
||||
|
||||
|
||||
class GameComment(models.Model):
|
||||
game = models.ForeignKey(
|
||||
Game, on_delete=models.CASCADE, related_name="comments", verbose_name="jeu"
|
||||
)
|
||||
author = models.ForeignKey(
|
||||
User, on_delete=models.CASCADE, verbose_name="auteur·ice"
|
||||
)
|
||||
text = models.TextField(verbose_name="texte")
|
||||
created_on = models.DateTimeField(
|
||||
auto_now_add=True, verbose_name="date de publication"
|
||||
)
|
||||
modified_on = models.DateTimeField(
|
||||
auto_now=True, verbose_name="date de modification"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ["created_on"]
|
||||
verbose_name = "commentaire sur un jeu"
|
||||
verbose_name_plural = "commentaires sur des jeux"
|
||||
|
||||
def __str__(self):
|
||||
return "({}) {}: {}".format(self.game, self.author, self.text)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
Il y a {{ category_list|length }} catégorie{{ category_list|pluralize }} de jeux :
|
||||
<ul>
|
||||
{% for category in category_list %}
|
||||
<li><a href="{{ category.get_absolute_url }}"><i class="fa fa-bookmark" aria-hidden="true"></i> {{ category.name }}</a></li>
|
||||
{% include "./partials/category_item.html" %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
<div id="details">
|
||||
<p><i class="fa fa-fw fa-bookmark"></i> <a href="{{ game.category.get_absolute_url }}">{{ game.category }}</a></p>
|
||||
<hr/>
|
||||
<p><i class="fa fa-fw fa-users" aria-hidden="true"></i> {{ game.player_range }}</p>
|
||||
<p><i class="fa fa-fw fa-clock-o" aria-hidden="true"></i> {{ game.duration }}
|
||||
<p><i class="fa fa-fw fa-users" aria-hidden="true"></i> {{ game.get_player_range }}</p>
|
||||
<p><i class="fa fa-fw fa-clock-o" aria-hidden="true"></i> {{ game.duration|default:"(Durée de jeu inconnue)" }}
|
||||
<hr/>
|
||||
<p><i class="fa fa-fw fa-tags" aria-hidden="true"></i>
|
||||
{% for tag in game.tags.all %}
|
||||
|
@ -23,10 +23,56 @@
|
|||
{% endfor %}
|
||||
</p>
|
||||
<hr/>
|
||||
<p><i class="fa fa-fw fa-pencil" aria-hidden="true"></i> {{ game.game_designer|default:"(Game designer inconnu)" }}</li>
|
||||
<p><i class="fa fa-fw fa-wrench" aria-hidden="true"></i> {{ game.game_designer|default:"(Game designer inconnu·e)" }}</li>
|
||||
<p><i class="fa fa-fw fa-paint-brush" aria-hidden="true"></i> {{ game.illustrator|default:"(Illustrateur·trice inconnu·e)" }}</li>
|
||||
<p><i class="fa fa-fw fa-cogs" aria-hidden="true"></i> {{ game.editor|default:"(Éditeur inconnu)" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p id="description">{{ object.description }}</p>
|
||||
<h2 id="description">Description</h2>
|
||||
{{ object.description|linebreaks }}
|
||||
|
||||
{% if game.missing_elements %}
|
||||
<h2>Pièces manquantes</h2>
|
||||
<p class="warning">{{ game.missing_elements|linebreaksbr }}</p>
|
||||
{% endif %}
|
||||
|
||||
<h2>Commentaires et propositions de variantes</h2>
|
||||
<ul>
|
||||
{% for comment in game.comments.all %}
|
||||
{% if comment == edited_comment %}
|
||||
<li id="edited_comment">
|
||||
<form class="comment" method="post">
|
||||
{% csrf_token %}
|
||||
<textarea name="comment_text" required>{{ comment.text }}</textarea>
|
||||
<button type="submit"><i class="fa fa-pencil" aria-hidden="true"></i> Modifier mon commentaire</button>
|
||||
</form>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="comment">
|
||||
<div class="meta">
|
||||
<span class="author">{{ comment.author }}</span>
|
||||
<span class="date">posté le {{ comment.created_on|date }} à {{ comment.created_on|time }}{% if comment.created_on|date:"YmdHi" != comment.modified_on|date:"YmdHi" %}, dernière modification le {{ comment.modified_on|date }} à {{ comment.modified_on|time }}{% endif %}</span>
|
||||
{% if comment.author == request.user %}
|
||||
<a href="{% url "inventory:modify_game_comment" game.slug comment.id %}#edited_comment"><i class="fa fa-pencil" aria-hidden="true"></i></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{{ comment.text|linebreaks }}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
<li>(Aucun commentaire sur ce jeu)</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if not edited_comment %}
|
||||
{% if request.user.is_authenticated %}
|
||||
<form class="comment" method="post" action="{% url "inventory:add_game_comment" game.slug %}">
|
||||
{% csrf_token %}
|
||||
<textarea name="comment_text" placeholder="Ajouter un commentaire à propos de {{ game.title }}" required></textarea>
|
||||
<button type="submit"><i class="fa fa-paper-plane" aria-hidden="true"></i> Envoyer le commentaire</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<a href="{% url "gestiojeux_auth:login" %}?next={{ request.get_full_path }}">Connectez-vous</a> pour ajouter un commentaire.
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<li>
|
||||
<a href="{{ category.get_absolute_url }}"><i class="fa fa-bookmark" aria-hidden="true"></i> <span class="title">{{ category.name }}</span></a>
|
||||
</li>
|
|
@ -1,15 +1,18 @@
|
|||
<li>
|
||||
<a href="{{ game.get_absolute_url }}">
|
||||
{{game.title}}
|
||||
<span class="title">{{ game.title }}</span>
|
||||
<div class="details">
|
||||
<p><i class="fa fa-fw fa-users" aria-hidden="true"></i> {{ game.player_range }}</p>
|
||||
<p><i class="fa fa-fw fa-users" aria-hidden="true"></i> {{ game.get_player_range }}</p>
|
||||
<p><i class="fa fa-fw fa-clock-o" aria-hidden="true"></i> {{ game.duration }}
|
||||
<p><i class="fa fa-fw fa-bookmark"></i> {{ game.category }}</p>
|
||||
{% for tag in game.tags.all %}
|
||||
<p><i class="fa fa-fw fa-tag" aria-hidden="true"></i> {{ tag }}</p>
|
||||
{% endfor %}
|
||||
{% if game.game_designer %}
|
||||
<p><i class="fa fa-fw fa-pencil" aria-hidden="true"></i> {{ game.game_designer }}
|
||||
<p><i class="fa fa-fw fa-wrench" aria-hidden="true"></i> {{ game.game_designer }}</p>
|
||||
{% endif %}
|
||||
{% if game.illustrator %}
|
||||
<p><i class="fa fa-fw fa-paint-brush" aria-hidden="true"></i> {{ game.illustrator }}</p>
|
||||
{% endif %}
|
||||
{% if game.editor %}
|
||||
<p><i class="fa fa-fw fa-cogs" aria-hidden="true"></i> {{ game.editor }}</p>
|
||||
|
|
8
inventory/templates/inventory/partials/pagination.html
Normal file
8
inventory/templates/inventory/partials/pagination.html
Normal file
|
@ -0,0 +1,8 @@
|
|||
{% if page_obj.has_other_pages %}
|
||||
<div id="pagination">
|
||||
{% if page_obj.has_previous %}<a href="?q={{ query }}&page={{ page_obj.previous_page_number }}">{% endif %}<i class="fa fa-arrow-left" aria-hidden="true"></i> Précédent{% if page_obj.has_previous %}</a>{% endif %}
|
||||
| Page {{ page_obj.number }} sur {{ paginator.num_pages }} |
|
||||
{% if page_obj.has_next %}<a href="?q={{ query }}&page={{ page_obj.next_page_number }}">{% endif %}Suivant <i class="fa fa-arrow-right" aria-hidden="true"></i>{% if page_obj.has_next %}</a>{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
3
inventory/templates/inventory/partials/tag_item.html
Normal file
3
inventory/templates/inventory/partials/tag_item.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<li>
|
||||
<a href="{{ tag.get_absolute_url }}"><i class="fa fa-tag" aria-hidden="true"></i> <span class="title">{{ tag.name }}</span></a>
|
||||
</li>
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
{% block "content" %}
|
||||
<h1>Recherche</h1>
|
||||
<form class="search" method="get" action=".">
|
||||
<form class="search" method="get">
|
||||
{{ form.q }}
|
||||
<button type="submit"><i class="fa fa-fw fa-search" aria-hidden="true"></i></button>
|
||||
</form>
|
||||
|
@ -15,25 +15,15 @@
|
|||
{% if result.model_name == "game" %}
|
||||
{% include "./partials/game_item.html" with game=result.object %}
|
||||
{% elif result.model_name == "category" %}
|
||||
<li>
|
||||
<a href="{{ result.object.get_absolute_url }}"><i class="fa fa-bookmark" aria-hidden="true"></i> {{ result.object.name }}</a>
|
||||
</li>
|
||||
{% include "./partials/category_item.html" with category=result.object %}
|
||||
{% elif result.model_name == "tag" %}
|
||||
<li>
|
||||
<a href="{{ result.object.get_absolute_url }}"><i class="fa fa-tag" aria-hidden="true"></i> {{ result.object.name }}</a>
|
||||
</li>
|
||||
{% include "./partials/tag_item.html" with tag=result.object %}
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
<li>Aucun résultat trouvé</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% if page_obj.has_previous or page_obj.has_next %}
|
||||
<div>
|
||||
{% if page_obj.has_previous %}<a href="?q={{ query }}&page={{ page_obj.previous_page_number }}">{% endif %}« Précédent{% if page_obj.has_previous %}</a>{% endif %}
|
||||
|
|
||||
{% if page_obj.has_next %}<a href="?q={{ query }}&page={{ page_obj.next_page_number }}">{% endif %}Suivant »{% if page_obj.has_next %}</a>{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% include "./partials/pagination.html" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{{ object.title }}
|
||||
{{ object.editor }}
|
||||
{{ object.game_designer }}
|
||||
{{ object.illustrator }}
|
||||
{{ object.editor }}
|
||||
{{ object.description }}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
Il y a {{ tag_list|length }} tag{{ tag_list|pluralize }} dans la ludothèque :
|
||||
<ul>
|
||||
{% for tag in tag_list %}
|
||||
<li><a href="{{ tag.get_absolute_url }}"><i class="fa fa-tag" aria-hidden="true"></i> {{ tag.name }}</a></li>
|
||||
{% include "./partials/tag_item.html" %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
|
|
@ -7,6 +7,8 @@ from .views import (
|
|||
TagView,
|
||||
GameListView,
|
||||
GameView,
|
||||
AddGameCommentView,
|
||||
ModifyGameCommentView,
|
||||
InventorySearchView,
|
||||
)
|
||||
|
||||
|
@ -20,5 +22,13 @@ urlpatterns = [
|
|||
path("tag/<slug>/", TagView.as_view(), name="tag"),
|
||||
path("game/", GameListView.as_view(), name="game_list"),
|
||||
path("game/<slug>/", GameView.as_view(), name="game"),
|
||||
path(
|
||||
"game/<slug>/add_comment", AddGameCommentView.as_view(), name="add_game_comment"
|
||||
),
|
||||
path(
|
||||
"game/<slug>/modify_comment/<int:comment_id>",
|
||||
ModifyGameCommentView.as_view(),
|
||||
name="modify_game_comment",
|
||||
),
|
||||
path("search/", InventorySearchView.as_view(), name="search"),
|
||||
]
|
||||
|
|
|
@ -1,8 +1,20 @@
|
|||
from django.views.generic import TemplateView, ListView, DetailView
|
||||
from django.views.generic import (
|
||||
TemplateView,
|
||||
ListView,
|
||||
DetailView,
|
||||
RedirectView,
|
||||
)
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.urls import reverse
|
||||
from django.shortcuts import redirect, get_object_or_404
|
||||
from django.contrib import messages
|
||||
from django.http import Http404
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from haystack.generic_views import SearchView
|
||||
from haystack.forms import SearchForm
|
||||
from haystack.query import SearchQuerySet
|
||||
from .models import Category, Tag, Game
|
||||
from .models import Category, Tag, Game, GameComment
|
||||
|
||||
|
||||
class InventoryView(TemplateView):
|
||||
|
@ -45,3 +57,55 @@ class InventorySearchView(SearchView):
|
|||
|
||||
def get_queryset(self):
|
||||
return SearchQuerySet().models(Category, Tag, Game)
|
||||
|
||||
|
||||
class AddGameCommentView(LoginRequiredMixin, SingleObjectMixin, RedirectView):
|
||||
model = Game
|
||||
permanent = False
|
||||
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
req_dict = self.request.POST
|
||||
if "comment_text" in req_dict:
|
||||
comment_text = req_dict["comment_text"]
|
||||
|
||||
game = self.get_object()
|
||||
game.comments.create(author=self.request.user, text=comment_text)
|
||||
messages.success(self.request, "Commentaire ajouté")
|
||||
else:
|
||||
messages.error(
|
||||
self.request, "Pas de texte pour le commentaire dans la requête"
|
||||
)
|
||||
|
||||
return reverse("inventory:game", kwargs=kwargs)
|
||||
|
||||
|
||||
class ModifyGameCommentView(LoginRequiredMixin, SingleObjectMixin, TemplateView):
|
||||
model = Game
|
||||
template_name = "inventory/game.html"
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
comment_id = kwargs["comment_id"]
|
||||
self.object = self.get_object()
|
||||
self.comment = get_object_or_404(GameComment, id=comment_id)
|
||||
if self.comment.game != self.object:
|
||||
raise Http404()
|
||||
if self.comment.author != self.request.user:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(*args, **kwargs)
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
req_dict = self.request.POST
|
||||
if "comment_text" in req_dict:
|
||||
self.comment.text = req_dict["comment_text"]
|
||||
self.comment.save()
|
||||
messages.success(self.request, "Commentaire modifié")
|
||||
else:
|
||||
messages.error(
|
||||
self.request, "Pas de texte pour le commentaire dans la requête"
|
||||
)
|
||||
return redirect("inventory:game", slug=kwargs["slug"])
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["edited_comment"] = self.comment
|
||||
return context
|
||||
|
|
|
@ -26,7 +26,7 @@ form {
|
|||
color: $help_text_color;
|
||||
}
|
||||
|
||||
input {
|
||||
input, textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
font: inherit;
|
||||
|
@ -36,11 +36,13 @@ input {
|
|||
|
||||
input[type="text"],
|
||||
input[type="email"],
|
||||
input[type="password"], {
|
||||
input[type="password"],
|
||||
input[type="search"],
|
||||
textarea {
|
||||
background-color: white;
|
||||
border: solid 1px $help_text_color;
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
border-radius: 5px;
|
||||
box-shadow: none;
|
||||
|
||||
&:optional {
|
||||
|
@ -56,6 +58,13 @@ input[type="password"], {
|
|||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
font-family: $font_family;
|
||||
font-size: 1em;
|
||||
resize: vertical;
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
width: auto;
|
||||
|
@ -99,9 +108,26 @@ select {
|
|||
|
||||
form.search {
|
||||
flex-direction: row;
|
||||
gap: 10px;
|
||||
|
||||
input[type="search"] {
|
||||
border-radius: 5px 0 0 5px;
|
||||
border-right: 0;
|
||||
}
|
||||
button {
|
||||
margin: 0;
|
||||
border-radius: 0 10px 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
form.comment {
|
||||
font-size: 0.7em;
|
||||
textarea {
|
||||
border-radius: 10px 10px 0 0;
|
||||
border-bottom: none;
|
||||
margin: 0;
|
||||
}
|
||||
button {
|
||||
border-radius: 0 0 10px 10px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ header {
|
|||
margin: 0;
|
||||
padding: 0 20px;
|
||||
color: $header_text_color;
|
||||
font-size: $font_size;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
nav {
|
||||
|
@ -31,12 +31,11 @@ header {
|
|||
border-radius: 0;
|
||||
|
||||
color: $header_text_color;
|
||||
font-size: $nav_font_size;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
background-color: darken($header_bg_color, 10%);
|
||||
color: $page_link_hover_color;
|
||||
color: $page_link_color;
|
||||
}
|
||||
&.current {
|
||||
background-color: $header_border_color;
|
||||
|
@ -44,11 +43,11 @@ header {
|
|||
&:focus {
|
||||
background-color: darken($header_bg_color, 10%);
|
||||
box-shadow: none;
|
||||
color: $page_link_hover_color;
|
||||
color: $page_link_color;
|
||||
}
|
||||
}
|
||||
|
||||
.username {
|
||||
font-size: 12pt;
|
||||
font-size: 0.7em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
padding: 10px;
|
||||
border: 1px solid $border_color;
|
||||
background-color: $bg_color;
|
||||
color: $page_text_color;
|
||||
}
|
||||
@mixin error_box {
|
||||
@include box($error_box_color, $error_box_border_color);
|
||||
|
@ -23,6 +22,7 @@
|
|||
text-decoration: none;
|
||||
text-align: center;
|
||||
font-size: 100%;
|
||||
color: $page_text_color;
|
||||
|
||||
@include box(lighten($header_border_color, 40%), $header_border_color);
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
$page_bg_color: #f6fbfd;
|
||||
$page_text_color: #250f2d;
|
||||
$page_link_color: #2b153f;
|
||||
$page_link_hover_color: #180c23;
|
||||
$page_link_color: #1e464c;
|
||||
$page_width: 800px;
|
||||
$small_page_width: 500px;
|
||||
|
||||
|
@ -16,20 +15,18 @@ $header_bg_color: #6bb8c4;
|
|||
$header_text_color: #f6fbfd;
|
||||
$header_infos_font_family: "Kalam";
|
||||
$header_border_color: #51808c;
|
||||
$nav_font_size: 18pt;
|
||||
|
||||
$footer_bg_color: $header_bg_color;
|
||||
$footer_font_size: 12pt;
|
||||
|
||||
$indexbar_bg_color_1: rgba($header_bg_color, 0.75);
|
||||
$indexbar_bg_color_2: rgba($header_bg_color, 0.6);
|
||||
$indexbar_text_color: darken($page_link_color, 15);
|
||||
|
||||
$info_box_color: #c9c8ff;
|
||||
$info_box_color: #e0dfff;
|
||||
$info_box_border_color: darken($info_box_color, 20%);
|
||||
$error_box_color: #ffcddd;
|
||||
$error_box_color: #ffdfe9;
|
||||
$error_box_border_color: darken($error_box_color, 20%);
|
||||
$success_box_color: #a4ffc4;
|
||||
$success_box_border_color: darken($success_box_color, 40%);
|
||||
$warning_box_color: #ffd45d;
|
||||
$success_box_color: #ddffd8;
|
||||
$success_box_border_color: darken($success_box_color, 20%);
|
||||
$warning_box_color: #ffedbb;
|
||||
$warning_box_border_color: darken($warning_box_color, 20%);
|
||||
|
|
|
@ -50,7 +50,7 @@ main {
|
|||
|
||||
footer {
|
||||
background-color: $footer_bg_color;
|
||||
font-size: $footer_font_size;
|
||||
font-size: 0.7em;
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
}
|
||||
|
@ -69,13 +69,23 @@ h1 {
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.25em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
text-decoration: underline lighten($header_border_color, 40%);
|
||||
color: $page_link_color;
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover {
|
||||
color: $page_link_hover_color;
|
||||
text-decoration-color: $page_link_color;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,7 +116,7 @@ hr {
|
|||
|
||||
button, .btn_row a {
|
||||
@include button;
|
||||
margin: 10px 5px;
|
||||
margin: 10px 0;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
|
@ -277,25 +287,20 @@ iframe {
|
|||
}
|
||||
|
||||
ul {
|
||||
padding: 0 20px;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
li>a {
|
||||
li>a {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
padding: 15px;
|
||||
margin: 10px 5px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
border-color: $header_border_color;
|
||||
background-color: lighten($header_border_color, 70%);
|
||||
}
|
||||
&:focus {
|
||||
border-color: $header_border_color;
|
||||
background-color: lighten($header_border_color, 70%);
|
||||
box-shadow: 0 0 1.5px 1px $header_bg_color;
|
||||
.title {
|
||||
text-decoration: underline lighten($header_border_color, 40%);
|
||||
}
|
||||
|
||||
.details {
|
||||
|
@ -309,5 +314,35 @@ ul {
|
|||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: $header_border_color;
|
||||
background-color: white;
|
||||
|
||||
.title {
|
||||
text-decoration-color: currentColor;
|
||||
}
|
||||
}
|
||||
&:focus {
|
||||
border-color: $header_border_color;
|
||||
background-color: white;
|
||||
box-shadow: 0 0 1.5px 1px $header_bg_color;
|
||||
}
|
||||
}
|
||||
|
||||
li.comment {
|
||||
@include box(white, $indexbar_bg_color_1);
|
||||
margin: 1em 0;
|
||||
font-size: 0.7em;
|
||||
|
||||
.author {
|
||||
font-weight: bold;
|
||||
}
|
||||
.date {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0.5em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ header {
|
|||
margin: 0;
|
||||
padding: 0 20px;
|
||||
color: #f6fbfd;
|
||||
font-size: 16pt; }
|
||||
font-size: 1em; }
|
||||
header nav {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
|
@ -24,19 +24,18 @@ header {
|
|||
padding: 10px 20px;
|
||||
border-radius: 0;
|
||||
color: #f6fbfd;
|
||||
font-size: 18pt;
|
||||
text-decoration: none; }
|
||||
header a:hover {
|
||||
background-color: #48a6b4;
|
||||
color: #180c23; }
|
||||
color: #1e464c; }
|
||||
header a.current {
|
||||
background-color: #51808c; }
|
||||
header a:focus {
|
||||
background-color: #48a6b4;
|
||||
box-shadow: none;
|
||||
color: #180c23; }
|
||||
color: #1e464c; }
|
||||
header .username {
|
||||
font-size: 12pt; }
|
||||
font-size: 0.7em; }
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
|
@ -50,9 +49,8 @@ form {
|
|||
form .errorlist li {
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ff6798;
|
||||
background-color: #ffcddd;
|
||||
color: #250f2d;
|
||||
border: 1px solid #ff79a3;
|
||||
background-color: #ffdfe9;
|
||||
margin-bottom: 10px; }
|
||||
form p {
|
||||
margin: 5px 0;
|
||||
|
@ -62,7 +60,7 @@ form {
|
|||
font-size: 0.7em;
|
||||
color: rgba(37, 15, 45, 0.65); }
|
||||
|
||||
input {
|
||||
input, textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
font: inherit;
|
||||
|
@ -71,26 +69,40 @@ input {
|
|||
|
||||
input[type="text"],
|
||||
input[type="email"],
|
||||
input[type="password"] {
|
||||
input[type="password"],
|
||||
input[type="search"],
|
||||
textarea {
|
||||
background-color: white;
|
||||
border: solid 1px rgba(37, 15, 45, 0.65);
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
border-radius: 5px;
|
||||
box-shadow: none; }
|
||||
input[type="text"]:optional,
|
||||
input[type="email"]:optional,
|
||||
input[type="password"]:optional {
|
||||
input[type="password"]:optional,
|
||||
input[type="search"]:optional,
|
||||
textarea:optional {
|
||||
border-color: rgba(37, 15, 45, 0.4); }
|
||||
input[type="text"]:focus,
|
||||
input[type="email"]:focus,
|
||||
input[type="password"]:focus {
|
||||
input[type="password"]:focus,
|
||||
input[type="search"]:focus,
|
||||
textarea:focus {
|
||||
border-color: #6bb8c4;
|
||||
box-shadow: 0 0 1.5px 1px #6bb8c4; }
|
||||
input[type="text"]:-moz-ui-invalid,
|
||||
input[type="email"]:-moz-ui-invalid,
|
||||
input[type="password"]:-moz-ui-invalid {
|
||||
border-color: #ff6798;
|
||||
box-shadow: 0 0 1.5px 1px #ff6798; }
|
||||
input[type="password"]:-moz-ui-invalid,
|
||||
input[type="search"]:-moz-ui-invalid,
|
||||
textarea:-moz-ui-invalid {
|
||||
border-color: #ff79a3;
|
||||
box-shadow: 0 0 1.5px 1px #ff79a3; }
|
||||
|
||||
textarea {
|
||||
font-family: "Open Sans";
|
||||
font-size: 1em;
|
||||
resize: vertical;
|
||||
min-height: 120px; }
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
|
@ -102,11 +114,11 @@ input[type="submit"] {
|
|||
text-decoration: none;
|
||||
text-align: center;
|
||||
font-size: 100%;
|
||||
color: #250f2d;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #51808c;
|
||||
background-color: #c9dbe0;
|
||||
color: #250f2d; }
|
||||
background-color: #c9dbe0; }
|
||||
input[type="submit"]:hover {
|
||||
background-color: #a9c6cd; }
|
||||
input[type="submit"]:focus {
|
||||
|
@ -120,11 +132,11 @@ select {
|
|||
text-decoration: none;
|
||||
text-align: center;
|
||||
font-size: 100%;
|
||||
color: #250f2d;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #51808c;
|
||||
background-color: #c9dbe0;
|
||||
color: #250f2d;
|
||||
width: 100%;
|
||||
font-size: 0.9em;
|
||||
margin: 0;
|
||||
|
@ -149,12 +161,25 @@ select {
|
|||
|
||||
.error_field {
|
||||
border-radius: 10px;
|
||||
background-color: rgba(255, 205, 221, 0.4); }
|
||||
background-color: rgba(255, 223, 233, 0.4); }
|
||||
|
||||
form.search {
|
||||
flex-direction: row;
|
||||
gap: 10px; }
|
||||
flex-direction: row; }
|
||||
form.search input[type="search"] {
|
||||
border-radius: 5px 0 0 5px;
|
||||
border-right: 0; }
|
||||
form.search button {
|
||||
margin: 0;
|
||||
border-radius: 0 10px 10px 0; }
|
||||
|
||||
form.comment {
|
||||
font-size: 0.7em; }
|
||||
form.comment textarea {
|
||||
border-radius: 10px 10px 0 0;
|
||||
border-bottom: none;
|
||||
margin: 0; }
|
||||
form.comment button {
|
||||
border-radius: 0 0 10px 10px;
|
||||
margin: 0; }
|
||||
|
||||
html {
|
||||
|
@ -192,7 +217,7 @@ main {
|
|||
|
||||
footer {
|
||||
background-color: #6bb8c4;
|
||||
font-size: 12pt;
|
||||
font-size: 0.7em;
|
||||
text-align: center;
|
||||
padding: 10px; }
|
||||
|
||||
|
@ -207,16 +232,24 @@ h1 {
|
|||
font-size: 1.5em;
|
||||
font-weight: bold; }
|
||||
|
||||
h2 {
|
||||
font-size: 1.25em;
|
||||
font-weight: bold; }
|
||||
|
||||
h3 {
|
||||
font-size: 1em;
|
||||
font-weight: bold; }
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
color: #2b153f;
|
||||
text-decoration: underline #c9dbe0;
|
||||
color: #1e464c;
|
||||
border-radius: 3px; }
|
||||
a:hover {
|
||||
color: #180c23; }
|
||||
text-decoration-color: #1e464c; }
|
||||
|
||||
:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 1.5px 1px #2b153f; }
|
||||
box-shadow: 0 0 1.5px 1px #1e464c; }
|
||||
|
||||
::-moz-focus-inner {
|
||||
border: none; }
|
||||
|
@ -240,12 +273,12 @@ button, .btn_row a {
|
|||
text-decoration: none;
|
||||
text-align: center;
|
||||
font-size: 100%;
|
||||
color: #250f2d;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #51808c;
|
||||
background-color: #c9dbe0;
|
||||
color: #250f2d;
|
||||
margin: 10px 5px; }
|
||||
margin: 10px 0; }
|
||||
button:hover, .btn_row a:hover {
|
||||
background-color: #a9c6cd; }
|
||||
button:focus, .btn_row a:focus {
|
||||
|
@ -265,30 +298,26 @@ button, .btn_row a {
|
|||
.error {
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ff6798;
|
||||
background-color: #ffcddd;
|
||||
color: #250f2d; }
|
||||
border: 1px solid #ff79a3;
|
||||
background-color: #ffdfe9; }
|
||||
|
||||
.info {
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #6562ff;
|
||||
background-color: #c9c8ff;
|
||||
color: #250f2d; }
|
||||
border: 1px solid #7d79ff;
|
||||
background-color: #e0dfff; }
|
||||
|
||||
.warning {
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #f6b500;
|
||||
background-color: #ffd45d;
|
||||
color: #250f2d; }
|
||||
border: 1px solid #ffd255;
|
||||
background-color: #ffedbb; }
|
||||
|
||||
.success {
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #00d74c;
|
||||
background-color: #a4ffc4;
|
||||
color: #250f2d; }
|
||||
border: 1px solid #84ff72;
|
||||
background-color: #ddffd8; }
|
||||
|
||||
.tooltip {
|
||||
position: relative;
|
||||
|
@ -408,27 +437,46 @@ iframe {
|
|||
margin: 1ex; }
|
||||
|
||||
ul {
|
||||
padding: 0 20px;
|
||||
padding: 0;
|
||||
list-style-type: none; }
|
||||
ul li > a {
|
||||
|
||||
li > a {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
padding: 15px;
|
||||
margin: 10px 5px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid transparent; }
|
||||
ul li > a:hover {
|
||||
border-color: #51808c;
|
||||
background-color: white; }
|
||||
ul li > a:focus {
|
||||
border-color: #51808c;
|
||||
background-color: white;
|
||||
box-shadow: 0 0 1.5px 1px #6bb8c4; }
|
||||
ul li > a .details {
|
||||
border: 1px solid transparent;
|
||||
text-decoration: none; }
|
||||
li > a .title {
|
||||
text-decoration: underline #c9dbe0; }
|
||||
li > a .details {
|
||||
font-size: 0.7em;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 5px;
|
||||
gap: 5px 20px; }
|
||||
ul li > a .details p {
|
||||
li > a .details p {
|
||||
margin: 0; }
|
||||
li > a:hover {
|
||||
border-color: #51808c;
|
||||
background-color: white; }
|
||||
li > a:hover .title {
|
||||
text-decoration-color: currentColor; }
|
||||
li > a:focus {
|
||||
border-color: #51808c;
|
||||
background-color: white;
|
||||
box-shadow: 0 0 1.5px 1px #6bb8c4; }
|
||||
|
||||
li.comment {
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid rgba(107, 184, 196, 0.75);
|
||||
background-color: white;
|
||||
margin: 1em 0;
|
||||
font-size: 0.7em; }
|
||||
li.comment .author {
|
||||
font-weight: bold; }
|
||||
li.comment .date {
|
||||
font-size: 0.7em; }
|
||||
li.comment p {
|
||||
margin: 0.5em; }
|
||||
|
|
25
mainsite/static/js/gestiojeux.js
Normal file
25
mainsite/static/js/gestiojeux.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
const MOBILE_NAV_PAGE_SIZE = 475; // px
|
||||
const MOBILE_NAV_TOGGLE_TIME = 300; // msec
|
||||
const TEXTAREA_MIN_SIZE = 120; // px
|
||||
|
||||
function mobile_nav_toggle() {
|
||||
$("nav > a").slideToggle(MOBILE_NAV_TOGGLE_TIME);
|
||||
}
|
||||
|
||||
$(window).resize(function () {
|
||||
if(window.innerWidth > MOBILE_NAV_PAGE_SIZE) {
|
||||
$("nav > a").show(0);
|
||||
}
|
||||
else {
|
||||
$("nav > a").hide(0);
|
||||
}
|
||||
});
|
||||
|
||||
$('textarea').each(function () {
|
||||
this.style.height = Math.max(this.scrollHeight, TEXTAREA_MIN_SIZE) + 'px';
|
||||
this.style.resize = 'none';
|
||||
this.style.overflowY = 'hidden';
|
||||
}).on('input', function () {
|
||||
this.style.height = 'auto';
|
||||
this.style.height = Math.max(this.scrollHeight, TEXTAREA_MIN_SIZE) + 'px';
|
||||
});
|
|
@ -1,3 +1,5 @@
|
|||
{% load static %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
|
@ -17,7 +19,7 @@
|
|||
</main>
|
||||
|
||||
{% include "partials/footer.html" %}
|
||||
{% include "partials/base_js.html" %}
|
||||
<script src="{% static "js/gestiojeux.js" %}"></script>
|
||||
{% block "extra_foot" %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
<script>
|
||||
function mobile_nav_toggle() {
|
||||
$("nav > a").slideToggle(300);
|
||||
}
|
||||
|
||||
$(window).resize(function () {
|
||||
if(window.innerWidth > 475) {
|
||||
$("nav > a").show(0);
|
||||
}
|
||||
else {
|
||||
$("nav > a").hide(0);
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -4,5 +4,5 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GestioJeux</title>
|
||||
<link type="text/css" rel="stylesheet" href="{% static "css/style.css" %}" />
|
||||
<link rel="shortcut icon" type="image/png" href="{% static "img/favicon.png" %}"/>
|
||||
<link type="image/png" rel="shortcut icon" href="{% static "img/favicon.png" %}"/>
|
||||
<script src="{% static "js/jquery-3.4.1.min.js" %}"></script>
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
{% if request.user.is_authenticated %}
|
||||
<div class="username">{{ request.user.username }}</div>
|
||||
<a class="login" href="{% url "gestiojeux_auth:logout" %}?next={{ request.get_full_path }}"><i class="fa fa-sign-out" aria-hidden="true"></i></a>
|
||||
{% else %} <a class="login" href="{% url "gestiojeux_auth:login" %}?next={{ request.get_full_path }}">Connexion</a>
|
||||
{% else %}
|
||||
<a class="login{% if url_name == "login" %} current{% endif %}" href="{% url "gestiojeux_auth:login" %}?next={{ request.get_full_path }}">Connexion</a>
|
||||
{% endif %}
|
||||
{# <a class="login" href="">Logout</a> #}
|
||||
{% endwith %}
|
||||
</header>
|
||||
|
|
Loading…
Reference in a new issue