Add categories and new colors #7

Merged
thisfro merged 10 commits from dev into main 2023-07-08 17:46:08 +02:00
19 changed files with 352 additions and 42 deletions

View file

@ -8,3 +8,8 @@ steps:
settings:
repo: git.thisfro.ch/pflaenz.li/pflaenzli
dockerfile: Dockerfile
registry: git.thisfro.ch/pflaenz.li/pflaenzli
username:
from_secret: docker_username
password:
from_secret: docker_password

15
.gitignore vendored
View file

@ -1,9 +1,14 @@
# Project
plz_verzeichnis_v2.json
django.po
plz.pkl
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
.vscode/settings.json
.vscode/tasks.json
.vscode/launch.json
.vscode/extensions.json
.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/

163
COLORS.md Normal file
View file

@ -0,0 +1,163 @@
<style>
.color-description {
display: flex;
align-items: center;
}
.color-swatch {
height: 20px;
width: 20px;
margin-right: 1rem;
white-space: pre;
margin-right: 1rem;
margin-left: 1rem;
}
.selector {
width: 12rem;
}
.dark {
color: white;
background-color: rgb(43, 48, 53);
}
</style>
# Colors
## Basics
There is a set of colors for each the light and dark theme.
## Light theme
### Main colors
<div class="color-description">
<code class="selector">--pfl-color</code>:
<div class="color-swatch" style="background-color: #4c6e4dff;"></div>
<code>#4c6e4dff</code>
</div>
<div class="color-description">
<code class="selector">--pfl-dark-green</code>:
<div class="color-swatch" style="background-color: #374139ff;"></div>
<code>#374139ff</code>
</div>
<div class="color-description">
<code class="selector">--pfl-grey</code>:
<div class="color-swatch" style="background-color: #93877a;"></div>
<code>#93877a</code>
</div>
<div class="color-description">
<code class="selector">--pfl-brown</code>:
<div class="color-swatch" style="background-color: #dbc8baff;"></div>
<code>#dbc8baff</code>
</div>
<div class="color-description">
<code class="selector">--pfl-orange</code>:
<div class="color-swatch" style="background-color: #ed7e2cff;"></div>
<code>#ed7e2cff</code>
</div>
### Background colors
<div class="color-description">
<code class="selector">--bg-pfl-color</code>:
<div class="color-swatch" style="background-color: #3f5b40ff;"></div>
<code>#3f5b40ff</code>
</div>
<div class="color-description">
<code class="selector">--bg-pfl-dark-green</code>:
<div class="color-swatch" style="background-color: #2f3831ff;"></div>
<code>#2f3831ff</code>
</div>
<div class="color-description">
<code class="selector">--bg-pfl-grey</code>:
<div class="color-swatch" style="background-color: #7b7166;"></div>
<code>#7b7166</code>
</div>
<div class="color-description">
<code class="selector">--bg-pfl-brown</code>:
<div class="color-swatch" style="background-color: #c4a58fff;"></div>
<code>#c4a58fff</code>
</div>
<div class="color-description">
<code class="selector">--bg-pfl-orange</code>:
<div class="color-swatch" style="background-color: #d96513ff;"></div>
<code>#d96513ff</code>
</div>
-------------------------------------------------------------------------
## Dark theme
### Main colors
<div class="dark">
<div class="color-description">
<code class="selector">--pfl-color</code>:
<div class="color-swatch" style="background-color: #8eb57b;"></div>
<code>#8eb57b</code>
</div>
<div class="color-description">
<code class="selector">--pfl-dark-green</code>:
<div class="color-swatch" style="background-color: #4c6e4dff;"></div>
<code>#4c6e4dff</code>
</div>
<div class="color-description">
<code class="selector">--pfl-grey</code>:
<div class="color-swatch" style="background-color: #bbbbbb;"></div>
<code>#bbbbbb</code>
</div>
<div class="color-description">
<code class="selector">--pfl-brown</code>:
<div class="color-swatch" style="background-color: #8f7e6b;"></div>
<code>#8f7e6b</code>
</div>
<div class="color-description">
<code class="selector">--pfl-orange</code>:
<div class="color-swatch" style="background-color: #e1ad45;"></div>
<code>#e1ad45</code>
</div>
</div>
### Background colors
<div class="dark">
<div class="color-description">
<code class="selector">--bg-pfl-color</code>:
<div class="color-swatch" style="background-color: #728f64;"></div>
<code>#728f64</code>
</div>
<div class="color-description">
<code class="selector">--bg-pfl-dark-green</code>:
<div class="color-swatch" style="background-color: #3d583e;"></div>
<code>#3d583e</code>
</div>
<div class="color-description">
<code class="selector">--bg-pfl-grey</code>:
<div class="color-swatch" style="background-color: #9b9b9b;"></div>
<code>#9b9b9b</code>
</div>
<div class="color-description">
<code class="selector">--bg-pfl-brown</code>:
<div class="color-swatch" style="background-color: #7b7166;"></div>
<code>#7b7166</code>
</div>
<div class="color-description">
<code class="selector">--bg-pfl-orange</code>:
<div class="color-swatch" style="background-color: #c98f44ff;"></div>
<code>#c98f44ff</code>
</div>
</div>

