diff --git a/agenda_hat/settings.py b/agenda_hat/settings.py index 96de4ca..b6342b9 100644 --- a/agenda_hat/settings.py +++ b/agenda_hat/settings.py @@ -21,16 +21,17 @@ # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ -# SECURITY WARNING: keep the secret key used in production secret! -# SECRET_KEY = 'django-insecure-4=nvn+3!^^#3489hot0brrx-!m+efx_^+x@^mwq^)c-$#u^^_m' -SECRET_KEY = os.environ['HAT_SECRET_KEY'] # SECURITY WARNING: don't run with debug turned on in production! DEBUG = {'False': False, 'True': True}[os.environ['HAT_DEBUG']] -ALLOWED_HOSTS = os.environ['HAT_ALLOWED_HOSTS'].split(',') -CSRF_TRUSTED_ORIGINS = ['https://'+host for host in ALLOWED_HOSTS] +if DEBUG: + SECRET_KEY = 'django-insecure-4=nvn+3!^^#3489hot0brrx-!m+efx_^+x@^mwq^)c-$#u^^_m' -STATIC_ROOT = Path(os.environ['HAT_STATIC_ROOT']) +else: + SECRET_KEY = os.environ['HAT_SECRET_KEY'] + ALLOWED_HOSTS = os.environ['HAT_ALLOWED_HOSTS'].split(',') + CSRF_TRUSTED_ORIGINS = ['https://'+host for host in ALLOWED_HOSTS] + STATIC_ROOT = Path(os.environ['HAT_STATIC_ROOT']) # Application definition diff --git a/agenda_hat/urls.py b/agenda_hat/urls.py index 80b0894..eb363bc 100644 --- a/agenda_hat/urls.py +++ b/agenda_hat/urls.py @@ -18,5 +18,5 @@ urlpatterns = [ path('admin/', admin.site.urls), - path('', include("hat.urls")) + path('', include("hat.urls")), ] diff --git a/hat/models.py b/hat/models.py index 236ce9a..786a96f 100644 --- a/hat/models.py +++ b/hat/models.py @@ -4,4 +4,9 @@ # Create your models here. class Item(models.Model): text = models.TextField() - pulled = models.BooleanField(default=False, editable=False) \ No newline at end of file + pulled = models.BooleanField(default=False, editable=False) + pulled_at = models.DateTimeField(null=True, blank=True) + + + # todo: shame meeting for taking forever. We already have a query of all items pulled today, + # todo: and we're storing times... timedelta, then add red highlight or something to long items diff --git a/hat/static/hat/hat.css b/hat/static/hat/hat.css index 9ed031d..df754f6 100644 --- a/hat/static/hat/hat.css +++ b/hat/static/hat/hat.css @@ -1,17 +1,53 @@ body { text-align: center; + display: grid; + grid-template-columns: 1fr 5fr 1fr; + height: 100dvh; + overflow: clip; +} + +ul { + list-style: none; + padding: 0; } .h1 { height: 80px; } +.sidebar { + display: flex; + gap: 0.5rem; + flex-direction: column; +} + +.sidebar button { + width: 100%; +} + +.message.new > form { + display: flex; + flex-direction: column; + margin: 1rem; + height: 7rem; + gap: 0.5rem; +} + +.message.new > form > button { + width: 50%; + align-self: center; +} + +/*Begin animation mess*/ + +.hat-pull.new + .hat, .hat { width: 500px; height: auto; rotate: 180deg; margin-top: auto; justify-self: end; + animation: none; } .hat.finished { @@ -33,12 +69,27 @@ body { align-self: center; } +.hat-pull.htmx-swapping .message.new { + opacity: 0; + transition: opacity 1s; + animation: 0.5s new-item-throw ease-in; +} + +.hat-pull.htmx-settling .message.new { + animation: none; +} + +.hat-pull.new { + animation: none; +} + .hat-pull img { width: 300px; height: auto; } -.hat-pull p { +.hat-pull .message { + margin-top: 3rem; text-align: center; width: 500px; height: fit-content; @@ -49,7 +100,14 @@ body { margin-left: -132%; } -.hat-pull.finished p { +.hat-pull .message.new { + animation: none; + opacity: 100%; + transition: opacity 0.5s; +} + +.hat-pull.finished .message, +.hat-pull.index .message { opacity: 0; animation: none; } @@ -58,6 +116,12 @@ body { animation: 1s hand-wave infinite; } +.hat-pull.index { + animation: 1s hello-wave infinite; +} + + + @keyframes hand-pull { from { } @@ -124,4 +188,27 @@ body { to { rotate: -45deg; } +} + +@keyframes hello-wave { + from { + rotate: -5deg; + } + 50% { + rotate: 5deg; + } + to { + rotate: -5deg; + } +} + +@keyframes new-item-throw { + from { + opacity: 1; + } + + to { + transform: translate(0, 100dvh) scale(1%); + opacity: 0; + } } \ No newline at end of file diff --git a/hat/templates/hat/counter-snippet.html b/hat/templates/hat/counter-snippet.html new file mode 100644 index 0000000..40da83c --- /dev/null +++ b/hat/templates/hat/counter-snippet.html @@ -0,0 +1,16 @@ +
+

