diff options
author | luxagraf <sng@luxagraf.net> | 2019-01-05 09:50:21 -0600 |
---|---|---|
committer | luxagraf <sng@luxagraf.net> | 2019-01-05 09:50:21 -0600 |
commit | d5f430d3e1e2b274d8d8f744251e8b6b4b72ebd9 (patch) | |
tree | 094404cdf4eaba53b1e225b54212679f6f032afd | |
parent | 23b4b185e3f3f8b9f17eebc49110cb4696acdb39 (diff) |
changed to custom modal, added saving animation for note editing.
25 files changed, 344 insertions, 94 deletions
@@ -1,16 +1,20 @@ ## Note and Notebooks - * add defailt "trash" notebook and note manager to not show notes in the trash. - * add delete note option to list and detail views + * side by side note view for comparing/adding annotations + * add delete note option to list * notebook main -- add form for editing all notebooks - * add loading animation when saving, hide when done. * add search to notebook list on create and edit note pages + * covert notebook and tag menus to searchable dropdown + - menu default as an overflow div maybe? Select list? + - hide select list with JS, pull data into div + - add event to button to reveal menu + - add input box to top of menu for search + - make search hide menu items as you search + - make return open link ## Accounts - * port modal login to new modal system * make settings actually editable * add settings for showing color - * which editor??? * hook into groups to see if user is allowed to add more notebooks * add payment via stripe @@ -23,3 +27,11 @@ ## Outlines + +# Done + * port modal login to new modal system + * add defailt "trash" notebook and note manager to not show notes in the trash. + * refactor models to get rid of null on TextFields + * add loading animation when saving, hide when done. + - need new type of modal with no close btn + - need to be resizeable diff --git a/apps/accounts/models.py b/apps/accounts/models.py index d000e3e..1b62ffd 100644 --- a/apps/accounts/models.py +++ b/apps/accounts/models.py @@ -26,4 +26,4 @@ class UserProfile(models.Model): @cached_property def get_notebook_list(self): - return Notebook.objects.filter(owner=self.user).select_related()[:8] + return Notebook.objects.filter(owner=self.user).select_related().annotate(note_count=models.Count('note'))[:8] diff --git a/apps/accounts/signals.py b/apps/accounts/signals.py index 837a7ed..7c7f7c9 100644 --- a/apps/accounts/signals.py +++ b/apps/accounts/signals.py @@ -2,6 +2,7 @@ from django.db.models.signals import post_save from django.dispatch import receiver from .models import User, UserProfile +from notes.models import Notebook @receiver(post_save, sender=User) @@ -10,3 +11,5 @@ def create_profile(sender, update_fields, created, instance, **kwargs): if created: user_profile = UserProfile.objects.create(user=instance) user_profile.save() + user_trash_notebook = Notebook.objects.create(owner=instance, name="Trash") + user_trash_notebook.save() diff --git a/apps/notes/migrations/0014_auto_20190104_1945.py b/apps/notes/migrations/0014_auto_20190104_1945.py new file mode 100644 index 0000000..42398a3 --- /dev/null +++ b/apps/notes/migrations/0014_auto_20190104_1945.py @@ -0,0 +1,56 @@ +# Generated by Django 2.1.2 on 2019-01-05 01:45 + +from django.db import migrations, models +import django.db.models.manager + + +class Migration(migrations.Migration): + + dependencies = [ + ('notes', '0013_remove_luxtag_owner'), + ] + + operations = [ + migrations.AlterModelManagers( + name='note', + managers=[ + ('include_trash', django.db.models.manager.Manager()), + ], + ), + migrations.AlterModelManagers( + name='notebook', + managers=[ + ('include_trash', django.db.models.manager.Manager()), + ], + ), + migrations.AlterField( + model_name='annotation', + name='body_html', + field=models.TextField(blank=True, default=''), + preserve_default=False, + ), + migrations.AlterField( + model_name='annotation', + name='body_text', + field=models.TextField(blank=True, default=''), + preserve_default=False, + ), + migrations.AlterField( + model_name='annotation', + name='highlight_text', + field=models.TextField(blank=True, default=''), + preserve_default=False, + ), + migrations.AlterField( + model_name='note', + name='body_html', + field=models.TextField(blank=True, default=''), + preserve_default=False, + ), + migrations.AlterField( + model_name='note', + name='body_text', + field=models.TextField(blank=True, default=''), + preserve_default=False, + ), + ] diff --git a/apps/notes/migrations/0015_auto_20190104_1946.py b/apps/notes/migrations/0015_auto_20190104_1946.py new file mode 100644 index 0000000..542dfc6 --- /dev/null +++ b/apps/notes/migrations/0015_auto_20190104_1946.py @@ -0,0 +1,31 @@ +# Generated by Django 2.1.2 on 2019-01-05 01:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('notes', '0014_auto_20190104_1945'), + ] + + operations = [ + migrations.AlterField( + model_name='luxtag', + name='color_rgb', + field=models.CharField(blank=True, default='', max_length=20), + preserve_default=False, + ), + migrations.AlterField( + model_name='note', + name='url', + field=models.CharField(blank=True, default='', max_length=250), + preserve_default=False, + ), + migrations.AlterField( + model_name='notebook', + name='color_rgb', + field=models.CharField(blank=True, default='', max_length=20), + preserve_default=False, + ), + ] diff --git a/apps/notes/models.py b/apps/notes/models.py index 9dc4f13..bfcb8ba 100644 --- a/apps/notes/models.py +++ b/apps/notes/models.py @@ -19,7 +19,7 @@ from taggit.models import TagBase, GenericTaggedItemBase class LuxTag(TagBase): - color_rgb = models.CharField(max_length=20, null=True, blank=True) + color_rgb = models.CharField(max_length=20, blank=True) class Meta: verbose_name = _("Tag") @@ -34,16 +34,24 @@ class TaggedNotes(GenericTaggedItemBase): tag = models.ForeignKey(LuxTag, related_name="%(app_label)s_%(class)s_items", on_delete=models.CASCADE) +class NotebookManager(models.Manager): + def get_queryset(self): + return super().get_queryset().exclude(name='Trash') + + 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) - color_rgb = models.CharField(max_length=20, null=True, blank=True) + color_rgb = models.CharField(max_length=20, 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) + include_trash = models.Manager() + objects = NotebookManager() # The default manager never shows the Notebook 'Trash' + class Meta: unique_together = ("owner", "name") @@ -69,21 +77,29 @@ class Notebook(models.Model): return rgba +class NoteManager(models.Manager): + def get_queryset(self): + return super().get_queryset().exclude(notebook__name='Trash') + + class Note(models.Model): unique_id = models.UUIDField(default=uuid.uuid4, editable=False) owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) date_created = models.DateTimeField(blank=True, auto_now_add=True, editable=False) date_updated = models.DateTimeField(blank=True, auto_now=True, editable=False) title = models.CharField(max_length=250) - body_text = models.TextField(null=True) - body_html = models.TextField(null=True, blank=True) + body_text = models.TextField(blank=True) + body_html = models.TextField(blank=True) body_qjson = JSONField(null=True, blank=True) - url = models.CharField(max_length=250, null=True, blank=True) + url = models.CharField(max_length=250, blank=True) slug = models.SlugField(blank=True) notebook = models.ForeignKey(Notebook, null=True, blank=True, on_delete=models.SET_NULL) tags = TaggableManager(through=TaggedNotes, blank=True, help_text='Tags') is_public = models.BooleanField(default=False) + include_trash = models.Manager() + objects = NoteManager() # The default manager never shows the notes in 'Trash' + class Meta: unique_together = ("owner", "slug") ordering = ("-date_created", "-date_updated") @@ -108,9 +124,9 @@ class Annotation(models.Model): owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) date_created = models.DateTimeField(blank=True, auto_now_add=True, editable=False) date_updated = models.DateTimeField(blank=True, auto_now=True, editable=False) - highlight_text = models.TextField(null=True) - body_text = models.TextField(null=True) - body_html = models.TextField(null=True, blank=True) + highlight_text = models.TextField(blank=True) + body_text = models.TextField(blank=True) + body_html = models.TextField(blank=True) body_qjson = JSONField(null=True, blank=True) note = models.ForeignKey(Note, null=True, blank=True, on_delete=models.SET_NULL) is_public = models.BooleanField(default=False) diff --git a/apps/notes/views.py b/apps/notes/views.py index 6751340..245e2ab 100644 --- a/apps/notes/views.py +++ b/apps/notes/views.py @@ -8,6 +8,7 @@ from django.db.models import Count from django.views.generic.base import RedirectView from django.utils.decorators import method_decorator from django.contrib.auth.decorators import login_required +from django.contrib import messages from django.shortcuts import get_object_or_404, render, redirect from django.urls import reverse, reverse_lazy @@ -59,7 +60,7 @@ class NoteListView(BaseListView): def get_context_data(self, **kwargs): context = super(NoteListView, self).get_context_data(**kwargs) - context['notebook_list'] = Notebook.objects.filter(owner=self.request.user).exclude(name="Trash").annotate(note_count=Count('note')) + context['notebook_list'] = Notebook.objects.filter(owner=self.request.user).annotate(note_count=Count('note')) context['tag_list'] = LuxTag.objects.filter(note__owner=self.request.user).annotate(note_count=Count('note')) return context @@ -89,13 +90,19 @@ class NoteDetailView(LoggedInViewWithUser, AjaxableResponseMixin, UpdateView): return context def form_valid(self, form): - self.object = form.save() - tags = serializers.serialize("json", self.object.tags.all()) - data = { - 'tags': tags, - 'notebook': {'name': self.object.notebook.name, 'color': self.object.notebook.color_rgb} - } - return JsonResponse(data, safe=True) + if "trash" in self.request.POST: + form.instance.notebook = Notebook.include_trash.get(owner=self.request.user, name="Trash") + self.object = form.save() + messages.info(self.request, 'The note %s was moved to the trash. <a href="/nb/trash">View trash</a>' % (self.object.title), extra_tags='safe') + return redirect('notes:list') + else: + self.object = form.save() + tags = serializers.serialize("json", self.object.tags.all()) + data = { + 'tags': tags, + 'notebook': {'name': self.object.notebook.name, 'color': self.object.notebook.color_rgb} + } + return JsonResponse(data, safe=True) class NoteCreateView(LoggedInViewWithUser, CreateView): @@ -173,7 +180,7 @@ class NotebookListView(LoggedInViewWithUser, CreateView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) NotebookFormSet = modelformset_factory(Notebook, form=NotebookForm, extra=0) - context['notebook_form_list'] = NotebookFormSet(queryset=Notebook.objects.filter(owner=self.request.user).exclude(name="Trash").select_related().annotate(note_count=Count('note'))) + context['notebook_form_list'] = NotebookFormSet(queryset=Notebook.objects.filter(owner=self.request.user).select_related().annotate(note_count=Count('note'))) #context['notebook_list'] = Notebook.objects.filter(owner=self.request.user).exclude(name="Trash").select_related().annotate(note_count=Count('note')) #context['notes_list'] = Note.objects.filter(owner=self.request.user).select_related() return context @@ -185,6 +192,13 @@ class NotebookListView(LoggedInViewWithUser, CreateView): class NotebookDetailView(BaseDetailView): model = Notebook + def get_queryset(self): + if not self.request.user.is_anonymous: + if self.kwargs["slug"] == 'trash': + return Notebook.include_trash.filter(owner=self.request.user) + else: + return Notebook.objects.filter(owner=self.request.user) + def get_object(self): notebook = get_object_or_404(self.get_queryset().select_related(), owner=self.request.user, slug=self.kwargs["slug"]) self.form = NotebookForm(instance=notebook) diff --git a/apps/utils/widgets.py b/apps/utils/widgets.py index 2745932..6dc28bf 100644 --- a/apps/utils/widgets.py +++ b/apps/utils/widgets.py @@ -142,10 +142,12 @@ class RelatedFieldWidgetCanAdd(widgets.Select): rel_to = related_model info = (rel_to._meta.app_label, rel_to._meta.object_name.lower()) related_url = 'admin:%s_%s_add' % info + print(related_url) self.related_url = related_url def render(self, name, value, *args, **kwargs): self.related_url = reverse(self.related_url) + print(self.related_url) output = [super(RelatedFieldWidgetCanAdd, self).render(name, value, *args, **kwargs)] output.append('<a class="circle plus small-circle modal-open" href="%s" id="add_id_%s" data-modal-hed-class="%s" data-modal-hed="Add a New %s">New</a>' % (self.related_url, name, name, name.capitalize())) return mark_safe(u''.join(output)) diff --git a/design/sass/_fonts.scss b/design/sass/_fonts.scss index dfe632a..5ea0e6e 100644 --- a/design/sass/_fonts.scss +++ b/design/sass/_fonts.scss @@ -1,10 +1,7 @@ @font-face { - font-family: 'carrois_gothicregular'; - src: url('carroisgothic-regular-webfont.eot'); - src: url('carroisgothic-regular-webfont.eot?#iefix') format('embedded-opentype'), - url('carroisgothic-regular-webfont.woff') format('woff'), - url('carroisgothic-regular-webfont.ttf') format('truetype'); - font-weight: normal; + font-family: 'proxima_novabold'; + src: url('/media/fonts/proximanova-bold-webfont.woff2') format('woff2'), + url('/media/fonts/proximanova-bold-webfont.woff') format('woff'); + font-weight: 600; font-style: normal; - } diff --git a/design/sass/_global.scss b/design/sass/_global.scss index b858866..41a1682 100644 --- a/design/sass/_global.scss +++ b/design/sass/_global.scss @@ -230,6 +230,9 @@ h3 { margin-bottom: .5rem; margin-top: 2rem; } +.float-right { + float: right; +} //************** other global classes ************************ .sans { @include generic_sans; diff --git a/design/sass/_header.scss b/design/sass/_header.scss index 29e1ef2..8df6667 100644 --- a/design/sass/_header.scss +++ b/design/sass/_header.scss @@ -21,7 +21,6 @@ header { } } nav { - @include fancy-sans-bold; letter-spacing: 1px; margin: 0 0 10px; ul { @@ -32,13 +31,14 @@ nav { } } a { - @include fontsize(14); + @include fancy-sans-bold; + @include fontsize(16); text-decoration: none; - color: #444; - font-weight: normal; + color: lighten(#444, 15); + font-weight: 600; padding: 6px; &:visited { - color: #444; + color: lighten(#444, 15); } &:hover { color: $link_color; @@ -83,6 +83,8 @@ nav { border-bottom-color: white; } a, a:visited { + @include fancy-sans; + font-weight: 400; color: lighten($body_font_color, 15); } a:hover { @@ -107,7 +109,7 @@ nav { height: 20px; border-radius: 100%; position: relative; - margin: -2px 8px 0 0; + margin: -4px 8px 0 0; display: inline-block; vertical-align: middle; background: $link_color; diff --git a/design/sass/_mixins.scss b/design/sass/_mixins.scss index bfccc17..b7da0f6 100644 --- a/design/sass/_mixins.scss +++ b/design/sass/_mixins.scss @@ -44,7 +44,7 @@ $max_width: 1280px; font-family: "proxima-nova",helvetica,arial,sans-serif; } @mixin fancy-sans-bold { - font-family: "proxima-nova",helvetica,arial,sans-serif; + font-family: "proxima_novabold",helvetica,arial,sans-serif; font-weight: 600; } @mixin fancy-serif { diff --git a/design/sass/_modal.scss b/design/sass/_modal.scss index f333fd2..8c9bf46 100644 --- a/design/sass/_modal.scss +++ b/design/sass/_modal.scss @@ -1,4 +1,4 @@ -#overlay{ +#overlay, #loading { position:fixed; width:100vw; height:100vh; @@ -60,6 +60,9 @@ max-width: 52%; width: 90%; } +#loading #overlay-wrapper { + max-width: 10%; +} #modal { min-height: 330px; padding: 0 1rem 1rem 1rem; @@ -92,6 +95,9 @@ } } +#loading #modal { + min-height: auto; +} #hed-wrapper { display: flex; align-items: center; @@ -100,3 +106,67 @@ width: auto; } } + +.loader { + font-size: 10px; + margin: 50px auto; + text-indent: -9999em; + width: 11em; + height: 11em; + border-radius: 50%; + background: $link_color; + background: -moz-linear-gradient(left, $link_color 10%, rgba(255, 255, 255, 0) 42%); + background: -webkit-linear-gradient(left, $link_color 10%, rgba(255, 255, 255, 0) 42%); + background: -o-linear-gradient(left, $link_color 10%, rgba(255, 255, 255, 0) 42%); + background: -ms-linear-gradient(left, $link_color 10%, rgba(255, 255, 255, 0) 42%); + background: linear-gradient(to right, $link_color 10%, rgba(255, 255, 255, 0) 42%); + position: relative; + -webkit-animation: load3 1.4s infinite linear; + animation: load3 1.4s infinite linear; + -webkit-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); +} +.loader:before { + width: 50%; + height: 50%; + background: $link_color; + border-radius: 100% 0 0 0; + position: absolute; + top: 0; + left: 0; + content: ''; +} +.loader:after { + background: #fff; + width: 75%; + height: 75%; + border-radius: 50%; + content: ''; + margin: auto; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; +} +@-webkit-keyframes load3 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@keyframes load3 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} diff --git a/design/sass/_notes.scss b/design/sass/_notes.scss index 4ab42b4..59e76ce 100644 --- a/design/sass/_notes.scss +++ b/design/sass/_notes.scss @@ -112,6 +112,11 @@ main { height: 9px; margin-right: 4px; } +.dropmenu .color-box { + margin-right: 5px; + position: relative; + top: -1px; +} .note-title { @include fontsize(26); } @@ -351,6 +356,29 @@ main { } } +.messages { + @include fancy-sans-bold; + @include fontsize(16); + list-style-type: none; + color: $link_color; + font-weight: 600; +} +.trash { + text-indent: -9999em; + width: 30px; + color: $link_color; + border: none; + background: url("data:image/svg+xml,%3Csvg xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns%23' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns%23' xmlns:svg='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg' xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' viewBox='0 -256 1792 1792' id='svg3741' version='1.1' inkscape:version='0.48.3.1 r9886' width='100%25' height='100%25' sodipodi:docname='trash_font_awesome.svg'%3E%3Cmetadata id='metadata3751'%3E%3Crdf:RDF%3E%3Ccc:Work rdf:about=''%3E%3Cdc:format%3Eimage/svg+xml%3C/dc:format%3E%3Cdc:type rdf:resource='http://purl.org/dc/dcmitype/StillImage' /%3E%3C/cc:Work%3E%3C/rdf:RDF%3E%3C/metadata%3E%3Cdefs id='defs3749' /%3E%3Csodipodi:namedview pagecolor='%23ffffff' bordercolor='%23666666' borderopacity='1' objecttolerance='10' gridtolerance='10' guidetolerance='10' inkscape:pageopacity='0' inkscape:pageshadow='2' inkscape:window-width='640' inkscape:window-height='480' id='namedview3747' showgrid='false' inkscape:zoom='0.13169643' inkscape:cx='896' inkscape:cy='896' inkscape:window-x='0' inkscape:window-y='25' inkscape:window-maximized='0' inkscape:current-layer='svg3741' /%3E%3Cg transform='matrix(1,0,0,-1,197.42373,1255.0508)' id='g3743'%3E%3Cpath d='M 512,800 V 224 q 0,-14 -9,-23 -9,-9 -23,-9 h -64 q -14,0 -23,9 -9,9 -9,23 v 576 q 0,14 9,23 9,9 23,9 h 64 q 14,0 23,-9 9,-9 9,-23 z m 256,0 V 224 q 0,-14 -9,-23 -9,-9 -23,-9 h -64 q -14,0 -23,9 -9,9 -9,23 v 576 q 0,14 9,23 9,9 23,9 h 64 q 14,0 23,-9 9,-9 9,-23 z m 256,0 V 224 q 0,-14 -9,-23 -9,-9 -23,-9 h -64 q -14,0 -23,9 -9,9 -9,23 v 576 q 0,14 9,23 9,9 23,9 h 64 q 14,0 23,-9 9,-9 9,-23 z M 1152,76 v 948 H 256 V 76 Q 256,54 263,35.5 270,17 277.5,8.5 285,0 288,0 h 832 q 3,0 10.5,8.5 7.5,8.5 14.5,27 7,18.5 7,40.5 z M 480,1152 h 448 l -48,117 q -7,9 -17,11 H 546 q -10,-2 -17,-11 z m 928,-32 v -64 q 0,-14 -9,-23 -9,-9 -23,-9 h -96 V 76 q 0,-83 -47,-143.5 -47,-60.5 -113,-60.5 H 288 q -66,0 -113,58.5 Q 128,-11 128,72 v 952 H 32 q -14,0 -23,9 -9,9 -9,23 v 64 q 0,14 9,23 9,9 23,9 h 309 l 70,167 q 15,37 54,63 39,26 79,26 h 320 q 40,0 79,-26 39,-26 54,-63 l 70,-167 h 309 q 14,0 23,-9 9,-9 9,-23 z' id='path3745' inkscape:connector-curvature='0' style='fill:%23FC5D2B' /%3E%3C/g%3E%3C/svg%3E%0A") no-repeat; + &:hover { + background: url("data:image/svg+xml,%3Csvg xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns%23' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns%23' xmlns:svg='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg' xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' viewBox='0 -256 1792 1792' id='svg3741' version='1.1' inkscape:version='0.48.3.1 r9886' width='100%25' height='100%25' sodipodi:docname='trash_font_awesome.svg'%3E%3Cmetadata id='metadata3751'%3E%3Crdf:RDF%3E%3Ccc:Work rdf:about=''%3E%3Cdc:format%3Eimage/svg+xml%3C/dc:format%3E%3Cdc:type rdf:resource='http://purl.org/dc/dcmitype/StillImage' /%3E%3C/cc:Work%3E%3C/rdf:RDF%3E%3C/metadata%3E%3Cdefs id='defs3749' /%3E%3Csodipodi:namedview pagecolor='%23ffffff' bordercolor='%23666666' borderopacity='1' objecttolerance='10' gridtolerance='10' guidetolerance='10' inkscape:pageopacity='0' inkscape:pageshadow='2' inkscape:window-width='640' inkscape:window-height='480' id='namedview3747' showgrid='false' inkscape:zoom='0.13169643' inkscape:cx='896' inkscape:cy='896' inkscape:window-x='0' inkscape:window-y='25' inkscape:window-maximized='0' inkscape:current-layer='svg3741' /%3E%3Cg transform='matrix(1,0,0,-1,197.42373,1255.0508)' id='g3743'%3E%3Cpath d='M 512,800 V 224 q 0,-14 -9,-23 -9,-9 -23,-9 h -64 q -14,0 -23,9 -9,9 -9,23 v 576 q 0,14 9,23 9,9 23,9 h 64 q 14,0 23,-9 9,-9 9,-23 z m 256,0 V 224 q 0,-14 -9,-23 -9,-9 -23,-9 h -64 q -14,0 -23,9 -9,9 -9,23 v 576 q 0,14 9,23 9,9 23,9 h 64 q 14,0 23,-9 9,-9 9,-23 z m 256,0 V 224 q 0,-14 -9,-23 -9,-9 -23,-9 h -64 q -14,0 -23,9 -9,9 -9,23 v 576 q 0,14 9,23 9,9 23,9 h 64 q 14,0 23,-9 9,-9 9,-23 z M 1152,76 v 948 H 256 V 76 Q 256,54 263,35.5 270,17 277.5,8.5 285,0 288,0 h 832 q 3,0 10.5,8.5 7.5,8.5 14.5,27 7,18.5 7,40.5 z M 480,1152 h 448 l -48,117 q -7,9 -17,11 H 546 q -10,-2 -17,-11 z m 928,-32 v -64 q 0,-14 -9,-23 -9,-9 -23,-9 h -96 V 76 q 0,-83 -47,-143.5 -47,-60.5 -113,-60.5 H 288 q -66,0 -113,58.5 Q 128,-11 128,72 v 952 H 32 q -14,0 -23,9 -9,9 -9,23 v 64 q 0,14 9,23 9,9 23,9 h 309 l 70,167 q 15,37 54,63 39,26 79,26 h 320 q 40,0 79,-26 39,-26 54,-63 l 70,-167 h 309 q 14,0 23,-9 9,-9 9,-23 z' id='path3745' inkscape:connector-curvature='0' style='fill:%23FC5D2B' /%3E%3C/g%3E%3C/svg%3E%0A") no-repeat; + } +} + +.loading { + #close-btn { + display: none; + } +} .ql-snow .ql-editor blockquote { border-left: none !important; margin-bottom: 5px; diff --git a/design/sass/screenv1.scss b/design/sass/screenv1.scss index f3df73e..de2593e 100644 --- a/design/sass/screenv1.scss +++ b/design/sass/screenv1.scss @@ -1,8 +1,8 @@ @import "_fonts.scss"; @import "_mixins.scss"; @import "_queries.scss"; -@import "_awesomeplete.scss"; @import "_global.scss"; +@import "_icons.scss"; @import "_header.scss"; @import "_footer.scss"; @import "_forms.scss"; diff --git a/design/templates/base.html b/design/templates/base.html index fc369ae..adcf599 100644 --- a/design/templates/base.html +++ b/design/templates/base.html @@ -29,11 +29,17 @@ <div id="notebooks-menu" class="dropmenu"> <ul id="notebooks-menu-list" class="list-style-none vertical"> {% for object in user.profile.get_notebook_list %} - <li><a href="{{object.get_absolute_url}}" title="view all notes in the notebook {{object.name}}"><span class="color-box" style="background-color: {{object.color_rgb}}"></span>{{object}}</a> + <li><a href="{{object.get_absolute_url}}" title="view all notes in the notebook {{object.name}}"><span class="color-box" style="background-color: {{object.color_rgb}}"></span>{{object}} {{object.note_count}}</a> {% endfor %} - <li class="menu-divider"> + <ul class="menu-divider"> + <li> + <a href="{% url 'notebooks:list' %}/trash">Trash</a> + </li> + <li> <a href="{% url 'notebooks:list' %}">Edit/Add Notebook</a> - </li></ul> + </li> + </ul> + </ul> </div> </li>{%else%} <li><a href="/" title="">Home</a></li>{%endif%} diff --git a/design/templates/django_registration/activation_complete.html b/design/templates/django_registration/activation_complete.html index 914be51..d83317a 100644 --- a/design/templates/django_registration/activation_complete.html +++ b/design/templates/django_registration/activation_complete.html @@ -1,8 +1,7 @@ - {% extends 'base.html' %} {% block content %} -<main> +<main class="single-col"> <h1>Your account is now active.</h1> -<p><a href="{% url 'login' %}">Login</a> and get started! <?p> +<p><a href="{% url 'login' %}">Login</a> and get started!</p> </main> {% endblock %} diff --git a/design/templates/django_registration/registration_complete.html b/design/templates/django_registration/registration_complete.html index e9d0610..59677ce 100644 --- a/design/templates/django_registration/registration_complete.html +++ b/design/templates/django_registration/registration_complete.html @@ -1,6 +1,6 @@ {% extends 'base.html' %} {% block content %} -<main> +<main class="single-col"> <h1>Thanks for signing up.</h1> <p>Please check your email for a link to confirm you new account.<?p> </main> diff --git a/design/templates/notes/notebook_detail.html b/design/templates/notes/notebook_detail.html index 73c13ab..37c8f8a 100644 --- a/design/templates/notes/notebook_detail.html +++ b/design/templates/notes/notebook_detail.html @@ -8,9 +8,9 @@ <main> <article class="note-container single-col"> <div class="flex-wrapper"> + {% if object.name != 'Trash'%} <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%}> @@ -28,6 +28,9 @@ <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> + {%else%} + <h1 class="notebook-title" id="nb-title">{{object.name}}</h1> + {%endif%} </div> <form id="new-note-form" action="{% url 'notebook-api-list' %}" method="post" class="hide"> diff --git a/design/templates/notes/notes_detail.html b/design/templates/notes/notes_detail.html index edf45e7..cce13b7 100644 --- a/design/templates/notes/notes_detail.html +++ b/design/templates/notes/notes_detail.html @@ -49,8 +49,8 @@ <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> <input id="btn-js-hide" type="submit" class="btn sm" value="Save" > + <button type="submit" value="trash" class="btn-hollow trash float-right" name="trash">Move to Trash</button> </form> - <button type="submit" value="trash" class="btn btn-hollow">Move to Trash</button> </article> <!--<aside class="note-list-container"> <div class="svg-wrapper"><svg class="svg-icon-arrow"> diff --git a/design/templates/notes/notes_list.html b/design/templates/notes/notes_list.html index 5ef067a..94e82ec 100644 --- a/design/templates/notes/notes_list.html +++ b/design/templates/notes/notes_list.html @@ -5,6 +5,15 @@ <div class="note-container"> <div class="note-hed-wrapper"> <h1 class="note-hed">Notes</h1> + {% if messages %} + <ul class="messages"> + {% for message in messages %} + <li{% if message.tags %} class="{{ message.tags }}"{% endif %}> + {% if 'safe' in message.tags %}{{ message|safe }}{% else %}{{ message }}{% endif %} + </li> + {% endfor %} + </ul> + {% endif %} {% if tags|length >= 1%}<h2 class="note-subhed">Tagged with: {% for tag in tags%}<a href="{{tag.slug}}">{{tag.name}}</a>{%endfor%}</h2>{%endif%} <h6 class="bottom-margin-0 inline-block"><button id="notebook-drop-btn" class="btn btn-light btn-drop-menu">Notebooks</button></h6> diff --git a/design/templates/pages/page.html b/design/templates/pages/page.html index 92dcc85..6703d5d 100644 --- a/design/templates/pages/page.html +++ b/design/templates/pages/page.html @@ -8,7 +8,7 @@ {% block extra %} {% if login_form %} -<div class="overlay-content" id="js-overlay-content" style="display: none;"> +<div class="overlay-content hide" id="js-overlay-login"> {% include 'lib/login.html' with form=login_form %} </div> {% endif %} diff --git a/scripts/src/main-nav.js b/scripts/src/main-nav.js index 0be7712..0dcd82b 100644 --- a/scripts/src/main-nav.js +++ b/scripts/src/main-nav.js @@ -46,40 +46,15 @@ if (document.getElementById('account-menu')) { }, false); } -//function buildNotebookMenu () { -// var data = JSON.parse(this.responseText); -// var div = document.getElementById("notebooks-menu"); -// var ul = document.createElement("ul"); -// ul.classList.add("vertical","list-style-none"); -// div.appendChild(ul); -// for(var i in data) { -// var li = document.createElement("li"); -// var a = document.createElement("a"); -// a.setAttribute("href", data[i]['json_absolute_url']); -// a.innerHTML = data[i]['name']; -// li.append(a); -// ul.append(li); -// } -// var li = document.createElement("li"); -// var a = document.createElement("a"); -// a.setAttribute("href", '/user/{{user.username}}/notebooks/'); -// a.innerHTML = "View all" -// li.append(a); -// ul.append(li); -//} -// -// -//// getJSON("{%url 'notebook-api-list' %}", buildNotebookMenu); -// - -if (typeof(document.getElementById('js-overlay-content')) != 'undefined' && document.getElementById('js-overlay-content') != null) { +if (typeof(document.getElementById('js-overlay-login')) != 'undefined' && document.getElementById('js-overlay-login') != null) { // Select your overlay trigger - var trigger = document.querySelector('#overlay-trigger'); - trigger.addEventListener('click', function(e){ - e.preventDefault(); - novicell.overlay.create({ - 'selector': trigger.getAttribute('data-element'), - 'class': 'selector-overlay', - }); - }); + var trigger = document.getElementById('overlay-trigger'); + addLoginHandler(trigger); + function addLoginHandler(el){ + console.log(el); + el.addEventListener('click', function(e){ + e.preventDefault(); + var modal = modalBox(el, document.getElementById('js-overlay-login')); + }); + } } diff --git a/scripts/src/note-edit.js b/scripts/src/note-edit.js index 5abbab7..3d01794 100644 --- a/scripts/src/note-edit.js +++ b/scripts/src/note-edit.js @@ -52,6 +52,9 @@ function edit_note(btn, form, title, quill, qcontainer, url){ link.setAttribute('href', '/n/t/'+tags[i]['fields']['slug']); link.appendChild(span); tags_display.appendChild(link); + if (window.overlay !== undefined) { + window.overlay.destroy(); + } } quill.change = false; } else { @@ -62,8 +65,16 @@ function edit_note(btn, form, title, quill, qcontainer, url){ request.onerror = function() { console.log('error on request'); }; - console.log(request); - console.log(form); + //create a modal to let the user know we're saving + var saveModal = document.createElement('div'); + var loader = document.createElement('div'); + loader.classList.add('loader'); + saveModal.appendChild(loader); + saveModal.modalHed = "Saving changes"; //modal text content + saveModal.wrapperClass = 'loading'; //add a wrapper class to the modal for styling + var modal = modalBox(saveModal); + document.getElementById('close-btn').classList.add('hide'); + //send the request to the REST API request.send(new FormData(form)); } title.setAttribute('contenteditable', false); @@ -141,7 +152,9 @@ if (typeof(document.getElementById('note-edit-form')) != 'undefined' && document form.addEventListener('input', function (e) { form.formchange = true; }); - document.getElementById('btn-js-hide').classList.add('hide'); + var formbtn = document.getElementById('btn-js-hide') + formbtn.classList.add('hide'); + console.log(formbtn); btn.classList.remove('hide'); btn.editing = false; btn.addEventListener('click', function(e){ @@ -157,7 +170,9 @@ if (typeof(document.getElementById('note-edit-form')) != 'undefined' && document function addHandler(el){ el.addEventListener('click', function(e){ e.preventDefault(); - var modal = modalBox(el, document.getElementById('js-overlay-notebook')); + var modalContent = document.getElementById('js-overlay-notebook'); + modalContent.wrapperClass = 'overlay'; //add a wrapper class to the modal for styling + var modal = modalBox(modalContent, el); }); } }); diff --git a/scripts/src/util.js b/scripts/src/util.js index daad7e1..144deae 100644 --- a/scripts/src/util.js +++ b/scripts/src/util.js @@ -35,7 +35,7 @@ function ajaxHijack(form, func) { //global init for Color Picker function initColorPicker(form){ var notebook_form_inputs = form.getElementsByTagName('input'); - var p = notebook_form.getElementsByTagName('fieldset')['color-picker']; + var p = form.getElementsByTagName('fieldset')['color-picker']; //document.getElementById('js-novi-backdrop').removeEventListener("click", handleMouseDown, true); p.classList.add('top'); p.popup = p.popup || new Picker({ @@ -100,23 +100,32 @@ function initQuill(el) { } //global modal function, give a DOM element, puts it in a model box. -function modalBox(el, content){ +function modalBox(content, btn){ + // if passed a btn object get data from that, otherwise check the content object + if (btn) { + var type = btn.dataset.modalHedClass; + var headline = btn.dataset.modalHed; + } else { + var type = content.hedClass || ''; + var headline = content.modalHed || ''; + } if (window.elemsRemoved !== undefined) { content = window.elemsRemoved; } - var headlines = ['Prompt']; var options = { - type : el.dataset.modalHedClass, - headline : el.dataset.modalHed, + type : type, + headline : headline, content : content, cancelText : 'X', confirmText : 'OK', cancelAction : function(){}, confirmAction : function(){}, reject : false, + class : content.wrapperClass }; //build the modal - var overlay = buildComponent('div', 'overlay'); + console.log(options.class); + var overlay = buildComponent('div', options.class); var outermodal = buildComponent('div', 'overlay-wrapper'); var innermodal = buildComponent('div', 'modal'); var headline = buildComponent('header', false, options.headline); |