View file

@ -1,6 +1,7 @@
# Pflänz.li
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
[![Build Status](https://drone.thisfro.ch/api/badges/pflaenz.li/pflaenz.li/status.svg?ref=refs/heads/main)](https://drone.thisfro.ch/pflaenz.li/pflaenz.li)
## Idea
A platform where people can trade their plants. You can post what you have and search for others with [filters](#filters). The aim is to make it easier to trade plants and collect as few data as possible. Only the email/username and a postal code is required.
@ -26,7 +27,8 @@ It would be nice to have categories somehow, but it would be hard to make it com
Searching with filters such as:
| Filter Name | Type | Input type |
|--------------|---------------|------------|
| Indoor only | `boolean` | checkbox |
| Distance | `int` | numfield |
| ZIP code | `int` | numfield |
| Name | `string` | textfield |
| Category | `Category` | dropdown |

View file

@ -10,7 +10,7 @@ from .models import Offer, PflaenzliUser, Wish
class CreateOfferForm(forms.ModelForm):
class Meta:
model = Offer
fields = ['title', 'description', 'zipcode', 'image']
fields = ['title', 'description', 'category', 'zipcode', 'image']
class RegistrationForm(UserCreationForm):
@ -22,6 +22,7 @@ class RegistrationForm(UserCreationForm):
class FilterForm(forms.Form):
category = forms.ChoiceField(choices=Offer.FILTER_CATEGORIES, label=_("Category"))
text = forms.CharField(max_length=128, required=False, label=_("Search"))
zipcode = forms.CharField(max_length=4, required=False, label=_("ZIP code"))
distance = forms.IntegerField(required=False, label=_("Distance"))
@ -29,7 +30,14 @@ class FilterForm(forms.Form):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Overwrite default
self.fields['category'].initial = 'ALL'
# Set the translated labels with the selected language and icons for each form field
self.fields['category'].label = mark_safe(
f'<i class="fa-solid fa-tag"></i> {self.fields["category"].label}'
)
self.fields['text'].label = mark_safe(
f'<i class="fa-solid fa-magnifying-glass"></i> {self.fields["text"].label}'
)

View file

@ -0,0 +1,28 @@
# Generated by Django 4.1.7 on 2023-05-19 10:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("pflaenzli", "0003_alter_offer_description_alter_offer_image_and_more"),
]
operations = [
migrations.AddField(
model_name="offer",
name="category",
field=models.CharField(
choices=[
("PLNT", "Plant"),
("SEED", "Seedling"),
("POT", "Pot"),
("TOOL", "Tools"),
("OTHR", "Other"),
],
default="PLNT",
max_length=4,
),
),
]

View file

@ -14,12 +14,25 @@ class PflaenzliUser(AbstractUser):
class Offer(models.Model):
CATEGORIES = [
('PLNT', _('Plant')),
('SEED', _('Seedling')),
('POT', _('Pots')),
('TOOL', _('Tools')),
('OTHR', _('Other')),
]
FILTER_CATEGORIES = [
('ALL', _('All')),
] + CATEGORIES
created = models.DateTimeField(default=timezone.now)
user = models.ForeignKey(PflaenzliUser, on_delete=models.CASCADE)
title = models.CharField(max_length=50, verbose_name=_('Title'))
description = models.TextField(max_length=5000, verbose_name=_('Description'))
zipcode = models.IntegerField(blank=True, default=0, verbose_name=_('ZIP code'))
image = models.ImageField(upload_to="uploads/", verbose_name=_('Image'))
category = models.CharField(choices=CATEGORIES, max_length=4, default='PLNT', verbose_name=_('Category'))
class Wish(models.Model):

View file

@ -1,6 +1,18 @@
:root {
--pfl-color: #188d1c;
--bg-pfl-color: #59af5c;
/* Primary */
--pfl-color: #4c6e4dff;
--pfl-dark-green: #374139ff;
--pfl-grey: #93877a;
--pfl-brown: #dbc8baff;
--pfl-orange: #ed7e2cff;
/* Muted */
--bg-pfl-color: #3f5b40ff;
--bg-pfl-dark-green: #2f3831ff;
--bg-pfl-grey: #7b7166;
--bg-pfl-brown: #c4a58fff;
--bg-pfl-orange: #d96513ff;
--pfl-primary-bg-subtle: #cbf7cd;
--pfl-primary-text: var(--bg-pfl-color);
--pfl-primary-border-subtle: #6db770;
@ -11,8 +23,21 @@
}
:root[data-bs-theme='dark'] {
--pfl-primary-bg-subtle: #183119;
--pfl-primary-text: #5aac5d;
/* Primary */
--pfl-color: #8eb57b;
--pfl-dark-green: #4c6e4dff;
--pfl-grey: #bbbbbb;
--pfl-brown: #8f7e6b;
--pfl-orange: #d3a569ff;
/* Muted */
--bg-pfl-color: #728f64;
--bg-pfl-dark-green: #3d583e;
--bg-pfl-grey: #9b9b9b;
--bg-pfl-brown: #7d6e5d;
--bg-pfl-orange: #c98f44ff;
--pfl-primary-text: var(--pfl-color);
--pfl-primary-border-subtle: var(--pfl-color);
--bs-heading-color: #fff;
--pfl-logo: url('/static/dark.png');
@ -20,20 +45,22 @@
}
.btn-pfl {
--bs-btn-color: #fff;
--bs-btn-color: var(--bs-body-bg);
--bs-btn-hover-color: var(--bs-body-bg);
--bs-btn-bg: var(--pfl-color);
--bs-btn-border-color: var(--pfl-color);
--bs-btn-hover-color: #fff;
--bs-btn-hover-bg: #117314;
--bs-btn-hover-border-color: var(--pfl-color);
--bs-btn-hover-bg: var(--bg-pfl-color);
--bs-btn-hover-border-color: var(--bg-pfl-color);
--bs-btn-focus-shadow-rgb: 49, 132, 253;
--bs-btn-active-color: #fff;
--bs-btn-active-bg: var(--pfl-color);
--bs-btn-active-border-color: #0a53be;
--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
--bs-btn-disabled-color: #fff;
--bs-btn-disabled-bg: var(--pfl-color);
--bs-btn-disabled-border-color: var(--pfl-color);
}
.btn-pfl-secondary {
--bs-btn-bg: var(--pfl-brown);
--bs-btn-hover-bg: var(--bg-pfl-brown);
--bs-btn-color: var(--bs-heading-color);
--bs-btn-hover-color: var(--bs-heading-color);
}
.bg-pfl {
@ -98,4 +125,38 @@ a {
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}
.pfl-plnt {
background-color: var(--pfl-color);
color: var(--bs-body-bg);
}
.pfl-seed {
background-color: var(--pfl-dark-green);
}
.pfl-pot {
background-color: var(--pfl-brown);
color: var(--bs-heading-color);
}
.pfl-tool {
background-color: var(--pfl-grey);
color: var(--bs-body-bg);
}
.pfl-othr {
background-color: var(--bs-heading-color);
color: var(--bs-body-bg);
}
.btn-danger {
--bs-btn-color: var(--bs-body-bg);
--bs-btn-bg: var(--pfl-orange);
--bs-btn-hover-color: var(--bs-body-bg);
--bs-btn-border-color: var(--pfl-orange);
--bs-btn-hover-bg: var(--bg-pfl-orange);
--bs-btn-hover-border-color: var(--bg-pfl-orange);
--bs-btn-active-bg: var(--pfl-orange);
}

View file

@ -1,7 +1,7 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}
{% trans "Not found" %}
{% trans "Forbidden" %}
{% endblock title %}
{% block content %}
<div>
@ -13,6 +13,6 @@
</p>
<h2>{% trans "What now?" %}</h2>
<a href="{% url 'index' %}" class="btn btn-pfl">{% trans "Go home" %}</a>
<a href="mailto:contact@pflaenz.li" class="btn btn-secondary">{% trans "Report error" %}</a>
<a href="mailto:contact@pflaenz.li" class="btn btn-pfl-secondary">{% trans "Report error" %}</a>
</div>
{% endblock content %}

View file

@ -1,7 +1,7 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}
{% trans "Not found" %}
{% trans "Forbidden" %}
{% endblock title %}
{% block content %}
<div>
@ -13,6 +13,6 @@
</p>
<h2>{% trans "What now?" %}</h2>
<a href="{% url 'index' %}" class="btn btn-pfl">{% trans "Go home" %}</a>
<a href="mailto:contact@pflaenz.li" class="btn btn-secondary">{% trans "Report error" %}</a>
<a href="mailto:contact@pflaenz.li" class="btn btn-pfl-secondary">{% trans "Report error" %}</a>
</div>
{% endblock content %}

View file

@ -13,6 +13,6 @@
</p>
<h2>{% trans "What now?" %}</h2>
<a href="{% url 'index' %}" class="btn btn-pfl">{% trans "Go home" %}</a>
<a href="mailto:contact@pflaenz.li" class="btn btn-secondary">{% trans "Report error" %}</a>
<a href="mailto:contact@pflaenz.li" class="btn btn-pfl-secondary">{% trans "Report error" %}</a>
</div>
{% endblock content %}

View file

@ -1,18 +1,18 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}
{% trans "Not found" %}
{% trans "Server error" %}
{% endblock title %}
{% block content %}
<div>
<h1 class="mb-5">
<span class="badge bg-danger">Error 500</span> {% trans "Forbidden" %}
<span class="badge bg-danger">Error 500</span> {% trans "Server error" %}
</h1>
<p class="mb-5 blockquote w-75 m-auto">
{% blocktrans %}Uh-oh! The delicate balance of the botanical realms has been disrupted. The forces of nature are in disarray, and our plant guardians are diligently working to restore harmony. We apologize for any inconvenience caused during this mystical turbulence. Please bear with us as we channel our magic to mend the rupture. Please contact us, if you have any information that could help to dispel the dark magic!{% endblocktrans %}
</p>
<h2>{% trans "What now?" %}</h2>
<a href="{% url 'index' %}" class="btn btn-pfl">{% trans "Go home" %}</a>
<a href="mailto:contact@pflaenz.li" class="btn btn-secondary">{% trans "Report error" %}</a>
<a href="mailto:contact@pflaenz.li" class="btn btn-pfl-secondary">{% trans "Report error" %}</a>
</div>
{% endblock content %}