Are we there yet?

+ {% if remaining_items == 0 %} + + Yes! + + {% elif remaining_items < 3 %} + + Almost! There are only {{ remaining_items }} agenda items left! + + {% else %} + + NO. There are {{ remaining_items }} agenda items left. + + {% endif %} +
\ No newline at end of file diff --git a/hat/templates/hat/hat.html b/hat/templates/hat/hat.html index 15f4109..cc1bd99 100644 --- a/hat/templates/hat/hat.html +++ b/hat/templates/hat/hat.html @@ -4,18 +4,34 @@ Agenda Hat - + + -

Agenda Hat

+
-
+
-

+

{{ item.text }} -

+
hat!
+ \ No newline at end of file diff --git a/hat/templates/hat/index.html b/hat/templates/hat/index.html new file mode 100644 index 0000000..15f4109 --- /dev/null +++ b/hat/templates/hat/index.html @@ -0,0 +1,21 @@ +{% load static %} + + + + + Agenda Hat + + +

Agenda Hat

+
+
+ +

+ {{ item.text }} +

+
+ hat! +
+ + \ No newline at end of file diff --git a/hat/templates/hat/new_item.html b/hat/templates/hat/new_item.html new file mode 100644 index 0000000..594c7bc --- /dev/null +++ b/hat/templates/hat/new_item.html @@ -0,0 +1,17 @@ +{% load static %} + +
+ +
+
+ {% csrf_token %} + {{ form.text }} + +
+
+
+ +{% include 'hat/counter-snippet.html' with remaining_items=remaining_items %} \ No newline at end of file diff --git a/hat/urls.py b/hat/urls.py index 1610f98..fe8e35e 100644 --- a/hat/urls.py +++ b/hat/urls.py @@ -1,7 +1,9 @@ from django.urls import path -from .views import pull_item +from .views import pull_item, index, CreateItemView urlpatterns = [ - path('', pull_item) + path("", index, name="index"), + path("next", pull_item, name="pull-item"), + path("add", CreateItemView.as_view(), name="new-item"), ] \ No newline at end of file diff --git a/hat/views.py b/hat/views.py index 5180941..6b8f7e5 100644 --- a/hat/views.py +++ b/hat/views.py @@ -1,16 +1,31 @@ from django.shortcuts import render +from django.urls import reverse_lazy +from django.utils import timezone +from django.views.generic import CreateView import random from .models import Item +def get_remaining_items(): + return Item.objects.filter(pulled=False).count() + +def index(request): + return render(request, 'hat/hat.html', { + 'hat_class': 'index', # todo: make timedelta in line 12 configurable + 'past_items': Item.objects.filter(pulled=True, pulled_at__range=(timezone.now() - timezone.timedelta(hours=6), timezone.now())), + 'remaining_items': Item.objects.filter(pulled=False).count(), + }) + + def pull_item(request): item = '' hat_class = '' try: item = random.choice(Item.objects.filter(pulled=False)) item.pulled = True + item.pulled_at = timezone.now() item.save() except IndexError: hat_class = 'finished' @@ -18,4 +33,21 @@ def pull_item(request): return render(request, 'hat/hat.html', { 'item': item, 'hat_class': hat_class, - }) \ No newline at end of file + 'past_items': Item.objects.filter(pulled=True, pulled_at__range=(timezone.now() - timezone.timedelta(hours=6), timezone.now())), + 'remaining_items': Item.objects.filter(pulled=False).count(), + }) + + +class CreateItemView(CreateView): + model = Item + template_name = "hat/new_item.html" + fields = [ + 'text', + ] + success_url = reverse_lazy('new-item') + print(Item.objects.filter(pulled=False)) + extra_context = { + 'remaining_items': get_remaining_items + } + +