From 4b157ed1d136ea7bcb20604915d90558cb5c70f4 Mon Sep 17 00:00:00 2001 From: j Date: Sun, 16 Jul 2023 11:26:14 +0530 Subject: [PATCH] comments --- app/item/admin.py | 8 +++- app/item/models.py | 30 ++++++++++++ app/settings.py | 11 +++++ app/static/css/comments.css | 43 ----------------- app/static/css/comments.scss | 90 ++++++++++++++++++++++++++++++++++++ app/static/css/site.scss | 52 +++++++++++++++++++++ app/static/css/style.css | 10 ++++ app/static/js/comments.js | 58 ++++++++++++++--------- app/static/js/render.js | 9 ++-- app/templates/archive.html | 20 +------- app/templates/base.html | 23 +++++++-- app/templates/index.html | 39 ++-------------- app/templates/item.html | 24 +++++++--- app/templates/listitem.html | 15 ++++++ requirements.txt | 6 +++ 15 files changed, 305 insertions(+), 133 deletions(-) delete mode 100644 app/static/css/comments.css create mode 100644 app/static/css/comments.scss create mode 100644 app/static/css/site.scss create mode 100644 app/templates/listitem.html diff --git a/app/item/admin.py b/app/item/admin.py index 1722428..94acd42 100644 --- a/app/item/admin.py +++ b/app/item/admin.py @@ -14,7 +14,13 @@ admin.site.register(models.Item, ItemAdmin) class CommentAdmin(admin.ModelAdmin): - search_fields = ['item__title', 'item__url', 'text', 'name', 'email'] + search_fields = [ + 'item__title', + 'item__url', + 'text', + 'name', + 'email' + ] list_display = ['__str__', 'published'] list_filter = ( ("published", admin.EmptyFieldListFilter), diff --git a/app/item/models.py b/app/item/models.py index 0bb4f8b..243ed3b 100644 --- a/app/item/models.py +++ b/app/item/models.py @@ -1,6 +1,8 @@ from django.utils.timezone import datetime, timedelta from django.utils import timezone import json +import requests +import lxml.html from django.conf import settings from django.contrib.auth import get_user_model @@ -31,6 +33,10 @@ class Item(models.Model): announced = models.DateTimeField(null=True, default=None, blank=True) data = models.JSONField(default=dict, editable=False) + def save(self, *args, **kwargs): + if self.url and not self.data: + self.update_data() + super().save(*args, **kwargs) def __str__(self): return '%s (%s)' % (self.title, self.url) @@ -70,6 +76,26 @@ class Item(models.Model): def get_absolute_url(self): return reverse('item', kwargs={'id': self.id}) + def update_data(self): + self.data.update(self.parse_url()) + + def parse_url(self): + content = requests.get(self.url).text + doc = lxml.html.fromstring(content) + data = {} + for meta in doc.cssselect('meta'): + key = meta.attrib.get('name') + if not key: + key = meta.attrib.get('property') + value = meta.attrib.get('content') + if key and value: + if key in ('viewport', ): + continue + key = key.replace('og:', '') + data[key] = value + return data + + class Comment(models.Model): created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) @@ -83,6 +109,10 @@ class Comment(models.Model): data = models.JSONField(default=dict, editable=False) published = models.DateTimeField(null=True, default=None) + @property + def is_published(self): + return bool(self.published) + def __str__(self): return '%s: %s' % (self.item, self.user) diff --git a/app/settings.py b/app/settings.py index 0d5222a..aade9f6 100644 --- a/app/settings.py +++ b/app/settings.py @@ -24,6 +24,7 @@ SECRET_KEY = "django-insecure-()6&rdheil=iyz%36dl-fnb)a+*7*^cb%isz6x%fi+ong5#*zz # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True +COMPRESS_ENABLED = True ALLOWED_HOSTS = [] @@ -38,6 +39,9 @@ INSTALLED_APPS = [ "django.contrib.messages", "django.contrib.staticfiles", + 'compressor', + 'sass_processor', + "app", "app.user", "app.item", @@ -118,6 +122,13 @@ USE_TZ = True # https://docs.djangoproject.com/en/4.2/howto/static-files/ STATIC_URL = "static/" +STATIC_ROOT = "www/static" +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + "sass_processor.finders.CssFinder", + "compressor.finders.CompressorFinder", +) # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field diff --git a/app/static/css/comments.css b/app/static/css/comments.css deleted file mode 100644 index 23142a9..0000000 --- a/app/static/css/comments.css +++ /dev/null @@ -1,43 +0,0 @@ - -.comments h3 { - font-weight: bold; - padding: 4px; - padding-left: 0; - margin: 0; - //display: none; -} -.comments.active h3 { - display: block; -} - -.comments .icon svg { - width: 12px; - height: 12px; -} - -.add-comment { - width: 100%; - height: 30vh; - text-align: center; -} -.add-comment input { - width: 100px; -} -.add-comment textarea { - width: 80%; - display: block; - background: black; - color: white; - margin: auto; - padding: 0; - border: 0; -} -.add-comment button { - background: red; - border: 0; -} - -.comment .text { - white-space: pre-line; -} - diff --git a/app/static/css/comments.scss b/app/static/css/comments.scss new file mode 100644 index 0000000..493ce13 --- /dev/null +++ b/app/static/css/comments.scss @@ -0,0 +1,90 @@ + +.comments h3 { + font-weight: bold; + padding: 4px; + padding-left: 0; + margin: 0; + //display: none; +} +.comments.active h3 { + display: block; +} + +.comments .icon svg { + width: 12px; + height: 12px; +} + +.add-comment { + box-sizing: border-box; + width: 100%; + height: 30vh; + padding-top: 8px; + padding-left: 4px; + +} +@media(max-width:768px) { + .add-comment { + padding-left: 4px; + } +} + +.add-comment textarea, +.add-comment input { + padding: 4px; + margin-left: 0; + margin-top: 4px; + margin-bottom: 4px; + margin-right: 4px; + background: none; + color: white; + border: 1px solid green; +} +.add-comment input { + width: calc(50% - 8px); +} +.add-comment textarea { + width: calc(100% - 8px); + height: 100px; + display: block; +} +.add-comment button { + background: black; + color: white; + border: solid 1px green; + padding: 8px; +} +.add-comment button:hover { + border: solid 1px lightgreen; + cursor: pointer; +} +.add-comment { + .buttons { + &.login { + input { + width: calc(25% - 8px); + } + } + } +} + +.comment { + padding: 4px; + border-bottom: 1px solid blueviolet; +} + +.comment .text { + white-space: pre-line; +} + +.comments h3 { + cursor: pointer; +} + +.comments.collapsed .block { + display: none; +} + +.comments .meta { + color: gray; +} diff --git a/app/static/css/site.scss b/app/static/css/site.scss new file mode 100644 index 0000000..4a8e4da --- /dev/null +++ b/app/static/css/site.scss @@ -0,0 +1,52 @@ +header, footer { + max-width: 1000px; + padding-top: 16px; + margin: auto; +} +header { + a { + color: yellow; + text-decoration: none; + } +} + +.index { + padding-top: 16px; + .item { + border-bottom: 1px solid blueviolet; + padding-bottom: 4px; + margin-bottom: 8px; + + a { + text-decoration: none; + color: white; + h1 { + text-decoration: underline; + } + } + h1 { + margin: 0; + padding: 0; + } + h1, .info, .comments { + } + + .image { + padding-top: 4px; + width: 100%; + img { + width: 100%; + aspect-ratio: 16/9; + object-fit: cover; + } + } + .content { + max-width: 1000px; + margin: auto; + } + } + .archive { + text-align: center; + } +} + diff --git a/app/static/css/style.css b/app/static/css/style.css index 811b250..61dbb57 100644 --- a/app/static/css/style.css +++ b/app/static/css/style.css @@ -9,6 +9,16 @@ body { line-height: normal; } +*, *::after, *::before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +*:focus { + outline: none; +} + a { color: rgb(128, 128, 255) } diff --git a/app/static/js/comments.js b/app/static/js/comments.js index b8b8ebd..dd15247 100644 --- a/app/static/js/comments.js +++ b/app/static/js/comments.js @@ -1,26 +1,41 @@ -function renderComments(data) { - var cdiv = div.querySelector('.comments') +function renderComments(cdiv, data) { cdiv.innerHTML = `