View file

@ -1,5 +1,7 @@
{% extends 'base.html' %}
{% block title %}Privacy Policy{% endblock %}
{% load i18n %}
{% block title %}FAQ{% endblock %}
{% block meta %}<meta name="description" content="Frequently asked questions">{% endblock %}
{% block content %}
<h1 class="mb-3">Frequently Asked Questions</h1>
<h2 class="mb-3">Is it free?</h2>

View file

@ -1,5 +1,11 @@
{% extends 'base.html' %}
{% block title %}Privacy Policy{% endblock %}
{% load i18n %}
{% block title %}
{% trans 'Imprint' %}
{% endblock %}
{% block meta %}
<meta name="description" content="Pflänz.li - {% trans 'Imprint' %}">
{% endblock %}
{% block content %}
<h1>Privacy Policy</h1>
<p>

View file

@ -2,7 +2,10 @@
{% load static %}
{% load i18n %}
{% block title %}Home{% endblock %}
{% block meta %}<meta name="description" content="A platform to trade plants.">{% endblock %}
{% block meta %}
<meta name="description"
content="{% trans 'Pflänz.li is a platform to trade plants.' %}">
{% endblock %}
{% block background %}home-background{% endblock %}
{% block content %}
<div class="p-5 mb-4 bg-body-tertiary rounded-3 home-opaque">
@ -20,7 +23,7 @@
class="btn btn-pfl btn-lg mb-3"
type="button">{% trans "Show offers" %}</a>
<a href="{% url 'register_user' %}"
class="btn btn-secondary btn-lg mb-3"
class="btn btn-pfl-secondary btn-lg mb-3"
type="button">{% trans "Register" %}</a>
</div>
</div>

