diff options
author | luxagraf <sng@luxagraf.net> | 2018-12-06 06:57:52 -0600 |
---|---|---|
committer | luxagraf <sng@luxagraf.net> | 2018-12-06 06:57:52 -0600 |
commit | d45fa99aa9d587b5674484f68955b43f39e8f6fd (patch) | |
tree | 29b2b5c14de7a26cc9cfe88ad6e89fec0fbe1cae | |
parent | 45245bc0a9b659ff547ec20eb70af3def4ee7c6f (diff) |
redid tags to use through model, cleaned up note and notebook detail
views
-rw-r--r-- | README.md | 18 | ||||
-rw-r--r-- | apps/notes/forms.py | 2 | ||||
-rw-r--r-- | apps/notes/models.py | 29 | ||||
-rw-r--r-- | apps/notes/serializers.py | 34 | ||||
-rw-r--r-- | apps/notes/tests/test_models.py | 23 | ||||
-rw-r--r-- | apps/notes/tests/test_views.py | 48 | ||||
-rw-r--r-- | apps/notes/urls.py | 23 | ||||
-rw-r--r-- | apps/notes/views.py | 40 | ||||
-rw-r--r-- | design/templates/notes/notebook_create.html | 20 | ||||
-rw-r--r-- | design/templates/notes/notebook_detail.html | 64 | ||||
-rw-r--r-- | design/templates/notes/notes_create.html | 21 | ||||
-rw-r--r-- | design/templates/notes/notes_detail.html | 76 | ||||
-rw-r--r-- | design/templates/notes/notes_list.html | 19 |
13 files changed, 251 insertions, 166 deletions
@@ -41,3 +41,21 @@ Create, edit and view notes ## Art credits <div>Icons made by <a href="https://www.freepik.com/" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div> + +## Features + +### Capture + +### Editing + +### Organizing + +### Surfacing + +### Outlining + +### Archiving + +### Versioning + +### Collaborating diff --git a/apps/notes/forms.py b/apps/notes/forms.py index c1df176..5ef9f84 100644 --- a/apps/notes/forms.py +++ b/apps/notes/forms.py @@ -20,7 +20,7 @@ class NoteForm(forms.ModelForm): class NotebookForm(NoteForm): class Meta: model = Notebook - fields = ['name'] + fields = ['name', 'color_rgb'] labels = { "name": _("Notebook Name"), } diff --git a/apps/notes/models.py b/apps/notes/models.py index c0b23ce..95c1c96 100644 --- a/apps/notes/models.py +++ b/apps/notes/models.py @@ -12,18 +12,36 @@ from django.conf import settings from utils.util import unique_slug_generator +from django.utils.translation import ugettext_lazy as _ + +from taggit.managers import TaggableManager +from taggit.models import TagBase, GenericTaggedItemBase + + +class LuxTag(TagBase): + color_rgb = models.CharField(max_length=20, null=True, blank=True) + + class Meta: + verbose_name = _("Tag") + verbose_name_plural = _("Tags") + + +class TaggedNotes(GenericTaggedItemBase): + tag = models.ForeignKey(LuxTag, related_name="%(app_label)s_%(class)s_items", on_delete=models.CASCADE) + class Notebook(models.Model): + """ Notebook model for Notes """ unique_id = models.UUIDField(default=uuid.uuid4, editable=False) owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) name = models.CharField(max_length=250) - url = models.CharField(max_length=250, null=True, blank=True) + color_rgb = models.CharField(max_length=20, null=True, blank=True) slug = models.SlugField(blank=True) date_created = models.DateTimeField(blank=True, auto_now_add=True, editable=False) date_updated = models.DateTimeField(blank=True, auto_now=True, editable=False) class Meta: - unique_together = ("owner", "slug") + unique_together = ("owner", "name") def __str__(self): return self.name @@ -35,7 +53,7 @@ class Notebook(models.Model): @cached_property def get_absolute_url(self): - return reverse("notes:notebook-detail", kwargs={"user": self.owner.username, "slug": self.slug}) + return reverse("notebooks:detail", kwargs={"slug": self.slug}) class Note(models.Model): @@ -50,18 +68,19 @@ class Note(models.Model): url = models.CharField(max_length=250, null=True, blank=True) slug = models.SlugField(blank=True) notebook = models.ForeignKey(Notebook, null=True, blank=True, on_delete=models.SET_NULL) - tags = TaggableManager(blank=True, help_text='Tags') + tags = TaggableManager(through=TaggedNotes, blank=True, help_text='Tags') is_public = models.BooleanField(default=False) class Meta: unique_together = ("owner", "slug") + ordering = ("-date_created", "-date_updated") def __str__(self): return self.title @cached_property def get_absolute_url(self): - return reverse("notes:note-detail", kwargs={"user": self.owner.username, "slug": self.slug}) + return reverse("notes:detail", kwargs={"slug": self.slug, 'pk': self.pk}) def save(self, **kwargs): if not self.title: diff --git a/apps/notes/serializers.py b/apps/notes/serializers.py index daef52e..f811edd 100644 --- a/apps/notes/serializers.py +++ b/apps/notes/serializers.py @@ -1,11 +1,29 @@ from rest_framework import serializers from taggit_serializer.serializers import TagListSerializerField, TaggitSerializer -from .models import Note, Notebook +from .models import Note, Notebook, LuxTag + +import six + + +class NewTagListSerializerField(TagListSerializerField): + def to_internal_value(self, value): + if isinstance(value, six.string_types): + value = [v.strip() for v in value.split(',')] + + if not isinstance(value, list): + self.fail('not_a_list', input_type=type(value).__name__) + + for s in value: + if not isinstance(s, six.string_types): + self.fail('not_a_str') + + self.child.run_validation(s) + return value class NoteSerializer(TaggitSerializer, serializers.ModelSerializer): - tags = TagListSerializerField() + tags = NewTagListSerializerField(required=False) class Meta: model = Note @@ -14,7 +32,17 @@ class NoteSerializer(TaggitSerializer, serializers.ModelSerializer): class NotebookSerializer(serializers.HyperlinkedModelSerializer): json_absolute_url = serializers.URLField(source='get_absolute_url', read_only=True) + owner = serializers.HiddenField( + default=serializers.CurrentUserDefault() + ) class Meta: model = Notebook - fields = ('name', 'json_absolute_url') + fields = ('name', 'color_rgb', 'json_absolute_url', 'owner') + + +class NoteTagSerializer(serializers.HyperlinkedModelSerializer): + + class Meta: + model = LuxTag + fields = ('name', 'color_hex') diff --git a/apps/notes/tests/test_models.py b/apps/notes/tests/test_models.py index cf21aca..05f2618 100644 --- a/apps/notes/tests/test_models.py +++ b/apps/notes/tests/test_models.py @@ -1,16 +1,26 @@ from django.test import TestCase +from django.urls import reverse +from django.contrib import auth from mixer.backend.django import mixer -from notes.models import Note, Notebook -from accounts.models import User +from notes.models import Note, Notebook + +User = auth.get_user_model() class NotebookModelTest(TestCase): + def setUp(self): + self.user = mixer.blend(User, username='tpynchon') + self.notebook = Notebook(owner=self.user, name="San Miguel Notes") + self.notebook.save() def test_string_representation(self): - user = mixer.blend(User, username='tpynchon') - notebook = Notebook(owner=user, name="San Miguel Notes") - self.assertEqual(str(notebook), "San Miguel Notes") + """Notebook title should be the name of the object""" + self.assertEqual(str(self.notebook), "San Miguel Notes") + + def test_get_absolute_url(self): + """Absolute URL should return /nb/slug """ + self.assertEqual(str(self.notebook.get_absolute_url), reverse("notebooks:detail", kwargs={'slug': self.notebook.slug})) class NoteModelTest(TestCase): @@ -41,4 +51,5 @@ class NoteModelTest(TestCase): self.assertEqual(str(self.note_no_title), str(self.note_no_title.body_text)[:50]) def test_get_absolute_url(self): - self.assertEqual(str(self.note.get_absolute_url), "/notes/%s/%s" % (self.note.owner.username, self.note.slug)) + """Absolute URL should return /n/slug/pk """ + self.assertEqual(str(self.note.get_absolute_url), "/n/%s/%s" % (self.note.slug, self.note.pk)) diff --git a/apps/notes/tests/test_views.py b/apps/notes/tests/test_views.py index 4f9a4ce..be48226 100644 --- a/apps/notes/tests/test_views.py +++ b/apps/notes/tests/test_views.py @@ -1,6 +1,6 @@ import json from django.test import Client -from django.test import RequestFactory, TestCase +from django.test import RequestFactory, TestCase, TransactionTestCase from django.urls import reverse from django.template.defaultfilters import slugify @@ -14,6 +14,37 @@ from notes.models import Note from notes.views import NoteListView, NoteViewSet +class NoteCreateViewTests(TransactionTestCase): + """ + Because I need pks to get URL of object I need + a clean database so I know the one and only object + has a pk of 1. There's probably a better way to do + this though. + Especially because this is a private API and subject + to change/deletion: + https://docs.djangoproject.com/en/2.1/topics/testing/advanced/#django.test.TransactionTestCase.reset_sequences + """ + reset_sequences = True + + def setUp(self): + self.client = Client() + self.user = User.objects.create(username='testuser', password='password') + + def test_note_create_view(self): + data = { + 'pk': 2, + 'title': "test note post", + 'body_text': "the body of the note", + 'url': "https://luxagraf.net/", + 'tags': [], + } + self.client.force_login(self.user) + url = reverse("notes:create") + response = self.client.post(url, data) + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, '/n/%s/%s' % (slugify(data['title']), Note.objects.count())) + + class NotesViewsTest(TestCase): def setUp(self): # Every test needs access to the request factory. @@ -35,25 +66,12 @@ class NotesViewsTest(TestCase): self.note.save() def test_list_view(self): - request = self.factory.get('/notes/') + request = self.factory.get('/n/') request.user = self.user response = NoteListView.as_view()(request) self.assertEqual(response.status_code, 200) # bad_user - def test_note_create_view(self): - data = { - 'title': "test note post", - 'body_text': "the body of the note", - 'url': "https://luxagraf.net/", - 'tags': [], - } - self.client.force_login(self.user) - url = reverse("notes:note-create") - response = self.client.post(url, data) - self.assertEqual(response.status_code, 302) - self.assertRedirects(response, '/notes/%s/%s' % (self.user.username, slugify(data['title']))) - def test_api_list(self): # Make an authenticated request to the view... request = self.factory.get('/api/notes/') diff --git a/apps/notes/urls.py b/apps/notes/urls.py deleted file mode 100644 index a79c7cd..0000000 --- a/apps/notes/urls.py +++ /dev/null @@ -1,23 +0,0 @@ -from django.urls import path - -from .views import ( - NoteDetailView, - NoteCreateView, - NoteListView, - NoteListRedirectView, - NotebookListView, - NotebookDetailView, - NoteTagView, -) - -app_name = "notes" - -urlpatterns = [ - path(r'create/', NoteCreateView.as_view(), name='note-create',), - path(r'<str:user>/tagged/<slug>', NoteTagView.as_view(), name='note-tag',), - path(r'<str:user>/notebooks/<slug>', NotebookDetailView.as_view(), name='notebook-detail',), - path(r'<str:user>/notebooks/', NotebookListView.as_view(), name='notebook-list',), - path(r'<str:user>/<slug>', NoteDetailView.as_view(), name='note-detail',), - path(r'<str:user>/', NoteListView.as_view(), name='note-list',), - path(r'', NoteListRedirectView.as_view(), name='note-redirect',), -] diff --git a/apps/notes/views.py b/apps/notes/views.py index d885ad9..5d55720 100644 --- a/apps/notes/views.py +++ b/apps/notes/views.py @@ -11,8 +11,8 @@ from rest_framework.response import Response from rest_framework.decorators import list_route from rest_framework import permissions -from .serializers import NoteSerializer, NotebookSerializer -from .models import Note, Notebook +from .serializers import NoteSerializer, NotebookSerializer, NoteTagSerializer +from .models import Note, Notebook, LuxTag from .forms import NoteForm, NotebookForm @@ -43,7 +43,7 @@ class NoteListView(LoggedInViewWithUser, ListView): class NoteTagView(LoggedInViewWithUser, ListView): model = Note template_name = 'notes/notes_list.html' - + def get_queryset(self): ''' This can generate a crazy amount of joins if there's a lot of tags @@ -69,12 +69,6 @@ class NoteTagView(LoggedInViewWithUser, ListView): return context -class NoteListRedirectView(RedirectView, LoggedInViewWithUser): - - def get_redirect_url(self, *args, **kwargs): - return reverse_lazy("notes:note-list", kwargs={"user": self.request.user.username}) - - class NoteDetailView(UpdateView, LoggedInViewWithUser): model = Note form_class = NoteForm @@ -101,7 +95,12 @@ class NoteCreateView(CreateView, LoggedInViewWithUser): return super(NoteCreateView, self).form_valid(form) def get_success_url(self): - return reverse_lazy('notes:note-detail', kwargs={'user': self.request.user.username, 'slug': self.object.slug}) + return reverse_lazy('notes:detail', kwargs={'slug': self.object.slug, 'pk': self.object.pk}) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['notes_list'] = Note.objects.filter(owner=self.request.user).select_related() + return context class NotebookListView(CreateView, LoggedInViewWithUser): @@ -124,11 +123,14 @@ class NotebookDetailView(DetailView, LoggedInViewWithUser): model = Notebook def get_object(self): - return get_object_or_404(self.get_queryset().select_related(), owner=self.request.user, slug=self.kwargs["slug"]) + notebook = get_object_or_404(self.get_queryset().select_related(), owner=self.request.user, slug=self.kwargs["slug"]) + self.form = NotebookForm(instance=notebook) + return notebook def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['notes_list'] = Note.objects.filter(owner=self.request.user).select_related() + context['form'] = self.form return context @@ -153,7 +155,7 @@ class NoteViewSet(viewsets.ModelViewSet): return Note.objects.filter(owner=self.request.user).order_by('-date_created') def perform_create(self, serializer): - serializer.save(owner=self.request.user) + serializer.save(owner=self.request.user, tags__owner=self.request.user) def get_object(self): obj = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"]) @@ -178,3 +180,17 @@ class NotebookViewSet(viewsets.ModelViewSet): def get_menu_data(self, serializer): return Notebook.objects.filter(owner=self.request.user).order_by('-name')[:1] + + +class TagViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows notes to be viewed or edited. + """ + serializer_class = NoteTagSerializer + permission_classes = (permissions.IsAuthenticated,) + + def get_queryset(self): + return LuxTag.objects.filter(owner=self.request.user) + + def perform_create(self, serializer): + serializer.save(owner=self.request.user) diff --git a/design/templates/notes/notebook_create.html b/design/templates/notes/notebook_create.html index 8ffc94a..1386946 100644 --- a/design/templates/notes/notebook_create.html +++ b/design/templates/notes/notebook_create.html @@ -2,6 +2,7 @@ {% block extrastyles %} <link rel="stylesheet" href="/media/quill.snow.css" /> +<script async src="/media/js/vanilla-picker.min.js"></script> {% endblock %} {% block content %} <main> @@ -10,34 +11,23 @@ {% csrf_token %} {{ form.non_field_errors }} {% for field in form %} -<fieldset class="{% if field.errors %}error {%endif%}{% if field.name == 'body_qjson' or field.name == 'body_html' %}hide {%endif%}" id="fs-{{field.name}}" > +<fieldset class="{% if field.errors %}error {%endif%}{% if field.name == 'color_hex' %}hide {%endif%}" id="fs-{{field.name}}" > {{field.label_tag}} {{field}} {% if field.errors %}{{field.errors}}{% endif %} </fieldset> {% endfor %} +<p id="color-picker"><a href="#">Pick color</a></p> <p><input class="btn btn-inline" value="create" type="submit" /></p> </form> <ul>{% for object in notebook_list %} <li> - <a href="{% url 'notes:notebook-detail' user.username object.slug %}"><i class="icon-notebook"> </i>{{object.name}}</a> + <a href="{% url 'notebooks:detail' object.slug %}"><i class="icon-notebook"> </i>{{object.name}}</a> </li> {%endfor%}</ul> </article> <aside class="note-list-container"> - <div class="svg-wrapper"><svg class="svg-icon-arrow"> - <svg viewBox="0 0 16 13" id="shape-double-arrow" width="100%" height="100%"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="square"><g id="Showing-post-info" transform="translate(-297.000000, -105.000000)" stroke="currentColor"><g transform="translate(305.000000, 111.500000) scale(-1, 1) rotate(-180.000000) translate(-305.000000, -111.500000) translate(297.000000, 105.000000)"><path d="M2.20710678,6.5 L6.85355339,1.85355339 L7.20710678,1.5 L6.5,0.792893219 L6.14644661,1.14644661 L1.14644661,6.14644661 L1.05805826,6.23483496 L0.792893219,6.5 L1.14644661,6.85355339 L6.14644661,11.8535534 L6.5,12.2071068 L7.20710678,11.5 L6.85355339,11.1464466 L2.20710678,6.5 Z" id="Combined-Shape"></path><path d="M10.2071068,6.5 L14.8535534,1.85355339 L15.2071068,1.5 L14.5,0.792893219 L14.1464466,1.14644661 L9.14644661,6.14644661 L9.05805826,6.23483496 L8.79289322,6.5 L9.14644661,6.85355339 L14.1464466,11.8535534 L14.5,12.2071068 L15.2071068,11.5 L14.8535534,11.1464466 L10.2071068,6.5 Z" id="Combined-Shape"></path></g></g></g></svg> - </svg></div> - <div class=""> - <ul class="list-note-preview">{% for obj in notes_list %} - <li> - <a href="{% url 'notes:note-detail' user.username obj.slug %}"> - <h4>{{obj.title}}</h4> - <div class="note-preview">{{obj.body_text|truncatewords:12}}</div> - </a> - </li> - {% endfor %}</ul> - </div> + {% include "notes/partials/note_sidebar.html" with note_list=note_list %} </aside> <div class="balance-container"> </div> diff --git a/design/templates/notes/notebook_detail.html b/design/templates/notes/notebook_detail.html index 36873e1..a0b06a3 100644 --- a/design/templates/notes/notebook_detail.html +++ b/design/templates/notes/notebook_detail.html @@ -1,49 +1,59 @@ {% extends 'base.html' %} +{% block extrastyles %} +<script async src="/media/js/vanilla-picker.min.js"></script> +{% endblock %} + {% block content %} <main> - <article class="note-container"> - {%comment%} - <form id="new-note-form" action="{% url 'notebook-api-list' %}" method="post"> + <article class="note-container single-col"> + <div class="flex-wrapper"> + <form id="nb-edit-form" action="{% url 'notebook-api-detail' object.pk %}" method="PATCH">{% csrf_token %} + {{ form.non_field_errors }} + + <div class="flex-wrapper flex-inner"> + {% for field in form %}{% if field.name == 'color_rgb' %} + <fieldset class="color-picker-fieldset" id="color-picker" {% if form.instance.color_rgb %}style="background-color: {{form.instance.color_rgb}}; border: none;"{%endif%}> + <input type="text" name="color_rgb" value="{{form.instance.color_rgb}}" maxlength="20" id="id_color_rgb"> + {% if field.errors %}{{field.errors}}{% endif %} + </fieldset>{% else %} + <fieldset class="hide"> + {{field.label_tag}} + {{field}} + {% if field.errors %}{{field.errors}}{% endif %} + </fieldset>{% endif %} + {% endfor %} + <h1 class="notebook-title" id="nb-title">{{object.name}}</h1> + </div> + <input id="btn-js-hide" type="submit" class="btn sm" value="Save" > + </form> + <div class="edit-btn-wrapper"><a class="hide btn btn-hollow" id="edit-toggle-btn">Edit</a></div> + </div> + + <form id="new-note-form" action="{% url 'notebook-api-list' %}" method="post" class="hide"> <label>Create a new notebook</label> {% csrf_token %} {{ form.non_field_errors }} {% for field in form %} - <fieldset class="{% if field.errors %}error {%endif%}{% if field.name == 'body_qjson' or field.name == 'body_html' %}hide {%endif%}" id="fs-{{field.name}}" > + <fieldset class="" id="fs-{{field.name}}" > {{field.label_tag}} {{field}} {% if field.errors %}{{field.errors}}{% endif %} </fieldset> {% endfor %} - <p><input class="btn btn-inline" value="create" type="submit" /></p> + <p><input id="btn-js-hide" class="btn btn-inline" value="create" type="submit" /></p> </form> - {%endcomment%} -{{object}} - <ul class="list-note-preview">{% for obj in object.note_set.all %} - <li> - <a href="{% url 'notes:note-detail' user.username obj.slug %}"> - <h4>{{obj.title}}</h4> - <div class="note-preview">{{obj.body_text|truncatewords:36}}</div> - </a> - </li> + <ul class="list-note-preview">{% for object in object.note_set.all %} + {% include "notes/partials/note_list.html" with object=object hidecolor=True hidenotebook=True %} {% endfor %}</ul> </article> <aside class="note-list-container"> - <div class="svg-wrapper"><svg class="svg-icon-arrow"> - <svg viewBox="0 0 16 13" id="shape-double-arrow" width="100%" height="100%"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="square"><g id="Showing-post-info" transform="translate(-297.000000, -105.000000)" stroke="currentColor"><g transform="translate(305.000000, 111.500000) scale(-1, 1) rotate(-180.000000) translate(-305.000000, -111.500000) translate(297.000000, 105.000000)"><path d="M2.20710678,6.5 L6.85355339,1.85355339 L7.20710678,1.5 L6.5,0.792893219 L6.14644661,1.14644661 L1.14644661,6.14644661 L1.05805826,6.23483496 L0.792893219,6.5 L1.14644661,6.85355339 L6.14644661,11.8535534 L6.5,12.2071068 L7.20710678,11.5 L6.85355339,11.1464466 L2.20710678,6.5 Z" id="Combined-Shape"></path><path d="M10.2071068,6.5 L14.8535534,1.85355339 L15.2071068,1.5 L14.5,0.792893219 L14.1464466,1.14644661 L9.14644661,6.14644661 L9.05805826,6.23483496 L8.79289322,6.5 L9.14644661,6.85355339 L14.1464466,11.8535534 L14.5,12.2071068 L15.2071068,11.5 L14.8535534,11.1464466 L10.2071068,6.5 Z" id="Combined-Shape"></path></g></g></g></svg> - </svg></div> - <div class=""> - <ul class="list-note-preview">{% for obj in notes_list %} - <li> - <a href="{% url 'notes:note-detail' user.username obj.slug %}"> - <h4>{{obj.title}}</h4> - <div class="note-preview">{{obj.body_text|truncatewords:12}}</div> - </a> - </li> - {% endfor %}</ul> - </div> + {% include "notes/partials/note_sidebar.html" with note_list=note_list %} </aside> <div class="balance-container"> </div> </main> {% endblock %} +{% block jsdomready %} +window.url = "{% url 'notebook-api-detail' object.pk %}"; +{%endblock%} diff --git a/design/templates/notes/notes_create.html b/design/templates/notes/notes_create.html index 9bbdb26..9ca4111 100644 --- a/design/templates/notes/notes_create.html +++ b/design/templates/notes/notes_create.html @@ -5,8 +5,9 @@ {% endblock %} {% block content %} <main> + <article class="note-container"> <h1>Create a new note</h1> - <form id="new-note-form" action="{% url 'notes:note-create' %}" method="post"> + <form id="new-note-form" action="{% url 'notes:create' %}" method="post"> {% csrf_token %} {{ form.non_field_errors }} {% for field in form %} @@ -23,6 +24,24 @@ {% endfor %} <p><input class="btn btn-inline" value="submit" type="submit" /></p> </form> +</article> + <aside class="note-list-container"> + <div class="svg-wrapper"><svg class="svg-icon-arrow"> + <svg viewBox="0 0 16 13" id="shape-double-arrow" width="100%" height="100%"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="square"><g id="Showing-post-info" transform="translate(-297.000000, -105.000000)" stroke="currentColor"><g transform="translate(305.000000, 111.500000) scale(-1, 1) rotate(-180.000000) translate(-305.000000, -111.500000) translate(297.000000, 105.000000)"><path d="M2.20710678,6.5 L6.85355339,1.85355339 L7.20710678,1.5 L6.5,0.792893219 L6.14644661,1.14644661 L1.14644661,6.14644661 L1.05805826,6.23483496 L0.792893219,6.5 L1.14644661,6.85355339 L6.14644661,11.8535534 L6.5,12.2071068 L7.20710678,11.5 L6.85355339,11.1464466 L2.20710678,6.5 Z" id="Combined-Shape"></path><path d="M10.2071068,6.5 L14.8535534,1.85355339 L15.2071068,1.5 L14.5,0.792893219 L14.1464466,1.14644661 L9.14644661,6.14644661 L9.05805826,6.23483496 L8.79289322,6.5 L9.14644661,6.85355339 L14.1464466,11.8535534 L14.5,12.2071068 L15.2071068,11.5 L14.8535534,11.1464466 L10.2071068,6.5 Z" id="Combined-Shape"></path></g></g></g></svg> + </svg></div> + <div class=""> + <ul class="list-note-preview">{% for obj in notes_list %} + <li> + <a href="{% url 'notes:detail' user.username obj.slug %}"> + <h4>{{obj.title}}</h4> + <div class="note-preview">{{obj.body_text|truncatewords:12}}</div> + </a> + </li> + {% endfor %}</ul> + </div> + </aside> + <div class="balance-container"> + </div> </main> {% endblock %} diff --git a/design/templates/notes/notes_detail.html b/design/templates/notes/notes_detail.html index 95583bd..b2ddbc3 100644 --- a/design/templates/notes/notes_detail.html +++ b/design/templates/notes/notes_detail.html @@ -2,26 +2,38 @@ {% block extrastyles %} <link rel="stylesheet" href="/media/quill.snow.css" /> {% endblock %} -{% block breadcrumbs %} -<li><a href="{%url 'notes:note-list' user.username %}">Notes</a></li> -{% endblock %} - {% block content %} <main> <article class="note-container"> + <form action="" method="post" id="note-edit-form">{% csrf_token %} <header class="note-header"> <div class="note-header-left"> - <span class="label">tags:</span> - <ul>{% for tag in object.tags.all %} - <li> - <a href="{% url 'notes:note-tag' user.username tag.slug %}">{{tag}}</a> - </li> - {%endfor%}</ul> - <div class="notebook"> - <span class="label">notebook:</span> - <a href="">{{object.notebook.name}}</a> - </div> + + <div class="flex-wrapper"> + <div class="notebook"> + <a id="n-link" href="{% url 'notebooks:detail' object.slug %}"><span id="n-box" class="color-box" style="background-color: {{object.notebook.color_rgb}}"></span><span id="n-name">{{object.notebook}}</span></a> + <div id="notebook-edit" class="hide"> + <span class="error">{{ form.notebook.errors }}</span> + {{form.notebook}} + </div> + </div> + <div class="tags"> + <span class="label">tags:</span> + <div id="t-display" class="">{% for tag in object.tags.all %} + <a class="t-link" href="{% url 'notes:tags' tag.slug %}"> + <span class="tag-wrapper" data-bg-color="#{{tag.color_color_rgb}};" >{{tag}}</span> + </a>{%endfor%} + </div> + <div id="tags-edit" class="hide"> + <span class="error">{{ form.notebook.errors }}</span> + {{form.tags}} + </div> + </div> + </div> + </div> + <div class="hide">{{form.body_text}}</div> + <fieldset class="hide">{{form.title}}</fieldset> <div class="note-header-right"> <h2 class="note-time">{{object.date_created|date:"M d, Y"}}</h2> {% if object.url %}<h3 class="note-url"><a class="btn btn-small btn-subtle" href="{{object.url}}">Source</a><a class="btn btn-small btn-subtle right-padding-0 left-margin-2" href="object.cache">Archive</a></h3>{% endif %} @@ -30,10 +42,6 @@ <div class="edit-btn-wrapper"><button class="hide btn btn-hollow" id="edit-toggle-btn">Edit</button></div> <h1 id="note-title" class="note-title">{{object.title}}</h1> <div id="q-container" class="inactive"><div id="note-body">{% if object.body_html %}{{object.body_html|safe}}{%else%}{{object.body_text}}{%endif%}</div></div> - <form action="" method="post" id="note-edit-form">{% csrf_token %} - {% for field in form %}{% if field.name in "title body_text" %} - <div class="hide">{{field}}</div> - {% endif%}{% endfor %} <input id="btn-js-hide" type="submit" class="btn sm" value="Save" > </form> </article> @@ -44,7 +52,7 @@ <div class=""> <ul class="list-note-preview">{% for obj in notes_list %} <li> - <a href="{% url 'notes:note-detail' user.username obj.slug %}"> + <a href="{% url 'notes:detail' obj.slug obj.pk %}"> <h4>{{obj.title}}</h4> <div class="note-preview">{{obj.body_text|truncatewords:12}}</div> </a> @@ -71,34 +79,6 @@ document.addEventListener('readystatechange', event => { }); </script> {% endblock %} - <script> {% block jsdomready %} - var btn = document.getElementById("edit-toggle-btn"), - qcontainer = document.getElementById('q-container'), - title = document.getElementById('note-title'), - form = document.getElementById('note-edit-form'), - note_html = document.createElement('textarea'), - note_qjson = document.createElement('textarea'); - - window.editing = false; - window.quillchange = false; - - hljs.initHighlightingOnLoad(); - btn.classList.remove('hide'); - note_html.setAttribute('name', 'body_html'); - note_html.setAttribute('class', 'hide'); - note_html.setAttribute('id', 'id_body_html'); - note_qjson.setAttribute('name', 'body_qjson'); - note_qjson.setAttribute('id', 'id_body_qjson'); - note_qjson.setAttribute('class', 'hide'); - form.appendChild(note_html); - form.appendChild(note_qjson); - document.getElementById("btn-js-hide").classList.add("hide"); - btn.addEventListener('click', function(){edit_note(this, title, qcontainer, window.quill, "{% url 'notes-api-detail' object.pk %}" )}, false) +window.url = "{% url 'notes-api-detail' object.pk %}"; {%endblock%} - </script> - -'indent -'align -'direction -'code-block diff --git a/design/templates/notes/notes_list.html b/design/templates/notes/notes_list.html index b1c1700..393cf89 100644 --- a/design/templates/notes/notes_list.html +++ b/design/templates/notes/notes_list.html @@ -4,16 +4,11 @@ <main> <article class="note-container"> <h1>Notes {% if tags|length == 1%} tagged {% for tag in tags%}{{tag}}{%endfor%}{%endif%}</h1> - <div>Tagged with: {% for tag in tags%}<a href="{{tag|slugify}}">{{tag}}</a>{%endfor%}</div> - <ul class="list-note-preview">{% for obj in object_list %} - <li> - <a href="{% url 'notes:note-detail' user.username obj.slug %}"> - <h4>{{obj.title}}</h4> - <div class="note-preview">{{obj.body_text|truncatewords:36}}</div> - </a> - </li> + {% if tags|length >= 1%}<div>Tagged with: {% for tag in tags%}<a href="{{tag|slugify}}">{{tag}}</a>{%endfor%}</div>{%endif%} + <ul class="list-note-preview">{% for object in object_list %} + {% include "notes/partials/note_list.html" with object=object %} {% endfor %}</ul> - </article> + </article>{% if tags|length >= 1%} <aside class="note-list-container"> <div class="svg-wrapper"><svg class="svg-icon-arrow"> <svg viewBox="0 0 16 13" id="shape-double-arrow" width="100%" height="100%"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="square"><g id="Showing-post-info" transform="translate(-297.000000, -105.000000)" stroke="currentColor"><g transform="translate(305.000000, 111.500000) scale(-1, 1) rotate(-180.000000) translate(-305.000000, -111.500000) translate(297.000000, 105.000000)"><path d="M2.20710678,6.5 L6.85355339,1.85355339 L7.20710678,1.5 L6.5,0.792893219 L6.14644661,1.14644661 L1.14644661,6.14644661 L1.05805826,6.23483496 L0.792893219,6.5 L1.14644661,6.85355339 L6.14644661,11.8535534 L6.5,12.2071068 L7.20710678,11.5 L6.85355339,11.1464466 L2.20710678,6.5 Z" id="Combined-Shape"></path><path d="M10.2071068,6.5 L14.8535534,1.85355339 L15.2071068,1.5 L14.5,0.792893219 L14.1464466,1.14644661 L9.14644661,6.14644661 L9.05805826,6.23483496 L8.79289322,6.5 L9.14644661,6.85355339 L14.1464466,11.8535534 L14.5,12.2071068 L15.2071068,11.5 L14.8535534,11.1464466 L10.2071068,6.5 Z" id="Combined-Shape"></path></g></g></g></svg> @@ -21,7 +16,7 @@ <div class=""> <ul class="list-note-preview">{% for obj in notes_list %} <li> - <a href="{% url 'notes:note-detail' user.username obj.slug %}"> + <a href="{% url 'notes:detail' obj.slug obj.pk %}"> <h4>{{obj.title}}</h4> <div class="note-preview">{{obj.body_text|truncatewords:12}}</div> </a> @@ -29,6 +24,10 @@ {% endfor %}</ul> </div> </aside> + {%else%} + <div class="balance-container-left"> + </div> + {%endif%} <div class="balance-container"> </div> </main> |