Compare commits

..

6 Commits

Author SHA1 Message Date
10c08a2f5e Current CSS 2021-04-10 08:24:33 +02:00
50f60be10a Shifting index 2021-04-10 08:24:23 +02:00
8b32b56dd9 Custom Widget to select content/invisible radio input 2021-04-10 08:24:08 +02:00
74d842a668 #47 Settinge of Place Hero Image 2021-04-10 08:23:36 +02:00
2ac39f719f Removing debug 2021-04-09 19:51:45 +02:00
9b6121e448 Small fix 2021-04-09 19:51:17 +02:00
12 changed files with 131 additions and 38 deletions

View File

@ -8,6 +8,8 @@ from django.db import models
from django.contrib.auth.forms import UserCreationForm, UserChangeForm from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from lostplaces import widgets
from lostplaces.models import Place, PlaceImage, Voucher, Explorer from lostplaces.models import Place, PlaceImage, Voucher, Explorer
class SignupVoucherForm(UserCreationForm): class SignupVoucherForm(UserCreationForm):
@ -68,6 +70,15 @@ class PlaceForm(forms.ModelForm):
model = Place model = Place
fields = '__all__' fields = '__all__'
exclude = ['submitted_by'] exclude = ['submitted_by']
widgets = {
'hero': widgets.SelectContent()
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if 'instance' in kwargs:
self.fields['hero'].queryset = PlaceImage.objects.filter(place=kwargs['instance'])
self.fields['hero'].widget.attrs['item_template'] = 'partials/select_place_image_item.html'
latitude = forms.DecimalField( latitude = forms.DecimalField(
widget=forms.NumberInput(attrs={'min':-90,'max': 90,'type': 'number', 'step': 'any'}) widget=forms.NumberInput(attrs={'min':-90,'max': 90,'type': 'number', 'step': 'any'})
@ -90,8 +101,23 @@ class PlaceImageForm(forms.ModelForm):
self.fields['filename'].required = False self.fields['filename'].required = False
class PlaceSetHeroForm(forms.ModelForm):
class Meta:
model = Place
fields = ['hero']
widgets = {
'hero': widgets.SelectContent()
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['hero'].queryset = PlaceImage.objects.filter(place=kwargs['instance'])
self.fields['hero'].widget.attrs['item_template'] = 'partials/select_place_image_item.html'
class TagSubmitForm(forms.Form): class TagSubmitForm(forms.Form):
tag_list = forms.CharField( tag_list = forms.CharField(
max_length=500, max_length=500,
required=False, required=False,
widget=forms.TextInput(attrs={'autocomplete':'off'}) widget=forms.TextInput(attrs={'autocomplete':'off'})

View File

@ -11,6 +11,7 @@ from lostplaces.models.abstract_models import Submittable, Taggable, Mapable
from easy_thumbnails.fields import ThumbnailerImageField from easy_thumbnails.fields import ThumbnailerImageField
from easy_thumbnails.files import get_thumbnailer from easy_thumbnails.files import get_thumbnailer
class Place(Submittable, Taggable, Mapable): class Place(Submittable, Taggable, Mapable):
""" """
Place defines a lost place (location, name, description etc.). Place defines a lost place (location, name, description etc.).
@ -25,9 +26,32 @@ class Place(Submittable, Taggable, Mapable):
verbose_name=_('Description'), verbose_name=_('Description'),
) )
hero = models.ForeignKey(
'PlaceImage',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='place_heros'
)
def get_hero_image(self):
if self.hero:
return self.hero
elif len(self.placeimages.all()) > 0:
return self.placeimages.first()
else:
return None
def get_absolute_url(self): def get_absolute_url(self):
return reverse('place_detail', kwargs={'pk': self.pk}) return reverse('place_detail', kwargs={'pk': self.pk})
def get_hero_index_in_queryset(self):
for i in range(0, len(self.placeimages.all())):
image = self.placeimages.all()[i]
if image == self.hero:
return i
return None
@classmethod @classmethod
# Get center position of LP-geocoordinates. # Get center position of LP-geocoordinates.
@ -89,7 +113,7 @@ class PlaceImage(PlaceAsset):
upload_to=generate_place_image_filename, upload_to=generate_place_image_filename,
resize_source=dict(size=(2560, 2560), resize_source=dict(size=(2560, 2560),
sharpen=True), sharpen=True),
verbose_name=_('Filename(s)'), verbose_name=_('Images'),
help_text=_('Optional: One or more images to upload') help_text=_('Optional: One or more images to upload')
) )
place = models.ForeignKey( place = models.ForeignKey(
@ -104,7 +128,7 @@ class PlaceImage(PlaceAsset):
of this image as textual representation of this instance of this image as textual representation of this instance
""" """
return 'Image ' + str(self.pk) return 'Image ' + str(self.place.name)
# These two auto-delete files from filesystem when they are unneeded: # These two auto-delete files from filesystem when they are unneeded:

View File

@ -858,6 +858,13 @@ body {
.LP-Pagination .LP-Pagination__Item .LP-Link { .LP-Pagination .LP-Pagination__Item .LP-Link {
padding: 8px 11px; } } padding: 8px 11px; } }
.LP-Select {
display: block;
cursor: pointer; }
.LP-Select:checked,
:checked + .LP-Select, .LP-Select--active {
box-shadow: 0 0 3px 3px #C09F80; }
.LP-Content { .LP-Content {
padding: 35px; } padding: 35px; }
@ -1060,19 +1067,13 @@ body {
padding: 5px; padding: 5px;
font-size: 25px; } font-size: 25px; }
.LP-UserInfo__Meta { .LP-UserInfo__Meta {
margin-top: 10px;
padding: 5px; } padding: 5px; }
.LP-UserInfo__Meta * { .LP-UserInfo__Meta * {
font-family: "Montserrat", Helvetica, sans-serif; font-family: "Montserrat", Helvetica, sans-serif;
font-size: 18px; } font-size: 18px; }
.LP-UserInfo__Meta .LP-UserInfo__Key { .LP-UserInfo__Meta .LP-UserInfo__Key {
padding-right: 25px; padding-right: 25px;
font-weight: bold; font-weight: bold; }
white-space: nowrap; }
.LP-UserInfo__Meta .LP-UserInfo__Value {
white-space: nowrap; }
.LP-UserInfo__Edit {
margin-top: 10px; }
.LP-Header { .LP-Header {
display: flex; display: flex;
@ -1681,6 +1682,12 @@ body {
object-position: botom; } object-position: botom; }
.LP-ImageGrid__Item--center img { .LP-ImageGrid__Item--center img {
object-position: center; } object-position: center; }
.LP-ImageGrid__Item img {
height: unset;
width: unset; }
.LP-ImageGrid__Item .LP-Image {
height: 100%;
width: 100%; }
.LP-ImageGrid__Item--add .LP-Link { .LP-ImageGrid__Item--add .LP-Link {
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -1734,12 +1741,17 @@ body {
.LP-ImageGrid__LightBox:target { .LP-ImageGrid__LightBox:target {
visibility: visible; visibility: visible;
display: grid; display: grid;
justify-items: center;
grid-template-areas: 'picture picture' 'previous next'; grid-template-areas: 'picture picture' 'previous next';
grid-template-rows: 1fr 4rem; grid-template-rows: 1fr 4rem;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
pointer-events: initial; } pointer-events: initial; }
.LP-ImageGrid__FullSizeImage { .LP-ImageGrid__FullSizeImage {
grid-area: picture; } grid-area: picture;
max-width: 100%;
max-height: 100%;
height: unset;
width: unset; }
.LP-ImageGrid__Previous { .LP-ImageGrid__Previous {
grid-area: previous; grid-area: previous;
align-self: center; align-self: center;
@ -1800,15 +1812,6 @@ body {
flex-shrink: 1; flex-shrink: 1;
flex-basis: max-content; } flex-basis: max-content; }
@media (max-width: 1000px) {
.LP-UserProfile {
flex-direction: column-reverse;
gap: 35px; }
.LP-UserProfile__Info {
flex-basis: 100%; }
.LP-UserProfile__Info .LP-UserInfo {
max-width: unset; } }
.LP-MainContainer { .LP-MainContainer {
margin: 0 auto; margin: 0 auto;
max-width: 1280px; } max-width: 1280px; }

View File

@ -26,7 +26,7 @@
<article class="LP-PlaceTeaser"> <article class="LP-PlaceTeaser">
<div class="LP-PlaceTeaser__Image"> <div class="LP-PlaceTeaser__Image">
{% partial 'image' %} {% partial 'image' %}
{% source_url source_url=place.placeimages.first.filename.thumbnail.url %} {% set source_url place.placeimages.first.filename.thumbnail.url %}
{% endpartial %} {% endpartial %}
</div> </div>
<div class="LP-PlaceTeaser__Meta"> <div class="LP-PlaceTeaser__Meta">

View File

@ -2,9 +2,7 @@
<div class="LP-Input {% if classes%}{{classes}}{% endif %} {% if field.errors %} LP-Input--error {% endif %}"> <div class="LP-Input {% if classes%}{{classes}}{% endif %} {% if field.errors %} LP-Input--error {% endif %}">
<label for="{{field.id_for_label}}" class="LP-Input__Label">{{field.label}}</label> <label for="{{field.id_for_label}}" class="LP-Input__Label">{{field.label}}</label>
{% with class="LP-Input__Field "%} {% render_field field class+='LP-Input__Field' %}
{% render_field field class=class%}
{% endwith %}
<span class="LP-Input__Message"> <span class="LP-Input__Message">
{% if field.errors %} {% if field.errors %}

View File

@ -7,9 +7,8 @@
<div class="LP-ImageGrid"> <div class="LP-ImageGrid">
<ul class="LP-ImageGrid__Container"> <ul class="LP-ImageGrid__Container">
{% for image in image_list %} {% for image in image_list %}
<li id="thumbnail{{forloop.counter}}" class="LP-ImageGrid__Item"> <li id="thumbnail{{forloop.counter0}}" class="LP-ImageGrid__Item">
{{ "#image"|add:forloop.counter }} {% include 'partials/image.html' with source_url=image.filename.thumbnail.url link_url="#image"|addstr:forloop.counter0 %}
{% include 'partials/image.html' with source_url=image.filename.thumbnail.url link_url="#image"|addstr:forloop.counter %}
{% if user.explorer == image.submitted_by%} {% if user.explorer == image.submitted_by%}
<span class="LP-ImageGrid__DeleteItem" title="Bild löschen"> <span class="LP-ImageGrid__DeleteItem" title="Bild löschen">
<a href="{% url 'place_image_delete' pk=image.id %}" class="LP-Link"> <a href="{% url 'place_image_delete' pk=image.id %}" class="LP-Link">
@ -17,16 +16,16 @@
</a> </a>
</span> </span>
{% endif %} {% endif %}
<div id="image{{forloop.counter}}" class="LP-ImageGrid__LightBox"> <div id="image{{forloop.counter0}}" class="LP-ImageGrid__LightBox">
<img class="LP-ImageGrid__FullSizeImage" src="{{image.filename.large.url}}" loading="lazy"/> <img class="LP-ImageGrid__FullSizeImage" src="{{image.filename.large.url}}" loading="lazy"/>
{% if forloop.counter < image_list|length %} {% if forloop.counter0 < image_list|length|add:-1 %}
<a href="#image{{forloop.counter|add:1}}" class="LP-ImageGrid__Next">Next</a> <a href="#image{{forloop.counter0|add:1}}" class="LP-ImageGrid__Next">Next</a>
{% endif %} {% endif %}
{% if forloop.counter > 1 %} {% if forloop.counter0 > 0 %}
<a href="#image{{forloop.counter|add:-1}}" class="LP-ImageGrid__Previous">Previous</a> <a href="#image{{forloop.counter0|add:-1}}" class="LP-ImageGrid__Previous">Previous</a>
{% endif %} {% endif %}
<span class="LP-ImageGrid__Close LP-ImageGrid__DeleteItem" title="Schließen"> <span class="LP-ImageGrid__Close LP-ImageGrid__DeleteItem" title="Schließen">
<a href="#thumbnail{{forloop.counter}}" class="LP-Link"> <a href="#thumbnail{{forloop.counter0}}" class="LP-Link">
<img class="LP-Icon" src="{% static 'icons/cancel.svg' %}"/> <img class="LP-Icon" src="{% static 'icons/cancel.svg' %}"/>
</a> </a>
</span> </span>

View File

@ -2,8 +2,8 @@
<article class="LP-PlaceTeaser {% if extended %} LP-PlaceTeaser--extended{% endif %}"> <article class="LP-PlaceTeaser {% if extended %} LP-PlaceTeaser--extended{% endif %}">
<div class="LP-PlaceTeaser__Image"> <div class="LP-PlaceTeaser__Image">
{% if place.placeimages.all|length > 0 %} {% if place.get_hero_image %}
{% include 'partials/image.html' with source_url=place.placeimages.first.filename.thumbnail.url link_url=place.get_absolute_url%} {% include 'partials/image.html' with source_url=place.get_hero_image.filename.thumbnail.url link_url=place.get_absolute_url%}
{% else %} {% else %}
<a href="{{place.get_absolute_url}}"> <a href="{{place.get_absolute_url}}">
<img class="LP-Image" src="{% static 'images/missing_image.png' %}" /> <img class="LP-Image" src="{% static 'images/missing_image.png' %}" />

View File

@ -0,0 +1,3 @@
{%load lostplaces %}
{% include 'partials/image.html' with source_url=object.filename.thumbnail.url %}

View File

@ -22,13 +22,15 @@
{% block maincontent %} {% block maincontent %}
<article class="LP-PlaceDetail"> <article class="LP-PlaceDetail">
<header class="LP-PlaceDetail__Header"> <header class="LP-PlaceDetail__Header">
<h1 class="LP-Headline">{{ place.name }} {% include 'partials/icons/place_favorite.html' %} {% include 'partials/icons/place_visited.html' %}</h1> <h1 class="LP-Headline">{{ place.name }} {% include 'partials/icons/place_favorite.html' %} {% include 'partials/icons/place_visited.html' %}</h1>
{% if place.placeimages.first.filename.hero.url %} {% if place.get_hero_image %}
<div class="LP-PlaceDetail__Image"> <div class="LP-PlaceDetail__Image">
{% partial image %} {% partial image %}
{% set source_url place.placeimages.first.filename.hero.url %} {% set source_url place.get_hero_image.filename.hero.url %}
{% set link_url %}
{{"#image"|addstr:place.get_hero_index_in_queryset}}
{% endset %}
{% endpartial %} {% endpartial %}
</div> </div>
{% endif %} {% endif %}

View File

@ -1,6 +1,7 @@
{% extends 'global.html'%} {% extends 'global.html'%}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
{% load widget_tweaks %}
# {% block title %}{% translate 'Edit place' %}{% endblock %} # {% block title %}{% translate 'Edit place' %}{% endblock %}
@ -39,6 +40,15 @@
</div> </div>
</div> </div>
{% if object.placeimages.all|length > 0 %}
<legend class="LP-Form__Legend">{% translate 'Set Hero Image' %}</legend>
<div class="LP-Form__Composition">
<div class="LP-Form__Field">
{% render_field form.hero container_class='LP-ImageGrid__Container' item_class='LP-ImageGrid__Item LP-Select' current_selected_value=object.hero.id%}
</div>
</div>
{% endif %}
{% translate 'Update' as action %} {% translate 'Update' as action %}
<div class="LP-Form__Composition LP-Form__Composition--buttons"> <div class="LP-Form__Composition LP-Form__Composition--buttons">
{% include 'partials/form/submit.html' with referrer=request.META.HTTP_REFERER action=action %} {% include 'partials/form/submit.html' with referrer=request.META.HTTP_REFERER action=action %}

View File

@ -0,0 +1,23 @@
<ul class="{{widget.attrs.container_class}}">
{% for group_name, group_choices, group_index in widget.optgroups %}
{% for option in group_choices %}
{% if option.value %}
<li style="display: content;">
<input
style="display: none;"
name="{{option.name}}"
id="{{widget.attrs.id}}{{group_index}}"
type="radio"
value="{{option.value.instance.id}}"
{% if widget.attrs.current_selected_value|stringformat:'s' == option.value.instance.id|stringformat:'s' %}checked="checked"{% endif %}
/>
<label class="{{widget.attrs.item_class}}" for="{{widget.attrs.id}}{{group_index}}">
{% if widget.attrs.item_template %}
{% include widget.attrs.item_template with object=option.value.instance %}
{% endif %}
</label>
</li>
{% endif %}
{% endfor %}
{% endfor %}
</ul>

View File

@ -0,0 +1,5 @@
from django import forms
class SelectContent(forms.Select):
template_name = 'widgets/select_content.html'