${icon.down} Comments

+
+
+
+
` + const content = cdiv.querySelector('.comments-content') comments.forEach(comment => { var c = document.createElement('div') c.className = 'comment' c.innerHTML = ` -
-
${comment.name}
-
${comment.date}
-
${comment.text}
+
${comment.text}
+
+ by ${comment.name} + on + ${comment.date}
` - cdiv.append(c) + content.append(c) }) var add = document.querySelector('.add-comment') add.style.display = 'block' - cdiv.append(add) + cdiv.querySelector('.block').append(add) + cdiv.querySelector('h3').addEventListener("click", event => { + var img = cdiv.querySelector('h3 .icon') + if (cdiv.classList.contains("collapsed")) { + cdiv.classList.remove("collapsed") + img.innerHTML = icon.down + } else { + cdiv.classList.add("collapsed") + img.innerHTML = icon.right + } + }) } document.querySelector('button#add-comment').addEventListener('click', event => { @@ -46,21 +61,20 @@ document.querySelector('button#add-comment').addEventListener('click', event => }).then(response => { return response.json() }).then(response => { - var comment= document.createElement('div') + var comment = document.createElement('div') comment.classList.add('comment') - var name = document.createElement('div') - name.classList.add('name') - name.innerText = response.name - comment.append(name) - var date = document.createElement('div') - date.classList.add('date') - date.innerText = response.date - comment.append(date) - var text = document.createElement('div') - text.classList.add('name') - text.innerText = response.text - comment.append(text) - document.querySelector('.comments').append(comment) + comment.innerHTML = ` +
+
+ by + on + +
+ ` + comment.querySelector('.name').innerText = response.name + comment.querySelector('.date').innerText = response.date + comment.querySelector('.text').innerText = response.text + document.querySelector('.comments .comments-content').append(comment) document.querySelector('.add-comment textarea').value = '' }) }) diff --git a/app/static/js/render.js b/app/static/js/render.js index d9724da..1ae74df 100644 --- a/app/static/js/render.js +++ b/app/static/js/render.js @@ -30,16 +30,17 @@ function renderItem(data) {
-
${data.value}
-
+
+ ${data.value} +
+
` - var comments = div.querySelector('.comments') if (window.renderComments) { - renderComments(comments, data) + renderComments(div.querySelector('.comments'), data) } else { comments.remove() } diff --git a/app/templates/archive.html b/app/templates/archive.html index feaeb05..2207109 100644 --- a/app/templates/archive.html +++ b/app/templates/archive.html @@ -1,25 +1,7 @@ {% extends "base.html" %} {% block content %} {% for item in items %} - + {% include "listitem.html" with item=item %} {% endfor %} {% endblock %} diff --git a/app/templates/base.html b/app/templates/base.html index 6a8eecf..c4ded3f 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -1,7 +1,22 @@ - +{% load static sass_tags compress %} + + +{% compress css file site %} + + + + +{% endcompress %} {% block head %} +{% endblock %} + + +{% block header %} +
+ phantas.ma +
{% endblock %} {% block main %}
@@ -11,5 +26,7 @@ {% endblock %} {% block end %} {% endblock %} - - +{% block footer %} +{% endblock %} + + diff --git a/app/templates/index.html b/app/templates/index.html index 2a84337..5e6ed39 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -1,44 +1,15 @@ {% extends "base.html" %} {% block content %} +
{% for item in items %} - + {% include "listitem.html" with item=item %} {% endfor %} {% if archive %} + {% endif %} +
{% endblock %} diff --git a/app/templates/item.html b/app/templates/item.html index e55da67..19033b0 100644 --- a/app/templates/item.html +++ b/app/templates/item.html @@ -1,27 +1,36 @@ {% extends "base.html" %} +{% load static sass_tags compress %} {% block head %} - - - {% endblock %} {% block main %}
{% endblock %} {% block end %} +{% compress js file m %} @@ -31,6 +40,7 @@ +{% endcompress %}