View file

@ -4,9 +4,12 @@
<html lang="en" class="h-100">
<head>
<title>Pflänz.li -
{% block title %}{% endblock %}
{% block title %}
{% endblock title %}
</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
{% block meta %}
{% endblock meta %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD"

View file

@ -17,7 +17,9 @@
src="{{ offer.image.url }}">
</div>
<div class="show-offer-info col-12 col-md-6">
<h1 class="mb-3">{{ offer.title }}</h1>
<h1 class="mb-3">
{{ offer.title }}<span class="ms-2 badge text-bg-secondary">{{ offer.get_category_display }}</span>
</h1>
<div class="mb-3 d-flex column-gap-2">
<p class="mr-3">
<i class="fas fa-user"></i>
@ -66,7 +68,7 @@
</div>
<div class="modal-body">{% trans "Do you really want to delete this offer? This can't be undone." %}</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
<button type="button" class="btn btn-pfl-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
<a href="{% url 'offer_delete' offer.id %}"
type="button"
class="btn btn-danger">{% trans "Delete" %}</a>

View file

@ -3,7 +3,10 @@
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}
{% trans 'Filter' %}
{% trans 'Offers' %}
{% endblock %}
{% block meta %}
<meta name="description" content="{% trans 'Search for offers' %}">
{% endblock %}
{% block content %}
<h1 class="mt-3">
@ -37,7 +40,9 @@
<img class="card-img-top offer-img" src="{% static 'placeholder.jpg' %}" />
{% endif %}
<div class="card-body">
<h5 class="h5">{{ offer.title }}</h5>
<h5 class="h5">
{{ offer.title }}<span class="ms-2 badge pfl-{{ offer.category|lower }}">{{ offer.get_category_display }}</span>
</h5>
</div>
</a>
<div class="card-footer d-flex justify-content-between">

View file

@ -199,13 +199,17 @@ def error_500(request):
def filter_offers(offers, form):
if form.cleaned_data['text']:
offers = offers.filter(title__icontains=form.cleaned_data['text'])
if category := form.cleaned_data['category']:
if category != 'ALL':
offers = offers.filter(category=category)
if form.cleaned_data['zipcode']:
if text := form.cleaned_data['text']:
offers = offers.filter(title__icontains=text)
if zipcode := form.cleaned_data['zipcode']:
if form.cleaned_data['distance']:
offers = filter_by_distance(offers, form.cleaned_data['zipcode'], form.cleaned_data['distance'])
offers = filter_by_distance(offers, zipcode, form.cleaned_data['distance'])
else:
offers = offers.filter(zipcode=int(form.cleaned_data['zipcode']))
offers = offers.filter(zipcode=int(zipcode))
return offers