diff --git a/equipment/models.py b/equipment/models.py index 85d6284..b3e98c8 100644 --- a/equipment/models.py +++ b/equipment/models.py @@ -3,6 +3,7 @@ from django.core.exceptions import ValidationError from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import Group from event.models import Activity, EventSpecificMixin +from django.db.models import Q from .fields import IdField @@ -20,20 +21,30 @@ class EquipmentCategory(models.Model): blank=True, null=True, default=None, + related_name="children", help_text=_("merci de ne pas faire de référence cyclique"), + verbose_name=_("parent"), ) + def has_parent(self, cat): + current = self + for k in range(100): + if current is None: + return False + if current == cat: + return True + current = current.parent + + def full_name(self): - if self.parent is None: - return "-" current = self res = "" for k in range(100): - if current.parent is None: - break res = "/{current}{old}".format( current=current.name, old=res) + if current.parent is None: + break current = current.parent return res @@ -62,6 +73,14 @@ class EquipmentCategory(models.Model): return super().save(*args, **kwargs) +class EquipmentQuerySet(models.QuerySet): + def in_category(self, cat): + filtre = Q(id__lt=0) + childs_id = [ c.id for c in EquipmentCategory.objects.all() if c.has_parent(cat) ] + for pk in childs_id: + filtre |= Q(category__id=pk) + return self.filter(filtre) + class Equipment(EventSpecificMixin, models.Model): name = models.CharField( @@ -80,11 +99,13 @@ class Equipment(EventSpecificMixin, models.Model): ) owner = models.ForeignKey( Group, + verbose_name=_("propriétaire"), blank=True, null=True, ) category = models.ForeignKey( EquipmentCategory, + verbose_name=_("catégorie"), on_delete=models.PROTECT, ) @@ -96,8 +117,21 @@ class Equipment(EventSpecificMixin, models.Model): _("dernière modification"), auto_now=True, ) + + objects = EquipmentQuerySet.as_manager() + + def is_in_category(self, cat): + current = self.category + for k in range(100): + if current is None: + return False + if current == cat: + return True + current = current.parent def ids_aviable(self): + if self.stock is None: + return [] res = list(map(lambda x: x+1, range(self.stock))) for lost in self.losts.all(): res = [ x @@ -116,7 +150,8 @@ class Equipment(EventSpecificMixin, models.Model): return res def stock_aviable(self): - return len(self.ids_available()) + aviable = self.ids_aviable() + return len(aviable) def stock_lost(self): return len(self.ids_lost()) @@ -165,10 +200,12 @@ class EquipmentAttributeValue(models.Model): Equipment, on_delete=models.CASCADE, related_name="attributes", + verbose_name=_("matériel"), help_text=_("Matériel concerné par le defaut"), ) attribute = models.ForeignKey( EquipmentAttribute, + verbose_name=_("attribut"), on_delete=models.CASCADE, ) value = models.CharField( @@ -186,7 +223,7 @@ class EquipmentAttributeValue(models.Model): class EquipmentAttribution(models.Model): - equipment = models.ForeignKey(Equipment) + equipment = models.ForeignKey(Equipment, verbose_name=_("matériel")) activity = models.ForeignKey(Activity) amount = models.BigIntegerField(_("quantité attribuée")) remarks = models.TextField(_("remarques concernant l'attribution")) @@ -211,6 +248,7 @@ class EquipmentDefault(models.Model): remark = models.TextField(_("remarque sur le défaut")) equipment = models.ForeignKey( Equipment, + verbose_name=_("matériel"), on_delete=models.CASCADE, related_name="remarks", help_text=_("Matériel concerné par le defaut"), @@ -235,6 +273,7 @@ class EquipmentLost(models.Model): ) equipment = models.ForeignKey( Equipment, + verbose_name=_("matériel"), on_delete=models.CASCADE, related_name="losts", help_text=_("Matériel concerné par la perte"), @@ -249,6 +288,7 @@ class EquipmentRevision(models.Model): ) equipment = models.ForeignKey( Equipment, + verbose_name=_("matériel"), on_delete=models.CASCADE, related_name="revisions", help_text=_("Matériel concerné par les révisions"), diff --git a/equipment/tables.py b/equipment/tables.py new file mode 100644 index 0000000..a14d907 --- /dev/null +++ b/equipment/tables.py @@ -0,0 +1,108 @@ +from django.utils.translation import ugettext_lazy as _ +from django.contrib.auth.models import Group +from django.db.models import Q +from django.http.request import QueryDict + +import django_filters +from django_filters.widgets import LinkWidget +from django_tables2.utils import A +import django_tables2 as tables + +from .models import Equipment, EquipmentCategory + + +class EquipmentFilter(django_filters.FilterSet): + owner = django_filters.ModelChoiceFilter( + field_name='owner', + queryset=Group.objects.all(), + widget=LinkWidget(), + ) + category = django_filters.ModelChoiceFilter( + field_name='category', + queryset=EquipmentCategory.objects.all(), + widget=LinkWidget(), + method='filter_category', + ) + + def filter_category(self, queryset, name, value): + return queryset.in_category(value) + + def get_categories(self, qs): + """ + rend les catégories qui servent à filtrer les Equipments de qs + ie les catégories des equipments et tous leurs parents + """ + filtre = Q(id__lt=0) + for eq in qs: + current = eq.category + for k in range(100): + if current is None: + break + filtre |= Q(id=current.id) + current = current.parent + return EquipmentCategory.objects.filter(filtre) + + def __init__(self, data=None, queryset=None, *, request=None, prefix=None): + # On que les requêtes vides rendent quelque chose + if data is None: + data = QueryDict('category&owner') + super().__init__(data=data, queryset=queryset, + request=request, prefix=prefix) + if self.queryset is not None: + for filter_ in self.filters.values(): + if filter_.queryset.model == Group: + own_ids = [eq.owner.id for eq in self.queryset] + filtre = Q(id__lt=0) + for own_id in own_ids: + filtre |= Q(id=own_id) + filter_.queryset = Group.objects.filter(filtre) + if filter_.queryset.model == EquipmentCategory: + filter_.queryset = self.get_categories(self.queryset) + + class Meta: + model = Equipment + fields = ['category', 'owner'] + + +class AbstractEquipmentTable(tables.Table): + stock_aviable_p = tables.Column( + accessor=A('stock_aviable_p'), + orderable=False, # TODO le rendre ordorable + verbose_name=_("Quantité disponible"), + ) + full_category_p = tables.Column( + accessor=A('full_category_p'), + order_by=('category'), + verbose_name=_("Catégorie"), + ) + name = tables.LinkColumn( + 'equipment:detail', + args=[A('pk')], + verbose_name=_("Matériel"), + ) + admin = tables.LinkColumn( + 'admin:equipment_equipment_change', + attrs={ + 'a': {'class': 'glyphicon glyphicon-cog'} + }, + text="", + orderable=False, + args=[A('pk')], + verbose_name=_(""), + ) + + def before_render(self, request): + if (request.user.is_staff and + request.user.has_perm('equipment_change_equipment')): + self.columns.show('admin') + else: + self.columns.hide('admin') + + +class EquipmentTable(AbstractEquipmentTable): + class Meta: + model = Equipment + template_name = 'equipment/tables/bootstrap-responsive.html' + fields = ['name', 'stock', 'owner', ] + sequence = ['admin', 'name', 'stock', 'stock_aviable_p', + 'full_category_p', 'owner', ] diff --git a/equipment/templates/equipment/detail.html b/equipment/templates/equipment/detail.html new file mode 100644 index 0000000..817739f --- /dev/null +++ b/equipment/templates/equipment/detail.html @@ -0,0 +1,13 @@ +{% extends "shared/base.html" %} +{% load i18n staticfiles %} + +{% block title %}{% trans "Matériel" %}{% endblock %} + +{% block content %} +

{{ equipment.name }}

+ +{% endblock %} + +{% block aside %} + Coucou :) +{% endblock %} diff --git a/equipment/templates/equipment/home.html b/equipment/templates/equipment/home.html new file mode 100644 index 0000000..648ee69 --- /dev/null +++ b/equipment/templates/equipment/home.html @@ -0,0 +1,44 @@ +{% extends "shared/base.html" %} +{% load i18n staticfiles %} + +{% block title %}{% trans "Matériel" %}{% endblock %} + +{% block content %} +

{% trans "Inventaire" %}

+ + + {% trans "Tout le matériel" %} + +

{% trans "Liste par Propriétaire" %}

+
+ {% for owner in owners %} + + + {{ owner.name }} + + {% endfor %} +
+

{% trans "Liste par Catégorie" %}

+
+ +
+{% endblock %} + +{% block aside %} +
+ {{ nb_type }} {% trans "référence" %}{{ nb_type|pluralize}} +
+
+ {{ stock }} {% trans "item" %}{{ stock|pluralize}} +
+
+ {{ categories.count }} {% trans "catégorie" %}{{ categories.count|pluralize}} +
+
+ {{ owners.count }} {% trans "propriéaire" %}{{ owners.count|pluralize}} +
+{% endblock %} diff --git a/equipment/templates/equipment/list.html b/equipment/templates/equipment/list.html new file mode 100644 index 0000000..1091304 --- /dev/null +++ b/equipment/templates/equipment/list.html @@ -0,0 +1,30 @@ +{% extends "shared/base.html" %} +{% load render_table from django_tables2 %} +{% load bootstrap3 %} +{% load i18n staticfiles %} + +{% block title %}{% trans "Matériel" %}{% endblock %} + +{% block content %} +

Inventaire

+ {% if subtitle %} +

{{ subtitle }}

+ {% endif %} + {% render_table table %} +{% endblock %} + +{% block aside %} +
+ {{ nb_type }} {% trans "référence" %}{{ nb_type|pluralize}} +
+
+ {{ stock }} {% trans "item" %}{{ stock|pluralize}} +
+ {% if filter %} +
+
+ {% bootstrap_form filter.form layout='horizontal' size='lg' %} +
+
+ {% endif %} +{% endblock %} diff --git a/equipment/templates/equipment/tables/bootstrap-responsive.html b/equipment/templates/equipment/tables/bootstrap-responsive.html new file mode 100644 index 0000000..4b17c05 --- /dev/null +++ b/equipment/templates/equipment/tables/bootstrap-responsive.html @@ -0,0 +1,16 @@ +{% extends 'equipment/tables/bootstrap.html' %} + +{% block table-wrapper %} +
+ {% block table %} + {{ block.super }} + {% endblock table %} + + {% if table.page and table.paginator.num_pages > 1 %} + {% block pagination %} + {{ block.super }} + {% endblock pagination %} + {% endif %} +
+{% endblock table-wrapper %} + diff --git a/equipment/templates/equipment/tables/bootstrap.html b/equipment/templates/equipment/tables/bootstrap.html new file mode 100644 index 0000000..87f25e6 --- /dev/null +++ b/equipment/templates/equipment/tables/bootstrap.html @@ -0,0 +1,103 @@ +{% load django_tables2 %} +{% load i18n %} +{% block table-wrapper %} +
+ {% block table %} + + {% block table.thead %} + {% if table.show_header %} + + + {% for column in table.columns %} + + {% endfor %} + + + {% endif %} + {% endblock table.thead %} + {% block table.tbody %} + + {% for row in table.paginated_rows %} + {% block table.tbody.row %} + + {% for column, cell in row.items %} + + {% endfor %} + + {% endblock table.tbody.row %} + {% empty %} + {% if table.empty_text %} + {% block table.tbody.empty_text %} + + {% endblock table.tbody.empty_text %} + {% endif %} + {% endfor %} + + {% endblock table.tbody %} + {% block table.tfoot %} + {% if table.has_footer %} + + + {% for column in table.columns %} + + {% endfor %} + + + {% endif %} + {% endblock table.tfoot %} +
+ {% if column.orderable %} + {{ column.header }} + {% else %} + {{ column.header }} + {% endif %} +
{% if column.localize == None %}{{ cell }}{% else %}{% if column.localize %}{{ cell|localize }}{% else %}{{ cell|unlocalize }}{% endif %}{% endif %}
{{ table.empty_text }}
{{ column.footer }}
+ {% endblock table %} + + {% if table.page and table.paginator.num_pages > 1 %} + {% block pagination %} + + {% endblock pagination %} + {% endif %} +
+{% endblock table-wrapper %} + diff --git a/equipment/templates/equipment/tree_cat.html b/equipment/templates/equipment/tree_cat.html new file mode 100644 index 0000000..02201c4 --- /dev/null +++ b/equipment/templates/equipment/tree_cat.html @@ -0,0 +1,11 @@ +
  • {{node.name}} + {%if node.children %} + + {%endif%} +
  • diff --git a/equipment/urls.py b/equipment/urls.py new file mode 100644 index 0000000..b990186 --- /dev/null +++ b/equipment/urls.py @@ -0,0 +1,11 @@ +from django.conf.urls import url +from .views import EquipmentList, EquipmentView, EquipmentListByCategory, EquipmentListByOwner, EquipmentHome + +app_name = 'equipment' +urlpatterns = [ + url(r'^$', EquipmentHome.as_view(), name='home'), + url(r'^all/$', EquipmentList.as_view(), name='list'), + url(r'^(?P[0-9]+)/$', EquipmentView.as_view(), name='detail'), + url(r'^c/(?P[0-9]+)/$', EquipmentListByCategory.as_view(), name='list_by_category'), + url(r'^o/(?P[0-9]+)/$', EquipmentListByOwner.as_view(), name='list_by_owner'), +] diff --git a/equipment/views.py b/equipment/views.py new file mode 100644 index 0000000..f4e83e2 --- /dev/null +++ b/equipment/views.py @@ -0,0 +1,97 @@ +from .models import Equipment, EquipmentCategory +from django.contrib.auth.models import Group +from django.db.models import Sum +from django.views.generic import DetailView, ListView +from django.contrib.auth.mixins import LoginRequiredMixin + +from django_filters.views import FilterView +from django_tables2.views import SingleTableMixin + +from .tables import EquipmentTable, EquipmentFilter + + +class EquipmentHome(LoginRequiredMixin, ListView): + template_name = 'equipment/home.html' + context_object_name = 'categories' + model = EquipmentCategory + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + # TODO remplacer par les vrais owners + context['owners'] = Group.objects.all() + categories = (EquipmentCategory.objects.order_by('name') + .prefetch_related('children')) + context['root_cat'] = categories.filter(parent=None) + queryset = Equipment.objects.all() + context['stock'] = queryset.aggregate(Sum('stock'))['stock__sum'] + context['nb_type'] = queryset.count() + return context + + +class EquipmentListAbstract(LoginRequiredMixin, SingleTableMixin,FilterView): + table_class = EquipmentTable + filterset_class = EquipmentFilter + template_name = 'equipment/list.html' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['stock'] = self.queryset.aggregate(Sum('stock'))['stock__sum'] + context['nb_type'] = self.queryset.count() + return context + + +class EquipmentList(EquipmentListAbstract): + def get_queryset(self): + self.queryset = Equipment.objects.all() + return self.queryset + + +class EquipmentListByCategory(EquipmentListAbstract): + def get_category(self): + try: + pk = self.kwargs.get('pk') + except KeyError: + raise AttributeError( + "View %s must be called with an object " + "pk in the URLconf." % self.__class__.__name__ + ) + return EquipmentCategory.objects.get(id=pk) + + def get_queryset(self): + cat = self.get_category() + self.queryset = Equipment.objects.all().in_category(cat) + return self.queryset + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + cat = self.get_category() + context['subtitle'] = "Dans {cat}".format(cat=cat.full_name()) + return context + + +class EquipmentListByOwner(EquipmentListAbstract): + def get_owner(self): + try: + pk = self.kwargs.get('pk') + except KeyError: + raise AttributeError( + "View %s must be called with an object " + "pk in the URLconf." % self.__class__.__name__ + ) + return Group.objects.get(id=pk) + + def get_queryset(self): + owner = self.get_owner() + self.queryset = Equipment.objects.filter(owner=owner) + return self.queryset + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + owner = self.get_owner() + context['subtitle'] = "Matériel de {owner}".format(owner=owner) + return context + + +class EquipmentView(DetailView): + model = Equipment + template_name = 'equipment/detail.html' diff --git a/evenementiel/settings/common.py b/evenementiel/settings/common.py index 0557b75..6b1cff6 100644 --- a/evenementiel/settings/common.py +++ b/evenementiel/settings/common.py @@ -60,6 +60,9 @@ INSTALLED_APPS = [ 'bootstrapform', 'widget_tweaks', 'taggit', + 'django_tables2', + 'django_filters', + 'bootstrap3', 'allauth_ens', 'allauth', @@ -189,8 +192,8 @@ CAS_EMAIL_FORMAT = "%s@clipper.ens.fr" CAS_FORCE_CHANGE_USERNAME_CASE = "lower" CAS_VERSION = 'CAS_2_SAML_1_0' -LOGIN_URL = reverse_lazy('users:login') -LOGOUT_URL = reverse_lazy('users:logout') +LOGIN_URL = reverse_lazy('account_login') +LOGOUT_URL = reverse_lazy('account_logout') LOGIN_REDIRECT_URL = reverse_lazy('shared:home') ACCOUNT_HOME_URL = reverse_lazy('shared:home') ACCOUNT_DETAILS_URL = reverse_lazy('shared:home') diff --git a/evenementiel/urls.py b/evenementiel/urls.py index 0416f5e..c0bf9ac 100644 --- a/evenementiel/urls.py +++ b/evenementiel/urls.py @@ -18,6 +18,7 @@ urlpatterns = [ # Admin url(r'^admin/', admin_site.urls), # Apps + url(r'^equipment/', include('equipment.urls')), url(r'^event/', include('event.urls')), url(r'^user/', include('users.urls')), # REST diff --git a/requirements.txt b/requirements.txt index 9740dbd..441bf48 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,12 @@ asgi-redis==1.3.0 asgiref==1.1.1 +django-bootstrap3==10.0.1 channels==1.1.5 Django==1.11.11 django-allauth==0.36.0 django-allauth-cas==1.0.0b2 +django-tables2==2.0.0a2 +django-filter==2.0.0 #git+https://git.eleves.ens.fr/cof-geek/django-allauth-ens@6e77b31e0dfed7659776d git+https://git.eleves.ens.fr/cof-geek/django-allauth-ens@30a072b7db1fc2d4652284227a3e7e876b14c915 django-bootstrap-form==3.2.1 diff --git a/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/forms.scssc b/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/forms.scssc new file mode 100644 index 0000000..d702d1a Binary files /dev/null and b/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/forms.scssc differ diff --git a/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/global.scssc b/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/global.scssc new file mode 100644 index 0000000..673ddae Binary files /dev/null and b/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/global.scssc differ diff --git a/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/header.scssc b/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/header.scssc new file mode 100644 index 0000000..5238fc3 Binary files /dev/null and b/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/header.scssc differ diff --git a/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/messages.scssc b/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/messages.scssc new file mode 100644 index 0000000..7288cfe Binary files /dev/null and b/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/messages.scssc differ diff --git a/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/tree.scssc b/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/tree.scssc new file mode 100644 index 0000000..70fb4d3 Binary files /dev/null and b/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/tree.scssc differ diff --git a/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/variables.scssc b/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/variables.scssc new file mode 100644 index 0000000..0113027 Binary files /dev/null and b/shared/static/css/.sass-cache/702601a8b7490c5ef78bf7afc3c3f2736c608d56/variables.scssc differ diff --git a/shared/static/css/forms.scss b/shared/static/css/forms.scss index ab179d7..46b973a 100644 --- a/shared/static/css/forms.scss +++ b/shared/static/css/forms.scss @@ -108,3 +108,14 @@ @include button-variant-2modes($btn-font-color, $btn-bg-base, $btn-bg-special, $btn-border); } +form#filter_form { + .form-group { + padding-right:20px; + } + + ul.form-control { + background-color: transparent; + border: none; + box-shadow: none; + } +} diff --git a/shared/static/css/global.css b/shared/static/css/global.css index 734d56f..2519bd7 100644 --- a/shared/static/css/global.css +++ b/shared/static/css/global.css @@ -158,17 +158,49 @@ color: #FF6969; background-color: white; } +form#filter_form .form-group { + padding-right: 20px; } +form#filter_form ul.form-control { + background-color: transparent; + border: none; + box-shadow: none; } + +.tree { + font-size: large; } + .tree ul, .tree li { + position: relative; } + .tree ul { + list-style: none; + padding-left: 32px; } + .tree li::before, + .tree li::after { + content: ""; + position: absolute; + left: -12px; } + .tree li::before { + border-top: 3px solid #FFC282; + top: 9px; + width: 8px; + height: 0; } + .tree li::after { + border-left: 3px solid #FFC282; + height: 100%; + width: 0px; + top: 2px; } + .tree ul > li:last-child::after { + height: 8px; } + /* MISE EN FORME GÉNÉRALE */ html { height: 100%; - background-color: #FFF5EB; } + background-color: #DCEAED; } body { font-family: "Saira Semi Condensed", sans-serif; font-size: medium; } #principal { - background-color: #FFF5EB; } + background-color: #DCEAED; } /*MAIN*/ main { @@ -182,13 +214,13 @@ main { main h1 { border-bottom: 7px solid #FFB363; padding-bottom: 5px; - font-family: "Saira", sans-serif; + font-family: "Capriola", sans-serif; font-weight: 600; } main h2 { border-bottom: 2px solid #FF6969; color: #FF6969; padding-bottom: 5px; - font-family: "Saira", sans-serif; + font-family: "Capriola", sans-serif; font-weight: 600; } /*ASIDE*/ @@ -196,7 +228,7 @@ aside { background-color: #FFC282; color: white; margin-top: 0px; - padding: 15px; } + padding: 0px !important; } aside a { color: #FF9191; } aside a:hover, aside a:active, aside a:focus { @@ -204,6 +236,30 @@ aside { aside code { color: white; background-color: #FFB363; } + aside .heading { + padding: 8px 15px; + font-size: 32px; + line-height: 1.3; + text-align: center; } + aside .heading.inverted { + background-color: #FFF5EB; + color: black; } + aside .heading.small { + font-size: 25px; } + aside .heading.small .sub { + font-size: 0.7em; + font-weight: normal; } + aside .heading .sub { + font-size: 0.7em; + font-weight: normal; } + aside .heading.separator { + border-bottom-color: #FF9191; + border-bottom-style: solid; } + aside .text { + padding: 15px; } + aside .text.inverted { + background-color: #FFF5EB; + color: black; } @media (min-width: 768px) { main { @@ -224,6 +280,25 @@ div.tag-list { code { font-size: small; } +.module-list { + display: flex; + align-items: stretch; + flex-wrap: wrap; } + +a.module { + background-color: #FFB363; + color: #FFF5EB; + padding: 20px 40px; + margin: 5px; + border-bottom-color: #FF9191; + border-bottom-style: solid; + font-size: large; + display: block; } + a.module:hover, a.module:active, a.module:focus { + color: #FFF5EB; + background-color: #FFC282; + text-decoration: none; } + /* COULD BE USERFULL LATER .row-eq-height { diff --git a/shared/static/css/global.css.map b/shared/static/css/global.css.map index ef1f5dc..108d068 100644 --- a/shared/static/css/global.css.map +++ b/shared/static/css/global.css.map @@ -1,7 +1,7 @@ { "version": 3, -"mappings": "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", -"sources": ["global.scss","variables.scss","messages.scss","header.scss","forms.scss"], +"mappings": ";AAAA;iBACiB;ACDjB,YAAY;AAoBZ,WAAW;ACpBX,aAAc;EACV,KAAK,EAAa,OAAO;EACzB,gBAAgB,EAAE,OAAO;EACzB,YAAY,EAAM,OAAO;;AAE7B,gBAAiB;EACb,KAAK,EAAa,OAAO;EACzB,gBAAgB,EAAE,OAAO;EACzB,YAAY,EAAM,OAAO;;AAE7B,gBAAiB;EACb,KAAK,EAAa,OAAO;EACzB,gBAAgB,EAAE,OAAO;EACzB,YAAY,EAAM,OAAO;;AAE7B,cAAe;EACX,KAAK,EAAa,OAAO;EACzB,gBAAgB,EAAE,OAAO;EACzB,YAAY,EAAM,OAAO;;AAE7B,MAAO;EACH,aAAa,EAAE,CAAC;;ACrBpB,YAAY;AAEZ,cAAe;EACb,WAAW,EAAS,IAAI;EACxB,cAAc,EAAM,IAAI;EACxB,gBAAgB,EFYL,OAAgB;EEX3B,KAAK,EFDa,OAAO;;AEK3B,eAAgB;EACd,gBAAgB,EFML,OAAgB;EEL3B,gBAAgB,EAAG,WAAW;EAC9B,YAAY,EAAM,IAAI;EAEhB,qIAEoB;IAChB,KAAK,EAAE,IAAI;IACX,gBAAgB,EFHX,OAAgB;;AEQjC,gBAAiB;EACb,UAAU,EAAE,qBAAsB;EAClC,OAAO,EAAG,GAAG;EAEb,iBAAiB;EACjB,gBAAgB,EFbH,OAAgB;EEc7B,YAAY,EAAE,IAAI;EAClB,WAAW,EAAE,KAAK;EAClB,YAAY,EAAE,KAAK;EAEnB,yBAA0B;IAV9B,gBAAiB;MAWT,gBAAgB,EAAI,WAAW;MAC/B,YAAY,EAAE,GAAG;MACjB,WAAW,EAAE,GAAG;MAChB,YAAY,EAAE,GAAG;;AAKzB,WAAY;EACR,KAAK,EAAE,IAAI;EACX,yBAA0B;IAF9B,WAAY;MAGJ,KAAK,EAAG,KAAK;MACb,KAAK,EAAE,IAAI;;AAInB,eAAgB;EACZ,WAAW;EAWX,WAAW;EAYX,WAAW;EArBP,uGAEQ;IACJ,KAAK,EAAE,KAAK;IACZ,WAAW,EFrCX,0BAA0B;IEsC1B,SAAS,EAAE,QAAQ;IACnB,aAAa,EAAE,iBAA0B;EAK7C,0GAEQ;IACJ,gBAAgB,EF/DR,OAAO;IEgEf,YAAY,EFhEJ,OAAO;EEkEnB,wCAAU;IACN,gBAAgB,EFjEP,OAAO;EEuEhB,4HAEQ;IACJ,WAAW,EF3DjB,oBAAoB;IE4Dd,SAAS,EAAE,KAAK;IAChB,KAAK,EF9ED,OAAO;IE+EX,UAAU,EAAE,WAAW;IACvB,yBAA0B;MAP9B,4HAEQ;QAMA,KAAK,EF/EJ,OAAO;;AGmG5B,YAAa;EA3CT;;;;;;;;;;;;;;;;;;;KAmBG;EACH,KAAK,EHrEQ,KAAK;EGsElB,gBAAgB,EHnEP,OAAgB;EGoEzB,YAAY,EHpEH,OAAgB;EGWzB;;;;;;;;;;;;;;;;;;;;KAoBG;EAxCH,0DAEQ;IA8EJ,KAAK,EH1EI,KAAK;IG2Ed,gBAAgB,EHzEP,OAAgB;IG0EzB,YAAY,EHzEP,OAAgB;EGhBzB,wCACS;IAsFL,KAAK,EH1EI,KAAK;IG2Ed,gBAAgB,EHzEP,OAAgB;IG0EzB,YAAY,EHzEP,OAAgB;IGTzB,gKAEQ;MA8EJ,KAAK,EH1EI,KAAK;MG2Ed,gBAAgB,EHzEP,OAAgB;MG0EzB,YAAY,EHzEP,OAAgB;EGOzB,oCAA0B;IAgEtB,KAAK,EH1EI,KAAK;IG2Ed,gBAAgB,EHzEP,OAAgB;IG0EzB,YAAY,EHzEP,OAAgB;IGTzB,kIAEQ;MA8EJ,KAAK,EH1EI,KAAK;MG2Ed,gBAAgB,EHzEP,OAAgB;MG0EzB,YAAY,EHzEP,OAAgB;EGTzB,oSAEQ;IAqFA,gBAAgB,EH9Ef,OAAgB;IG+EjB,YAAY,EH/EX,OAAgB;EGmFzB,mBAAO;IACH,KAAK,EHpFA,OAAgB;IGqFrB,gBAAgB,EHxFP,KAAK;;AGiGlB,4BAAY;EACR,aAAa,EAAC,IAAI;AAGtB,gCAAgB;EACZ,gBAAgB,EAAE,WAAW;EAC7B,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,IAAI;;ACtHxB,KAAM;EACF,SAAS,EAAC,KAAK;EACf,kBAAO;IACH,QAAQ,EAAE,QAAQ;EAGtB,QAAG;IACC,UAAU,EAAE,IAAI;IAChB,YAAY,EAAE,IAAI;EAGtB;iBACU;IACN,OAAO,EAAE,EAAE;IACX,QAAQ,EAAE,QAAQ;IAClB,IAAI,EAAE,KAAK;EAEf,gBAAW;IACP,UAAU,EAAE,iBAA4B;IACxC,GAAG,EAAE,GAAG;IACR,KAAK,EAAE,GAAG;IACV,MAAM,EAAE,CAAC;EAEb,eAAU;IACN,WAAW,EAAE,iBAA4B;IACzC,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,GAAG;IACV,GAAG,EAAE,GAAG;EAEZ,+BAA0B;IACtB,MAAM,EAAE,GAAG;;ALtBnB,4BAA4B;AAC5B,IAAK;EACD,MAAM,EAAI,IAAI;EACd,gBAAgB,ECAA,OAAO;;ADG3B,IAAK;EACD,WAAW,ECSF,kCAAkC;EDR3C,SAAS,EAAE,MAAM;;AAGrB,UAAW;EACP,gBAAgB,ECTA,OAAO;;ADY3B,QAAQ;AACR,IAAK;EACD,gBAAgB,EAAC,KAAK;EACtB,UAAU,EAAC,GAAG;EACd,OAAO,EAAE,IAAI;EAEb,MAAE;IACE,KAAK,ECbA,OAAgB;IDerB,yCAEQ;MACJ,KAAK,EClBJ,OAAgB;EDqBzB,OAAG;IACC,aAAa,EAAK,iBAA4B;IAC9C,cAAc,EAAI,GAAG;IACrB,WAAW,EClBR,sBAAsB;IDmBzB,WAAW,EAAE,GAAG;EAEpB,OAAG;IACC,aAAa,EAAK,iBAA0B;IAC5C,KAAK,EC7BA,OAAgB;ID8BrB,cAAc,EAAI,GAAG;IACrB,WAAW,ECzBR,sBAAsB;ID0BzB,WAAW,EAAE,GAAG;;AAIxB,SAAS;AACT,KAAM;EACF,gBAAgB,ECrCF,OAAkB;EDsChC,KAAK,EAAE,KAAK;EACZ,UAAU,EAAC,GAAG;EACd,OAAO,EAAE,cAAa;EAEtB,OAAE;IACE,KAAK,EC7CI,OAAgB;ID+CzB,4CAEQ;MACJ,KAAK,EClDA,OAAgB;EDqD7B,UAAK;IACD,KAAK,EAAE,KAAK;IACZ,gBAAgB,EClEJ,OAAO;EDoEvB,cAAS;IACL,OAAO,EAAE,QAAQ;IACxB,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,GAAG;IACT,UAAU,EAAC,MAAM;IAEjB,uBAAW;MACP,gBAAgB,ECzEP,OAAO;MD0EhB,KAAK,EAAC,KAAK;IAGf,oBAAQ;MACJ,SAAS,EAAE,IAAI;MAEf,yBAAK;QACD,SAAS,EAAE,KAAK;QAChB,WAAW,EAAE,MAAM;IAI3B,mBAAK;MACD,SAAS,EAAE,KAAK;MAChB,WAAW,EAAE,MAAM;IAGvB,wBAAY;MACR,mBAAmB,ECnFd,OAAgB;MDoFrB,mBAAmB,EAAE,KAAK;EAGlC,WAAM;IACF,OAAO,EAAE,IAAI;IAEb,oBAAW;MACP,gBAAgB,ECpGP,OAAO;MDqGhB,KAAK,EAAC,KAAK;;AAMvB,yBAA0B;EACtB,IAAK;IACD,UAAU,EAAC,IAAI;;EAEnB,KAAM;IACF,UAAU,EAAC,IAAI;AAIvB,EAAG;EACD,UAAU,EAAG,iBAA6B;;AAI5C,SAAU;EACN,YAAY,EAAE,GAAG;EACjB,aAAa,EAAE,GAAG;;AAGtB,YAAa;EACT,UAAU,EAAE,IAAI;;AAGpB,IAAK;EACD,SAAS,EAAE,KAAK;;AAGpB,YAAa;EACT,OAAO,EAAE,IAAI;EACb,WAAW,EAAE,OAAO;EACpB,SAAS,EAAE,IAAI;;AAGnB,QAAS;EACL,gBAAgB,EC/IA,OAAO;EDgJvB,KAAK,EC9IY,OAAO;ED+IxB,OAAO,EAAE,SAAS;EAClB,MAAM,EAAE,GAAG;EACX,mBAAmB,ECxIN,OAAgB;EDyI7B,mBAAmB,EAAE,KAAK;EAC1B,SAAS,EAAE,KAAK;EAChB,OAAO,EAAE,KAAK;EAEd,+CAEQ;IACJ,KAAK,ECzJQ,OAAO;ID0JpB,gBAAgB,EC/IN,OAAkB;IDgJ5B,eAAe,EAAE,IAAI;;AAI7B;;;;;;;;EAQE", +"sources": ["global.scss","variables.scss","messages.scss","header.scss","forms.scss","tree.scss"], "names": [], "file": "global.css" } diff --git a/shared/static/css/global.scss b/shared/static/css/global.scss index 6a92abc..970add1 100644 --- a/shared/static/css/global.scss +++ b/shared/static/css/global.scss @@ -4,11 +4,12 @@ @import 'messages'; @import 'header'; @import 'forms'; +@import 'tree'; /* MISE EN FORME GÉNÉRALE */ html { height : 100% ; - background-color: $second_white_color; + background-color: $third_white_color; } body { @@ -17,7 +18,7 @@ body { } #principal { - background-color: $second_white_color; + background-color: $third_white_color; } /*MAIN*/ @@ -55,7 +56,7 @@ aside { background-color:$second_soft_color; color: white; margin-top:0px; - padding: 15px; + padding: 0px!important; a { color: $main_soft_color; @@ -70,6 +71,45 @@ aside { color: white; background-color: $second_bold_color; } + .heading { + padding: 8px 15px; + font-size: 32px; + line-height: 1.3; + text-align:center; + + &.inverted { + background-color:$second_white_color; + color:black; + } + + &.small { + font-size: 25px; + + .sub { + font-size: 0.7em; + font-weight: normal; + } + } + + .sub { + font-size: 0.7em; + font-weight: normal; + } + + &.separator { + border-bottom-color: $main_soft_color; + border-bottom-style: solid; + } + } + .text { + padding: 15px; + + &.inverted { + background-color:$second_white_color; + color:black; + } + + } } @media (min-width: 768px) { @@ -98,6 +138,32 @@ div.tag-list { code { font-size: small; } + +.module-list { + display: flex; + align-items: stretch; + flex-wrap: wrap; +} + +a.module { + background-color: $second_bold_color; + color: $second_white_color; + padding: 20px 40px; + margin: 5px; + border-bottom-color: $main_soft_color; + border-bottom-style: solid; + font-size: large; + display: block; + + &:hover, + &:active, + &:focus { + color: $second_white_color; + background-color: $second_soft_color; + text-decoration: none; + } +} + /* COULD BE USERFULL LATER .row-eq-height { diff --git a/shared/static/css/tree.scss b/shared/static/css/tree.scss new file mode 100644 index 0000000..c69ca48 --- /dev/null +++ b/shared/static/css/tree.scss @@ -0,0 +1,40 @@ +.tree { + font-size:large; + ul, li { + position: relative; + } + + ul { + list-style: none; + padding-left: 32px; + } + + li::before, + li::after { + content: ""; + position: absolute; + left: -12px; + } + li::before { + border-top: 3px solid $second_soft_color; + top: 9px; + width: 8px; + height: 0; + } + li::after { + border-left: 3px solid $second_soft_color; + height: 100%; + width: 0px; + top: 2px; + } + ul > li:last-child::after { + height: 8px; + } + + .category_node { + + } +} + + + diff --git a/shared/static/css/variables.scss b/shared/static/css/variables.scss index 01a86ea..483dec1 100644 --- a/shared/static/css/variables.scss +++ b/shared/static/css/variables.scss @@ -7,6 +7,11 @@ $second_bold_color: #FFB363; $second_soft_color: #FFC282; $second_white_color: #FFF5EB; +$third_bold_color: #48B0C7; +$third_soft_color: #8FD4E3; +$third_white_color: #DCEAED; + + $btn-font-color: white; $btn-bg-base: $main_bold_color; $btn-bg-special: $main_soft_color; @@ -16,5 +21,5 @@ $underline-brand: $second_soft_color; /* FONTS */ $font_brand:'Lily Script One', cursive; $font_nav:'Work Sans', cursive; -$font_bold:'Saira', sans-serif; +$font_bold:'Capriola', sans-serif; $font_normal:'Saira Semi Condensed', sans-serif; diff --git a/shared/templates/shared/base.html b/shared/templates/shared/base.html index d2a729c..aae0c9b 100644 --- a/shared/templates/shared/base.html +++ b/shared/templates/shared/base.html @@ -14,7 +14,7 @@ {# Fonts #} - + {# Global stylesheets #} @@ -57,10 +57,10 @@
    {% block real_content %} -
    +
    {% block content %}{% endblock %}
    -