Merge branch 'main' into progress_update

This commit is contained in:
Joel Bradshaw 2021-01-18 19:41:06 -08:00
commit 29140be78e
42 changed files with 763 additions and 693 deletions

View file

@ -0,0 +1,22 @@
# Generated by Django 3.0.7 on 2021-01-18 19:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('bookwyrm', '0036_annualgoal'),
]
operations = [
migrations.AlterModelOptions(
name='shelfbook',
options={'ordering': ('-created_date',)},
),
migrations.AlterField(
model_name='user',
name='email',
field=models.EmailField(max_length=254, null=True, unique=True),
),
]

View file

@ -25,6 +25,7 @@ from . import fields, Review
class User(OrderedCollectionPageMixin, AbstractUser):
''' a user who wants to read books '''
username = fields.UsernameField()
email = models.EmailField(unique=True, null=True)
key_pair = fields.OneToOneField(
'KeyPair',
@ -246,7 +247,7 @@ class AnnualGoal(BookWyrmModel):
''' the books you've read this year '''
return self.user.readthrough_set.filter(
finish_date__year__gte=self.year
).order_by('finish_date').all()
).order_by('-finish_date').all()
@property

View file

@ -14,20 +14,16 @@
}
/* --- TOGGLES --- */
input.toggle-control {
.toggle-button[aria-pressed=true], .toggle-button[aria-pressed=true]:hover {
background-color: hsl(171, 100%, 41%);
color: white;
}
.hide-active[aria-pressed=true], .hide-inactive[aria-pressed=false] {
display: none;
}
.hidden {
display: none;
}
input.toggle-control:checked ~ .toggle-content {
display: block;
}
input.toggle-control:checked ~ .modal.toggle-content {
display: flex;
display: none !important;
}
/* --- STARS --- */

View file

@ -1,7 +1,7 @@
// set up javascript listeners
window.onload = function() {
// let buttons set keyboard focus
Array.from(document.getElementsByClassName('toggle-control'))
// buttons that display or hide content
document.querySelectorAll('[data-controls]')
.forEach(t => t.onclick = toggleAction);
// javascript interactions (boost/fav)
@ -13,8 +13,6 @@ window.onload = function() {
.forEach(t => t.onclick = selectAll);
// toggle between tabs
Array.from(document.getElementsByClassName('tab-change-nested'))
.forEach(t => t.onclick = tabChangeNested);
Array.from(document.getElementsByClassName('tab-change'))
.forEach(t => t.onclick = tabChange);
@ -29,9 +27,22 @@ window.onload = function() {
// update localstorage
Array.from(document.getElementsByClassName('set-display'))
.forEach(t => t.onclick = updateDisplay);
// hidden submit button in a form
document.querySelectorAll('.hidden-form input')
.forEach(t => t.onchange = revealForm);
};
function revealForm(e) {
var hidden = e.currentTarget.closest('.hidden-form').getElementsByClassName('hidden')[0];
if (hidden) {
removeClass(hidden, 'hidden');
}
}
function updateDisplay(e) {
// used in set reading goal
var key = e.target.getAttribute('data-id');
var value = e.target.getAttribute('data-value');
window.localStorage.setItem(key, value);
@ -41,37 +52,52 @@ function updateDisplay(e) {
}
function setDisplay(el) {
// used in set reading goal
var key = el.getAttribute('data-hide');
var value = window.localStorage.getItem(key)
if (!value) {
el.className = el.className.replace('hidden', '');
} else if (value != null && !!value) {
el.className += ' hidden';
}
var value = window.localStorage.getItem(key);
addRemoveClass(el, 'hidden', value);
}
function toggleAction(e) {
// set hover, if appropriate
var hover = e.target.getAttribute('data-hover-target');
if (hover) {
document.getElementById(hover).focus();
var el = e.currentTarget;
var pressed = el.getAttribute('aria-pressed') == 'false';
var targetId = el.getAttribute('data-controls');
document.querySelectorAll('[data-controls="' + targetId + '"]')
.forEach(t => t.setAttribute('aria-pressed', (t.getAttribute('aria-pressed') == 'false')));
if (targetId) {
var target = document.getElementById(targetId);
addRemoveClass(target, 'hidden', !pressed);
addRemoveClass(target, 'is-active', pressed);
}
// show/hide container
var container = document.getElementById('hide-' + targetId);
if (!!container) {
addRemoveClass(container, 'hidden', pressed);
}
// set checkbox, if appropriate
var checkbox = el.getAttribute('data-controls-checkbox');
if (checkbox) {
document.getElementById(checkbox).checked = !!pressed;
}
// set focus, if appropriate
var focus = el.getAttribute('data-focus-target');
if (focus) {
document.getElementById(focus).focus();
}
}
function interact(e) {
e.preventDefault();
ajaxPost(e.target);
var identifier = e.target.getAttribute('data-id');
var elements = document.getElementsByClassName(identifier);
for (var i = 0; i < elements.length; i++) {
if (elements[i].className.includes('hidden')) {
elements[i].className = elements[i].className.replace('hidden', '');
} else {
elements[i].className += ' hidden';
}
}
return true;
Array.from(document.getElementsByClassName(identifier))
.forEach(t => addRemoveClass(t, 'hidden', t.className.indexOf('hidden') == -1));
}
function selectAll(e) {
@ -79,32 +105,32 @@ function selectAll(e) {
.forEach(t => t.checked=true);
}
function tabChangeNested(e) {
var target = e.target.closest('li')
var parentElement = target.parentElement.closest('li').parentElement;
handleTabChange(target, parentElement)
}
function tabChange(e) {
var target = e.target.closest('li')
var parentElement = target.parentElement;
handleTabChange(target, parentElement)
}
var el = e.currentTarget;
var parentElement = el.closest('[role="tablist"]');
function handleTabChange(target, parentElement) {
parentElement.querySelectorAll('[aria-selected="true"]')
.forEach(t => t.setAttribute("aria-selected", false));
target.querySelector('[role="tab"]').setAttribute("aria-selected", true);
el.setAttribute("aria-selected", true);
parentElement.querySelectorAll('li')
.forEach(t => t.className='');
target.className = 'is-active';
.forEach(t => removeClass(t, 'is-active'));
addClass(el, 'is-active');
var tabId = el.getAttribute('data-tab');
Array.from(document.getElementsByClassName(el.getAttribute('data-category')))
.forEach(t => addRemoveClass(t, 'hidden', t.id != tabId));
}
function toggleMenu(e) {
var el = e.target.closest('.pulldown-menu');
el.setAttribute('aria-expanded', el.getAttribute('aria-expanded') == 'false');
var el = e.currentTarget;
var expanded = el.getAttribute('aria-expanded') == 'false';
el.setAttribute('aria-expanded', expanded);
var targetId = el.getAttribute('data-controls');
if (targetId) {
var target = document.getElementById(targetId);
addRemoveClass(target, 'is-active', expanded);
}
}
function ajaxPost(form) {
@ -113,3 +139,31 @@ function ajaxPost(form) {
body: new FormData(form)
});
}
function addRemoveClass(el, classname, bool) {
if (bool) {
addClass(el, classname);
} else {
removeClass(el, classname);
}
}
function addClass(el, classname) {
var classes = el.className.split(' ');
if (classes.indexOf(classname) > -1) {
return;
}
el.className = classes.concat(classname).join(' ');
}
function removeClass(el, className) {
var classes = [];
if (el.className) {
classes = el.className.split(' ');
}
const idx = classes.indexOf(className);
if (idx > -1) {
classes.splice(idx, 1);
}
el.className = classes.join(' ');
}

View file

@ -39,14 +39,28 @@
{% if request.user.is_authenticated and not book.cover %}
<div class="box p-2">
<h3 class="title is-6 mb-1">Add cover</h3>
<form name="add-cover" method="POST" action="/upload-cover/{{ book.id }}" enctype="multipart/form-data">
{% csrf_token %}
<div class="field">
<label class="label" for="id_cover">Cover:</label>
<input type="file" name="cover" accept="image/*" class="" id="id_cover">
</div>
<div class="field">
<button class="button is-small" type="submit">Add cover</button>
<div class="field has-addons">
<div class="control">
<div class="file is-small mb-1">
<label class="file-label">
<input class="file-input" type="file" name="cover" accept="image/*" enctype="multipart/form-data" id="id_cover" required>
<span class="file-cta">
<span class="file-icon">
<i class="fas fa-upload"></i>
</span>
<span class="file-label">
Choose file...
</span>
</span>
</label>
</div>
</div>
<div class="control">
<button class="button is-small is-primary" type="submit">Add</button>
</div>
</div>
</form>
</div>
@ -94,30 +108,20 @@
{% include 'snippets/trimmed_text.html' with full=book|book_description %}
{% if request.user.is_authenticated and perms.bookwyrm.edit_book and not book|book_description %}
<div>
<input class="toggle-control" type="radio" name="add-description" id="hide-description-{{ book.id }}" checked>
<div class="toggle-content hidden">
{% include 'snippets/toggle/toggle_button.html' with text="Add description" controls_text="add-description" controls_uid=book.id %}
</div>
</div>
{% include 'snippets/toggle/open_button.html' with text="Add description" controls_text="add-description" controls_uid=book.id focus="id_description" hide_active=True id="hide-description" %}
<div>
<input class="toggle-control" type="radio" name="add-description" id="add-description-{{ book.id }}" data-hover-target="id_description">
<div class="toggle-content hidden">
<div class="box">
<form name="add-description" method="POST" action="/add-description/{{ book.id }}">
{% csrf_token %}
<p class="fields is-grouped">
<label class="label"for="id_description">Description:</label>
<textarea name="description" cols="None" rows="None" class="textarea" id="id_description"></textarea>
</p>
<div class="field">
<button class="button is-primary" type="submit">Save</button>
{% include 'snippets/toggle/toggle_button.html' with text="Cancel" controls_text="hide-description" controls_uid=book.id %}
</div>
</form>
<div class="box hidden" id="add-description-{{ book.id }}">
<form name="add-description" method="POST" action="/add-description/{{ book.id }}">
{% csrf_token %}
<p class="fields is-grouped">
<label class="label"for="id_description">Description:</label>
<textarea name="description" cols="None" rows="None" class="textarea" id="id_description"></textarea>
</p>
<div class="field">
<button class="button is-primary" type="submit">Save</button>
{% include 'snippets/toggle/close_button.html' with text="Cancel" controls_text="add-description" controls_uid=book.id hide_inactive=True %}
</div>
</div>
</form>
</div>
{% endif %}
@ -144,40 +148,38 @@
</div>
{% if readthroughs.exists %}
<div>
<h2 class="title is-5">Your reading activity</h2>
{% for readthrough in readthroughs %}
{% include 'snippets/readthrough.html' with readthrough=readthrough %}
{% endfor %}
</div>
{% endif %}
<div class="block">
<div>
<input type="radio" class="toggle-control" name="add-readthrough-form" id="hide-create-readthrough" checked>
<div class="toggle-content hidden">
{% include 'snippets/toggle/toggle_button.html' with text="Add read dates" controls_text="add-readthrough" %}
<section class="block">
<header class="columns">
<h2 class="column title is-5 mb-1">Your reading activity</h2>
<div class="column is-narrow">
{% include 'snippets/toggle/open_button.html' with text="Add read dates" icon="plus" class="is-small" controls_text="add-readthrough" %}
</div>
</div>
<div>
<input type="radio" class="toggle-control" id="add-readthrough" name="add-readthrough-form">
<div class="toggle-content hidden box">
<form name="add-readthrough" action="/create-readthrough" method="post">
{% include 'snippets/readthrough_form.html' with readthrough=None %}
<div class="field is-grouped">
</header>
<section class="hidden box" id="add-readthrough">
<form name="add-readthrough" action="/create-readthrough" method="post">
{% include 'snippets/readthrough_form.html' with readthrough=None %}
<div class="field is-grouped">
<div class="control">
<button class="button is-primary" type="submit">Create</button>
{% include 'snippets/toggle/toggle_button.html' with text="Cancel" controls_text="hide-create-readthrough" %}
</div>
</form>
</div>
</div>
</div>
<div class="control">
{% include 'snippets/toggle/close_button.html' with text="Cancel" controls_text="add-readthrough" %}
</div>
</div>
</form>
</section>
{% for readthrough in readthroughs %}
{% include 'snippets/readthrough.html' with readthrough=readthrough %}
{% endfor %}
</section>
{% endif %}
{% if request.user.is_authenticated %}
<div class="box">
<section class="box">
{% include 'snippets/create_status.html' with book=book hide_cover=True %}
</div>
</section>
<div class="block">
<section class="block">
<form name="tag" action="/tag/" method="post">
<label for="tags" class="is-3">Tags</label>
{% csrf_token %}
@ -185,7 +187,7 @@
<input id="tags" class="input" type="text" name="name">
<button class="button" type="submit">Add tag</button>
</form>
</div>
</section>
{% endif %}
<div class="block">

View file

@ -8,40 +8,40 @@
{% endif %}
<form name="edit-profile" action="/edit-profile/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p class="block">
<div class="block">
<label class="label" for="id_avatar">Avatar:</label>
{{ form.avatar }}
{% for error in form.avatar.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
</p>
<p class="block">
</div>
<div class="block">
<label class="label" for="id_name">Display name:</label>
{{ form.name }}
{% for error in form.name.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
</p>
<p class="block">
</div>
<div class="block">
<label class="label" for="id_summary">Summary:</label>
{{ form.summary }}
{% for error in form.summary.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
</p>
<p class="block">
</div>
<div class="block">
<label class="label" for="id_email">Email address:</label>
{{ form.email }}
{% for error in form.email.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
</p>
<p class="block">
</div>
<div class="block">
<label class="checkbox label" for="id_manually_approves_followers">
Manually approve followers:
{{ form.manually_approves_followers }}
</label>
</p>
</div>
<button class="button is-primary" type="submit">Save</button>
</form>
</div>
@ -50,14 +50,14 @@
<h2 class="title">Change password</h2>
<form name="edit-profile" action="/change-password/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p class="block">
<div class="block">
<label class="label" for="id_password">New password:</label>
<input type="password" name="password" maxlength="128" class="input" required="" id="id_password">
</p>
<p class="block">
</div>
<div class="block">
<label class="label" for="id_confirm_password">Confirm password:</label>
<input type="password" name="confirm-password" maxlength="128" class="input" required="" id="id_confirm_password">
</p>
</div>
<button class="button is-primary" type="submit">Change password</button>
</form>
</div>

View file

@ -9,7 +9,7 @@
<p>There are no books here right now! Try searching for a book to get started</p>
{% else %}
<div class="tabs is-small">
<ul>
<ul role="tablist">
{% for shelf in suggested_books %}
{% if shelf.books %}
{% with shelf_counter=forloop.counter %}
@ -17,17 +17,13 @@
<p>
{{ shelf.name }}
</p>
<div class="tabs is-small is-toggle" role="tablist">
<div class="tabs is-small is-toggle">
<ul>
{% for book in shelf.books %}
<li class="{% if shelf_counter == 1 and forloop.first %}is-active{% endif %}" data-id="tab-book-{{ book.id }}">
<label for="book-{{ book.id }}" class="tab-change-nested">
<div role="tab" tabindex="0" aria-selected="{% if shelf_counter == 1 and forloop.first %}true{% else %}false{% endif %}" aria-controls="book-{{ book.id }}-panel">
<a>
{% include 'snippets/book_cover.html' with book=book size="medium" %}
</a>
</div>
</label>
<li class="tab-change{% if shelf_counter == 1 and forloop.first %} is-active{% endif %}" data-tab="book-{{ book.id }}" data-tab="book-{{ book.id }}" role="tab" tabindex="0" aria-selected="{% if shelf_counter == 1 and forloop.first %}true{% else %}false{% endif %}" aria-controls="book-{{ book.id }}" data-category="suggested-tabs">
<a>
{% include 'snippets/book_cover.html' with book=book size="medium" %}
</a>
</li>
{% endfor %}
</ul>
@ -41,41 +37,33 @@
{% for shelf in suggested_books %}
{% with shelf_counter=forloop.counter %}
{% for book in shelf.books %}
<div>
<input class="toggle-control" type="radio" name="recent-books" id="book-{{ book.id }}" {% if shelf_counter == 1 and forloop.first %}checked{% endif %}>
<div class="toggle-content hidden" role="tabpanel" id="book-{{ book.id }}-panel">
<div class="card">
<div class="card-header">
<p class="card-header-title">
<span>{% include 'snippets/book_titleby.html' with book=book %}</span>
</p>
<div class="card-header-icon is-hidden-tablet">
{% include 'snippets/toggle/toggle_button.html' with label="close" controls_text="no-book" class="delete" %}
</div>
</div>
<div class="card-content">
<div class="columns is-gapless">
<div class="column is-narrow">
{% include 'snippets/shelve_button.html' with book=book %}
</div>
{% active_shelf book as active_shelf %}
{% if active_shelf.shelf.identifier == 'reading' and book.latest_readthrough %}
<div class="column">
{% include 'snippets/progress_update.html' with readthrough=book.latest_readthrough %}
</div>
{% endif %}
</div>
{% include 'snippets/create_status.html' with book=book %}
</div>
<div class="suggested-tabs card{% if shelf_counter != 1 or not forloop.first %} hidden{% endif %}" role="tabpanel" id="book-{{ book.id }}">
<div class="card-header">
<p class="card-header-title">
<span>{% include 'snippets/book_titleby.html' with book=book %}</span>
</p>
<div class="card-header-icon is-hidden-tablet">
{% include 'snippets/toggle/toggle_button.html' with label="close" controls_text="book" controls_uid=book.id class="delete" nonbutton=True pressed=True %}
</div>
</div>
<div class="card-content">
<div class="columns is-gapless">
<div class="column is-narrow">
{% include 'snippets/shelve_button.html' with book=book %}
</div>
{% active_shelf book as active_shelf %}
{% if active_shelf.shelf.identifier == 'reading' and book.latest_readthrough %}
<div class="column">
{% include 'snippets/progress_update.html' with readthrough=book.latest_readthrough %}
</div>
{% endif %}
</div>
{% include 'snippets/create_status.html' with book=book %}
</div>
</div>
{% endfor %}
{% endwith %}
{% endfor %}
<div>
<input class="toggle-control" type="radio" name="recent-books" id="no-book">
</div>
{% endif %}
{% if goal %}
@ -108,24 +96,7 @@
{% if not goal and tab == 'home' %}
{% now 'Y' as year %}
<section class="block hidden" aria-title="Announcements" data-hide="hide-{{ year }}-reading-goal">
<article class="card">
<header class="card-header">
<h3 class="card-header-title has-background-primary has-text-white">
<span class="icon icon-book is-size-3 mr-2" aria-hidden="true"></span> {{ year }} reading goal
</h3>
</header>
<section class="card-content content">
<p>Set a goal for how many books you'll finish reading in {{ year }}, and track your progress throughout the year.</p>
{% include 'snippets/goal_form.html' %}
</section>
<footer class="card-footer has-background-white-bis">
<div class="card-footer-item is-flex-direction-column">
<button class="button is-danger is-light is-block set-display" data-id="hide-{{ year }}-reading-goal" data-value="true">Dismiss message</button>
<p class="help">You can set or change your reading goal any time from your <a href="{{ request.user.local_path }}">profile page</a></p>
</div>
</footer>
</article>
{% include 'snippets/goal_card.html' with year=year %}
<hr>
</section>
{% endif %}

View file

@ -6,29 +6,21 @@
{% if user == request.user %}
<div class="block">
{% if goal %}
<input type="radio" class="toggle-control" name="edit-goal" id="hide-edit-goal" checked>
<div class="toggle-content hidden">
{% include 'snippets/toggle/toggle_button.html' with text="Edit goal" controls_text="show-edit-goal" %}
</div>
{% include 'snippets/toggle/open_button.html' with text="Edit goal" controls_text="show-edit-goal" focus="edit-form-header" %}
{% endif %}
</div>
<div class="block">
<input type="radio" class="toggle-control" name="edit-goal" id="show-edit-goal" data-hover-target="edit-form-header">
<div class="toggle-content{% if goal %} hidden{% endif %}">
{% now 'Y' as year %}
<section class="card">
<header class="card-header">
<h2 class="card-header-title has-background-primary has-text-white" tabindex="0" id="edit-form-header">
<span class="icon icon-book is-size-3 mr-2" aria-hidden="true"></span> {{ year }} reading goal
</h2>
</header>
<section class="card-content content">
<p>Set a goal for how many books you'll finish reading in {{ year }}, and track your progress throughout the year.</p>
{% now 'Y' as year %}
<section class="card {% if goal %}hidden{% endif %}" id="show-edit-goal">
<header class="card-header">
<h2 class="card-header-title has-background-primary has-text-white" tabindex="0" id="edit-form-header">
<span class="icon icon-book is-size-3 mr-2" aria-hidden="true"></span> {{ year }} reading goal
</h2>
</header>
<section class="card-content content">
<p>Set a goal for how many books you'll finish reading in {{ year }}, and track your progress throughout the year.</p>
{% include 'snippets/goal_form.html' with goal=goal year=year %}
</section>
{% include 'snippets/goal_form.html' with goal=goal year=year %}
</section>
</div>
</section>
</div>
{% endif %}

View file

@ -41,17 +41,16 @@
</div>
</form>
<label for="main-nav" role="button" class="navbar-burger pulldown-menu" aria-label="menu" aria-expanded="false" data-target="mainNav" tabindex="0">
<div role="button" tabindex="0" class="navbar-burger pulldown-menu" data-controls="main-nav" aria-expanded="false">
<div class="navbar-item mt-3">
<div class="icon icon-dots-three-vertical" title="Main navigation menu">
<span class="is-sr-only">Main navigation menu</span>
</div>
</div>
</label>
</div>
</div>
<input class="toggle-control" type="checkbox" id="main-nav">
<div id="mainNav" class="navbar-menu toggle-content">
<div class="navbar-menu" id="main-nav">
<div class="navbar-start">
{% if request.user.is_authenticated %}
<a href="/user/{{ request.user.localname }}/shelves" class="navbar-item">

View file

@ -27,16 +27,11 @@
<p>
Didn't find what you were looking for?
</p>
<input class="toggle-control" type="radio" name="more-results" id="fewer-results" checked>
<div class="toggle-content hidden">
{% include 'snippets/toggle/toggle_button.html' with text="Show results from other catalogues" small=True controls_text="more-results" %}
</div>
{% include 'snippets/toggle/open_button.html' with text="Show results from other catalogues" small=True controls_text="more-results" %}
</div>
{% endif %}
<input class="toggle-control" type="radio" name="more-results" id="more-results" {% if not local_results.results %}checked{% endif %}>
<div class="toggle-content hidden">
<div class="{% if local_results.results %}hidden{% endif %}" id="more-results">
{% for result_set in book_results|slice:"1:" %}
{% if result_set.results %}
<section class="block">
@ -61,8 +56,9 @@
</section>
{% endif %}
{% endfor %}
{% if local_results.results %}
{% include 'snippets/toggle/toggle_button.html' with text="Hide results from other catalogues" small=True controls_text="fewer-results" %}
{% include 'snippets/toggle/close_button.html' with text="Hide results from other catalogues" small=True controls_text="more-results" %}
{% endif %}
</div>
</div>

View file

@ -31,38 +31,30 @@
{% if is_self %}
<div class="column is-narrow">
<input type="radio" id="create-shelf-form-hide" name="create-shelf-form" class="toggle-control" checked>
<div class="toggle-content hidden">
{% include 'snippets/toggle/toggle_button.html' with text="Create shelf" icon="plus" class="is-clickable" controls_text="create-shelf-form-show" %}
</div>
{% include 'snippets/toggle/open_button.html' with text="Create shelf" icon="plus" class="is-clickable" controls_text="create-shelf-form" %}
</div>
{% endif %}
</div>
<div>
<input type="radio" id="create-shelf-form-show" name="create-shelf-form" class="toggle-control">
<div class="toggle-content hidden">
<div class="box mb-5">
<h2 class="title is-4">Create new shelf</h2>
<form name="create-shelf" action="/create-shelf/" method="post">
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
<div class="field">
<label class="label" for="id_name_create">Name:</label>
<input type="text" name="name" maxlength="100" class="input" required="true" id="id_name_create">
</div>
<label class="label">
<p>Shelf privacy:</p>
{% include 'snippets/privacy_select.html' with no_label=True %}
</label>
<div class="field is-grouped">
<button class="button is-primary" type="submit">Create shelf</button>
{% include 'snippets/toggle/toggle_button.html' with text="Cancel" controls_text="create-shelf-form-hide" %}
</div>
</form>
<div class="hidden box mb-5" id="create-shelf-form">
<h2 class="title is-4">Create new shelf</h2>
<form name="create-shelf" action="/create-shelf/" method="post">
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
<div class="field">
<label class="label" for="id_name_create">Name:</label>
<input type="text" name="name" maxlength="100" class="input" required="true" id="id_name_create">
</div>
</div>
<label class="label">
<p>Shelf privacy:</p>
{% include 'snippets/privacy_select.html' with no_label=True %}
</label>
<div class="field is-grouped">
<button class="button is-primary" type="submit">Create shelf</button>
{% include 'snippets/toggle/close_button.html' with text="Cancel" controls_text="create-shelf-form" %}
</div>
</form>
</div>
<div class="block columns">
@ -76,40 +68,34 @@
</div>
{% if is_self %}
<div class="column is-narrow">
<input type="radio" id="edit-shelf-form-hide" name="edit-shelf-form" class="toggle-control" checked>
<div class="toggle-content hidden">
{% include 'snippets/toggle/toggle_button.html' with text="Edit shelf" icon="pencil" class="is-clickable" controls_text="edit-shelf-form-show" %}
</div>
{% include 'snippets/toggle/open_button.html' with text="Edit shelf" icon="pencil" class="is-clickable" controls_text="edit-shelf-form" %}
</div>
{% endif %}
</div>
<input type="radio" id="edit-shelf-form-show" name="edit-shelf-form" class="toggle-control">
<div class="toggle-content hidden">
<div class="box mb-5">
<h2 class="title is-4">Edit shelf</h2>
<form name="create-shelf" action="/edit-shelf/{{ shelf.id }}" method="post">
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
{% if shelf.editable %}
<div class="field">
<label class="label" for="id_name">Name:</label>
<input type="text" name="name" maxlength="100" class="input" required="true" value="{{ shelf.name }}" id="id_name">
</div>
{% else %}
<input type="hidden" name="name" required="true" value="{{ shelf.name }}">
{% endif %}
<div class="hidden box mb-5" id="edit-shelf-form">
<h2 class="title is-4">Edit shelf</h2>
<form name="create-shelf" action="{{ shelf.local_path }}" method="post">
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
{% if shelf.editable %}
<div class="field">
<label class="label" for="id_name">Name:</label>
<input type="text" name="name" maxlength="100" class="input" required="true" value="{{ shelf.name }}" id="id_name">
</div>
{% else %}
<input type="hidden" name="name" required="true" value="{{ shelf.name }}">
{% endif %}
<label class="label">
<p>Shelf privacy:</p>
{% include 'snippets/privacy_select.html' with no_label=True current=shelf.privacy %}
</label>
<div class="field is-grouped">
<button class="button is-primary" type="submit">Update shelf</button>
{% include 'snippets/toggle/toggle_button.html' with text="Cancel" controls_text="edit-shelf-form-hide" %}
</div>
</form>
</div>
<label class="label">
<p>Shelf privacy:</p>
{% include 'snippets/privacy_select.html' with no_label=True current=shelf.privacy %}
</label>
<div class="field is-grouped">
<button class="button is-primary" type="submit">Update shelf</button>
{% include 'snippets/toggle/close_button.html' with text="Cancel" controls_text="edit-shelf-form" %}
</div>
</form>
</div>
<div class="block">

View file

@ -0,0 +1,21 @@
<article class="card">
<header class="card-header">
{% block card-header %}
{% endblock %}
</header>
{% if not status or status.status_type != 'GeneratedNote' or status.book or status.mention_books.exists or status.mention_users.exists %}
<section class="card-content">
{% block card-content %}
{% endblock %}
</section>
{% endif %}
<footer class="card-footer has-background-white-bis">
{% block card-footer %}
{% endblock %}
</footer>
{% block card-bonus %}
{% endblock %}
</article>

View file

@ -0,0 +1,13 @@
{% load bookwyrm_tags %}
{% with 0|uuid as uuid %}
<div class="dropdown control{% if right %} is-right{% endif %}" id="menu-{{ uuid }}">
<button type="button" class="button dropdown-trigger pulldown-menu {{ class }}" aria-expanded="false" class="pulldown-menu" aria-haspopup="true" aria-controls="menu-options-{{ uuid }}" data-controls="menu-{{ uuid }}">
{% block dropdown-trigger %}{% endblock %}
</button>
<div class="dropdown-menu">
<ul class="dropdown-content" role="menu" id="menu-options-{{ book.id }}">
{% block dropdown-list %}{% endblock %}
</ul>
</div>
</div>
{% endwith %}

View file

@ -0,0 +1,23 @@
<div class="modal hidden" id="{{ controls_text }}-{{ controls_uid }}">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head" tabindex="0" id="modal-title-{{ controls_text }}-{{ controls_uid }}">
<h2 class="modal-card-title">
{% block modal-title %}{% endblock %}
</h2>
{% include 'snippets/toggle/toggle_button.html' with label="close" class="delete" nonbutton=True %}
</header>
{% block modal-form-open %}{% endblock %}
{% block modal-body %}{% endblock %}
<footer class="modal-card-foot">
{% block modal-footer %}{% endblock %}
</footer>
{% block modal-form-close %}{% endblock %}
</div>
<label class="modal-close is-large" for="{{ controls_text }}-{{ readthrough.id }}" aria-label="close"></label>
{% include 'snippets/toggle/toggle_button.html' with label="close" class="modal-close is-large" nonbutton=True %}
</div>

View file

@ -1,20 +1,4 @@
{% load bookwyrm_tags %}
{% with 0|uuid as uuid %}
<div class="control">
<div>
<input type="radio" class="toggle-control" id="include-spoilers-{{ uuid }}" name="sensitive" value="true" {% if parent_status.content_warning %}checked{% endif %} data-hover-target="id_content_warning_{{ uuid }}">
<div class="toggle-content hidden">
<label class="is-sr-only" for="id_content_warning_{{ uuid }}">Spoilers/content warning:</label>
<input type="text" name="content_warning" maxlength="255" class="input" id="id_content_warning_{{ uuid }}" placeholder="Spoilers ahead!"{% if parent_status.content_warning %} value="{{ parent_status.content_warning }}"{% endif %}>
{% include 'snippets/toggle/toggle_button.html' with controls_text="hide-spoilers" controls_uid=uuid text="Remove spoilers/content warning" small=True %}
</div>
</div>
<div>
<input type="radio" class="toggle-control" name="sensitive" value="false" id="hide-spoilers-{{ uuid }}" {% if not parent_status.content_warning %}checked{% endif %}>
<div class="toggle-content hidden">
{% include 'snippets/toggle/toggle_button.html' with controls_text="include-spoilers" controls_uid=uuid text="Add spoilers/content warning" small=True %}
</div>
</div>
<div class="control{% if not parent_status.content_warning %} hidden{% endif %}" id="spoilers-{{ uuid }}">
<label class="is-sr-only" for="id_content_warning-{{ uuid }}">Spoiler alert:</label>
<input type="text" name="content_warning" maxlength="255" class="input" id="id_content_warning-{{ uuid }}" placeholder="Spoilers ahead!"{% if parent_status.content_warning %} value="{{ parent_status.content_warning }}"{% endif %}>
</div>
{% endwith %}

View file

@ -3,41 +3,32 @@
<div class="tabs is-boxed">
<ul role="tablist">
<li class="is-active" data-id="tab-review-{{ book.id }}" data-category="tab-option-{{ book.id }}">
<label for="review-{{ book.id }}">
<div class="tab-change" role="tab" aria-selected="true" tabindex="0">
<a>Review</a>
</div>
</label>
<li class="tab-change is-active" data-category="tab-option-{{ book.id }}" role="tab" aria-selected="true" tabindex="0" data-tab="review-{{ book.id }}">
<a>Review</a>
</li>
<li data-id="tab-comment-{{ book.id }}" data-category="tab-option-{{ book.id }}">
<label for="comment-{{ book.id}}">
<div class="tab-change" role="tab" tabindex="0">
<a>Comment</a>
</div>
</label>
<li class="tab-change" data-category="tab-option-{{ book.id }}" role="tab" tabindex="0" data-tab="comment-{{ book.id}}">
<a>Comment</a>
</li>
<li data-id="tab-quotation-{{ book.id }}" data-category="tab-option-{{ book.id }}">
<label for="quote-{{ book.id }}">
<div class="tab-change" role="tab" tabindex="0">
<a>Quote</a>
</div>
</label>
<li class="tab-change" data-category="tab-option-{{ book.id }}" role="tab" tabindex="0" data-tab="quote-{{ book.id }}">
<a>Quote</a>
</li>
</ul>
</div>
<div>
<input class="toggle-control" type="radio" name="status-tabs-{{ book.id }}" id="review-{{ book.id }}" checked>
<div class="tab-option-{{ book.id }}" id="review-{{ book.id }}">
{% with 0|uuid as uuid %}
{% include 'snippets/create_status_form.html' with type='review' %}
{% endwith %}
</div>
<div>
<input class="toggle-control" type="radio" name="status-tabs-{{ book.id }}" id="comment-{{ book.id }}">
<div class="hidden tab-option-{{ book.id }}" id="comment-{{ book.id }}">
{% with 0|uuid as uuid %}
{% include 'snippets/create_status_form.html' with type="comment" placeholder="Some thoughts on '"|add:book.title|add:"'" %}
{% endwith %}
</div>
<div>
<input class="toggle-control" type="radio" name="status-tabs-{{ book.id }}" id="quote-{{ book.id }}">
<div class="hidden tab-option-{{ book.id }}" id="quote-{{ book.id }}">
{% with 0|uuid as uuid %}
{% include 'snippets/create_status_form.html' with type="quotation" placeholder="An excerpt from '"|add:book.title|add:"'" %}
{% endwith %}
</div>

View file

@ -1,7 +1,8 @@
<form class="toggle-content hidden tab-option-{{ book.id }}" name="{{ type }}" action="/post/{{ type }}" method="post" id="tab-{{ type }}-{{ book.id }}">
<form class="is-flex-grow-1" name="{{ type }}" action="/post/{{ type }}" method="post" id="tab-{{ type }}-{{ book.id }}{{ reply_parent.id }}">
{% csrf_token %}
<input type="hidden" name="book" value="{{ book.id }}">
<input type="hidden" name="user" value="{{ request.user.id }}">
<input type="hidden" name="reply_parent" value="{{ reply_parent.id }}">
{% if type == 'review' %}
<div class="control">
<label class="label" for="id_name_{{ book.id }}_{{ type }}">Title:</label>
@ -9,8 +10,9 @@
</div>
{% endif %}
<div class="control">
{% if not type == 'reply' %}
<label class="label" for="id_{% if type == 'quotation' %}quote{% else %}content{% endif %}_{{ book.id }}_{{ type }}">{{ type|title }}:</label>
{% include 'snippets/content_warning_field.html' %}
{% endif %}
{% if type == 'review' %}
<fieldset>
@ -31,18 +33,30 @@
{% if type == 'quotation' %}
<textarea name="quote" class="textarea" id="id_quote_{{ book.id }}_{{ type }}" placeholder="{{ placeholder }}" required></textarea>
{% else %}
<textarea name="content" class="textarea" id="id_content_{{ book.id }}_{{ type }}" placeholder="{{ placeholder }}" required></textarea>
{% include 'snippets/content_warning_field.html' with parent_status=status %}
<textarea name="content" class="textarea" id="id_content_{{ type }}-{{ book.id }}{{reply_parent.id}}" placeholder="{{ placeholder }}" {% if type == 'reply' %} aria-label="Reply"{% endif %} required></textarea>
{% endif %}
</div>
{% if type == 'quotation' %}
<div class="control">
<label class="label" for="id_content_{{ book.id }}_quote">Comment:</label>
<textarea name="content" class="textarea is-small" id="id_content_{{ book.id }}_quote"></textarea>
<label class="label" for="id_content_quote-{{ book.id }}">Comment:</label>
{% include 'snippets/content_warning_field.html' with parent_status=status %}
<textarea name="content" class="textarea is-small" id="id_content_quote-{{ book.id }}"></textarea>
</div>
{% endif %}
<div class="control is-grouped">
{% include 'snippets/privacy_select.html' %}
<button class="button is-primary" type="submit">post {{ type }}</button>
<input type="checkbox" class="hidden" name="sensitive" id="id_show_spoilers-{{ uuid }}" {% if status.content_warning %}checked{% endif %} aria-hidden="true">
{# bottom bar #}
<div class="columns pt-1">
<div class="field has-addons column">
<div class="control">
{% include 'snippets/toggle/toggle_button.html' with text="Include spoiler alert" icon="warning is-size-4" controls_text="spoilers" controls_uid=uuid focus="id_content_warning" checkbox="id_show_spoilers" class="toggle-button" pressed=status.content_warning %}
</div>
<div class="control">
{% include 'snippets/privacy_select.html' with current=reply_parent.privacy%}
</div>
</div>
<div class="column is-narrow">
<button class="button is-link" type="submit">Post</button>
</div>
</div>
</form>

View file

@ -0,0 +1,13 @@
{% extends 'snippets/components/modal.html' %}
{% block modal-title %}Delete these read dates?{% endblock %}
{% block modal-footer %}
<form name="delete-readthrough-{{ readthrough.id }}" action="/delete-readthrough" method="POST">
{% csrf_token %}
<input type="hidden" name="id" value="{{ readthrough.id }}">
<button class="button is-danger" type="submit">
Delete
</button>
{% include 'snippets/toggle/toggle_button.html' with text="Cancel" controls_text="delete-readthrough" controls_uid=readthrough.id %}
</form>
{% endblock %}

View file

@ -1,49 +1,46 @@
{% load bookwyrm_tags %}
<div>
<input class="toggle-control" type="checkbox" name="finish-reading-{{ uuid }}" id="finish-reading-{{ uuid }}">
<div class="modal toggle-content hidden">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Finish "{{ book.title }}"</p>
{% include 'snippets/toggle/toggle_button.html' with label="close" controls_text="finish-reading" controls_uid=uuid class="delete" %}
</header>
{% active_read_through book user as readthrough %}
<form name="finish-reading" action="/finish-reading/{{ book.id }}" method="post">
<section class="modal-card-body">
{% csrf_token %}
<input type="hidden" name="id" value="{{ readthrough.id }}">
<div class="field">
<label class="label">
Started reading
<input type="date" name="start_date" class="input" id="finish_id_start_date-{{ uuid }}" value="{{ readthrough.start_date | date:"Y-m-d" }}">
</label>
</div>
<div class="field">
<label class="label">
Finished reading
<input type="date" name="finish_date" class="input" id="id_finish_date-{{ uuid }}" value="{% now "Y-m-d" %}">
</label>
</div>
</section>
<footer class="modal-card-foot">
<div class="columns">
<div class="column field">
<label for="post_status-{{ uuid }}">
<input type="checkbox" name="post-status" class="checkbox" id="post_status-{{ uuid }}" checked>
Post to feed
</label>
{% include 'snippets/privacy_select.html' %}
</div>
<div class="column">
<button type="submit" class="button is-success">Save</button>
{% include 'snippets/toggle/toggle_button.html' with text="Cancel" controls_text="finish-reading" controls_uid=uuid %}
</div>
</div>
</footer>
</form>
</div>
<label class="modal-close is-large" for="finish-reading-{{ uuid }}" aria-label="close" role="button"></label>
{% extends 'snippets/components/modal.html' %}
{% block modal-title %}
Finish "<em>{{ book.title }}</em>"
{% endblock %}
{% block modal-form-open %}
<form name="finish-reading" action="/finish-reading/{{ book.id }}" method="post">
{% endblock %}
{% block modal-body %}
<section class="modal-card-body">
{% csrf_token %}
<input type="hidden" name="id" value="{{ readthrough.id }}">
<div class="field">
<label class="label">
Started reading
<input type="date" name="start_date" class="input" id="finish_id_start_date-{{ uuid }}" value="{{ readthrough.start_date | date:"Y-m-d" }}">
</label>
</div>
<div class="field">
<label class="label">
Finished reading
<input type="date" name="finish_date" class="input" id="id_finish_date-{{ uuid }}" value="{% now "Y-m-d" %}">
</label>
</div>
</section>
{% endblock %}
{% block modal-footer %}
<div class="columns">
<div class="column field">
<label for="post_status-{{ uuid }}">
<input type="checkbox" name="post-status" class="checkbox" id="post_status-{{ uuid }}" checked>
Post to feed
</label>
{% include 'snippets/privacy_select.html' %}
</div>
<div class="column">
<button type="submit" class="button is-success">Save</button>
{% include 'snippets/toggle/close_button.html' with text="Cancel" controls_text="finish-reading" controls_uid=uuid %}
</div>
</div>
{% endblock %}
{% block modal-form-close %}</form>{% endblock %}

View file

@ -0,0 +1,23 @@
{% extends 'snippets/components/card.html' %}
{% block card-header %}
<h3 class="card-header-title has-background-primary has-text-white">
<span class="icon icon-book is-size-3 mr-2" aria-hidden="true"></span> {{ year }} reading goal
</h3>
{% endblock %}
{% block card-content %}
<div class="content">
<p>Set a goal for how many books you'll finish reading in {{ year }}, and track your progress throughout the year.</p>
{% include 'snippets/goal_form.html' %}
</div>
{% endblock %}
{% block card-footer %}
<div class="card-footer-item is-flex-direction-column">
<button class="button is-danger is-light is-block set-display" data-id="hide-{{ year }}-reading-goal" data-value="true">Dismiss message</button>
<p class="help">You can set or change your reading goal any time from your <a href="{{ request.user.local_path }}">profile page</a></p>
</div>
{% endblock %}

View file

@ -28,7 +28,7 @@
<p>
<button type="submit" class="button is-link">Set goal</button>
{% if goal %}
{% include 'snippets/toggle/toggle_button.html' with text="Cancel" controls_text="hide-edit-goal" %}
{% include 'snippets/toggle/close_button.html' with text="Cancel" controls_text="show-edit-goal" %}
{% endif %}
</p>
</form>

View file

@ -1,5 +1,5 @@
{% load bookwyrm_tags %}
<div class="select">
<div class="select {{ class }}">
{% with 0|uuid as uuid %}
{% if not no_label %}
<label class="is-sr-only" for="privacy-{{ uuid }}">Post privacy</label>
@ -12,7 +12,7 @@
Unlisted
</option>
<option value="followers" {% if current == 'followers' %}selected{% endif %}>
Followers only
Followers
</option>
<option value="direct" {% if current == 'direct' %}selected{% endif %}>
Private

View file

@ -1,18 +1,33 @@
{% load bookwyrm_tags %}
{% if request.user.is_authenticated %}
<span class="is-sr-only">Leave a rating</span>
<div class="field is-grouped stars rate-stars">
{% for i in '12345'|make_list %}
<form name="rate" action="/rate/" method="POST">
<div class="block">
<form class="hidden-form" name="rate" action="/post/rating" method="POST">
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
<input type="hidden" name="book" value="{{ book.id }}">
<input type="hidden" name="privacy" value="public">
<input type="hidden" name="rating" value="{{ forloop.counter }}">
<button type="submit" class="icon icon-star-{% if book|rating:user < forloop.counter %}empty{% else %}full{% endif %}">
<span class="is-sr-only">{{ forloop.counter }} star{{ forloop.counter | pluralize }}</span>
</button>
<div class="field is-grouped stars form-rate-stars mb-1">
<label class="is-sr-only" for="no-rating-{{ book.id }}">No rating</label>
<input class="is-sr-only" type="radio" name="rating" value="" id="no-rating-{{ book.id }}" checked>
{% for i in '12345'|make_list %}
<input class="is-sr-only" id="book{{book.id}}-star-{{ forloop.counter }}" type="radio" name="rating" value="{{ forloop.counter }}" {% if book|rating:user == forloop.counter %}checked{% endif %}>
<label class="icon icon-star-empty" for="book{{book.id}}-star-{{ forloop.counter }}">
<span class="is-sr-only">{{ forloop.counter }} star{{ forloop.counter | pluralize }}</span>
</label>
{% endfor %}
</div>
<div class="field has-addons hidden">
<div class="control">
{% include 'snippets/privacy_select.html' with class="is-small" %}
</div>
<div class="control">
<button class="button is-small is-primary" type="submit">Rate</button>
</div>
</div>
</form>
{% endfor %}
</div>
{% endif %}

View file

@ -1,7 +1,6 @@
{% load humanize %}
<div class="content block">
<input class="toggle-control" type="radio" name="show-edit-readthrough-{{ readthrough.id }}" id="show-readthrough-{{ readthrough.id }}" checked>
<div class="toggle-content hidden">
<div id="hide-edit-readthrough-{{ readthrough.id }}">
<dl class="mb-1">
{% if readthrough.start_date %}
<div class="is-flex">
@ -25,9 +24,13 @@
</div>
{% endif %}
</dl>
<div class="field is-grouped">
{% include 'snippets/toggle/toggle_button.html' with small=True text="Edit read dates" icon="pencil" controls_text="edit-readthrough" controls_uid=readthrough.id %}
{% include 'snippets/toggle/toggle_button.html' with small=True text="Delete these read dates" icon="x" controls_text="delete-readthrough" controls_uid=readthrough.id %}
<div class="field has-addons">
<div class="control">
{% include 'snippets/toggle/toggle_button.html' with class="is-small" text="Edit read dates" icon="pencil" controls_text="edit-readthrough" controls_uid=readthrough.id focus="edit-readthrough" %}
</div>
<div class="control">
{% include 'snippets/toggle/toggle_button.html' with class="is-small" text="Delete these read dates" icon="x" controls_text="delete-readthrough" controls_uid=readthrough.id focus="modal-title-delete-readthrough" %}
</div>
</div>
{% if show_progress %}
Progress Updates:
@ -62,41 +65,14 @@
</div>
</div>
<div class="block">
<input class="toggle-control" type="radio" name="show-edit-readthrough-{{ readthrough.id }}" id="edit-readthrough-{{ readthrough.id }}">
<div class="toggle-content hidden">
<div class="box">
<form name="edit-readthrough" action="/edit-readthrough" method="post">
{% include 'snippets/readthrough_form.html' with readthrough=readthrough %}
<div class="field is-grouped">
<button class="button is-primary" type="submit">Save</button>
{% include 'snippets/toggle/toggle_button.html' with text="Cancel" controls_text="show-readthrough" controls_uid=readthrough.id %}
</div>
</form>
<div class="box hidden" id="edit-readthrough-{{ readthrough.id }}" tabindex="0">
<h3 class="title is-5">Edit read dates</h3>
<form name="edit-readthrough" action="/edit-readthrough" method="post">
{% include 'snippets/readthrough_form.html' with readthrough=readthrough %}
<div class="field is-grouped">
<button class="button is-primary" type="submit">Save</button>
{% include 'snippets/toggle/close_button.html' with text="Cancel" controls_text="edit-readthrough" controls_uid=readthrough.id %}
</div>
</div>
</div>
<div>
<input class="toggle-control" type="checkbox" name="delete-readthrough-{{ readthrough.id }}" id="delete-readthrough-{{ readthrough.id }}">
<div class="modal toggle-content hidden">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Delete this read-though?</p>
<label class="delete" for="delete-readthrough-{{ readthrough.id }}" aria-label="close"></label>
</header>
<footer class="modal-card-foot">
<form name="delete-readthrough-{{ readthrough.id }}" action="/delete-readthrough" method="POST">
{% csrf_token %}
<input type="hidden" name="id" value="{{ readthrough.id }}">
<button class="button is-danger is-light" type="submit">
Delete
</button>
{% include 'snippets/toggle/toggle_button.html' with text="Cancel" controls_text="delete-readthrough" controls_uid=readthrough.id %}
</form>
</footer>
</div>
<label class="modal-close is-large" for="delete-readthrough-{{ readthrough.id }}" aria-label="close"></label>
</div>
</form>
</div>
{% include 'snippets/delete_readthrough_modal.html' with controls_text="delete-readthrough" controls_uid=readthrough.id %}

View file

@ -1,25 +0,0 @@
{% load bookwyrm_tags %}
<form class="is-flex-grow-1" name="reply" action="/post/reply" method="post">
<div class="columns is-align-items-flex-end">
{% csrf_token %}
<input type="hidden" name="reply_parent" value="{{ status.id }}">
<input type="hidden" name="user" value="{{ request.user.id }}">
<div class="column">
{% include 'snippets/content_warning_field.html' with parent_status=status %}
<label for="id_content_{{ status.id }}-{{ uuid }}" class="is-sr-only">Reply</label>
<div class="field">
<textarea class="textarea" name="content" placeholder="Leave a comment..." id="id_content_{{ status.id }}-{{ uuid }}" required="true"></textarea>
</div>
</div>
<div class="column is-narrow">
<div class="field">
{% include 'snippets/privacy_select.html' with current=status.privacy %}
</div>
<div class="field">
<button class="button is-primary" type="submit">
post reply
</button>
</div>
</div>
</div>
</form>

View file

@ -1,36 +1,29 @@
<div class="dropdown">
<div class="dropdown-trigger">
<label for="shelf-select-dropdown-{{ book.id }}-toggle" role="button" aria-expanded="false" class="pulldown-menu" tabindex="0" aria-haspopup="true" aria-controls="shelf-select-{{ book.id }}">
<div class="button">
<span>Change shelf</span>
<span class="icon icon-arrow-down" aria-hidden="true"></span>
</div>
</label>
</div>
<input type="checkbox" class="toggle-control" id="shelf-select-dropdown-{{ book.id }}-toggle">
<div class="dropdown-menu toggle-content hidden" id="shelf-select-{{ book.id }}" role="menu">
<ul class="dropdown-content">
{% for shelf in request.user.shelf_set.all %}
{% if shelf.identifier != current.identifier %}
<li role="menuitem">
<form class="dropdown-item pt-0 pb-0" name="shelve" action="/shelve/" method="post">
{% csrf_token %}
<input type="hidden" name="book" value="{{ book.id }}">
<input type="hidden" name="shelf" value="{{ shelf.identifier }}">
<button class="button is-small" type="submit">{{ shelf.name }}</button>
</form>
</li>
{% endif %}
{% endfor %}
<hr class="navbar-divider">
<li>
<form class="dropdown-item pt-0 pb-0" name="shelve" action="/unshelve/" method="post">
{% csrf_token %}
<input type="hidden" name="book" value="{{ book.id }}">
<input type="hidden" name="shelf" value="{{ current.id }}">
<button class="button is-small is-danger is-light" type="submit">Unshelve</button>
</form>
</li>
</ul>
</div>
</div>
{% extends 'snippets/components/dropdown.html' %}
{% block dropdown-trigger %}
<span>Change shelf</span>
<span class="icon icon-arrow-down" aria-hidden="true"></span>
{% endblock %}
{% block dropdown-list %}
{% for shelf in request.user.shelf_set.all %}
{% if shelf.identifier != current.identifier %}
<li role="menuitem">
<form class="dropdown-item pt-0 pb-0" name="shelve" action="/shelve/" method="post">
{% csrf_token %}
<input type="hidden" name="book" value="{{ book.id }}">
<input type="hidden" name="shelf" value="{{ shelf.identifier }}">
<button class="button is-fullwidth is-small" type="submit">{{ shelf.name }}</button>
</form>
</li>
{% endif %}
{% endfor %}
<hr class="navbar-divider">
<li>
<form class="dropdown-item pt-0 pb-0" name="shelve" action="/unshelve/" method="post">
{% csrf_token %}
<input type="hidden" name="book" value="{{ book.id }}">
<input type="hidden" name="shelf" value="{{ current.id }}">
<button class="button is-fullwidth is-small is-danger is-light" type="submit">Unshelve</button>
</form>
</li>
{% endblock %}

View file

@ -3,63 +3,38 @@
{% with book.id|uuid as uuid %}
{% active_shelf book as active_shelf %}
<div class="field is-grouped">
<div class="field has-addons">
{% if switch_mode and active_shelf.book != book %}
{% include 'snippets/switch_edition_button.html' with edition=book size='is-small' %}
{% else %}
{% if active_shelf.shelf.identifier == 'read' %}
<button class="button is-small" disabled>
<span>Read</span> <span class="icon icon-check"></span>
</button>
{% elif active_shelf.shelf.identifier == 'reading' %}
{% include 'snippets/toggle/toggle_button.html' with small=True text="I'm done!" controls_text="finish-reading" controls_uid=uuid %}
{% elif active_shelf.shelf.identifier == 'to-read' %}
{% include 'snippets/toggle/toggle_button.html' with small=True text="Start reading" controls_text="start-reading" controls_uid=uuid %}
{% else %}
<form name="shelve" action="/shelve/" method="post">
{% csrf_token %}
<input type="hidden" name="book" value="{{ active_shelf.book.id }}">
<input type="hidden" name="shelf" value="to-read">
<button class="button is-small" type="submit">Want to read</button>
</form>
{% endif %}
<div class="dropdown">
<div class="dropdown-trigger">
<label for="shelf-select-dropdown-{{ uuid }}-toggle" role="button" aria-expanded="false" class="pulldown-menu" tabindex="0" aria-haspopup="true" aria-controls="shelf-select-{{ uuid }}">
<div class="button is-small">
<span class="icon icon-arrow-down"><span class="is-sr-only">More shelves</span></span>
</div>
</label>
</div>
<input type="checkbox" class="toggle-control" id="shelf-select-dropdown-{{ uuid }}-toggle">
<div class="dropdown-menu toggle-content hidden" id="shelf-select-{{ uuid }}" role="menu">
<ul class="dropdown-content">
{% for shelf in request.user.shelf_set.all %}
<li role="menuitem">
{% if active_shelf.shelf.identifier != 'reading' and shelf.identifier == 'reading' %}
<div class="dropdown-item pt-0 pb-0">
{% include 'snippets/toggle/toggle_button.html' with small=True text="Start reading" controls_text="start-reading" controls_uid=uuid %}
</div>
{% else %}
<form class="dropdown-item pt-0 pb-0" name="shelve" action="/shelve/" method="post">
{% csrf_token %}
<input type="hidden" name="book" value="{{ active_shelf.book.id }}">
<button class="button is-small" name="shelf" type="submit" value="{{ shelf.identifier }}" {% if shelf in book.shelf_set.all %} disabled {% endif %}>
<span>{{ shelf.name }}</span>
{% if shelf in book.shelf_set.all %}<span class="icon icon-check"></span>{% endif %}
</button>
</form>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
<div class="control">
{% include 'snippets/switch_edition_button.html' with edition=book size='is-small' %}
</div>
{% else %}
<div class="control">
{% if active_shelf.shelf.identifier == 'read' %}
<button class="button is-small" disabled>
<span>Read</span> <span class="icon icon-check"></span>
</button>
{% elif active_shelf.shelf.identifier == 'reading' %}
{% include 'snippets/toggle/toggle_button.html' with class="is-small" text="I'm done!" controls_text="finish-reading" controls_uid=uuid focus="modal-title-finish-reading" %}
{% elif active_shelf.shelf.identifier == 'to-read' %}
{% include 'snippets/toggle/toggle_button.html' with class="is-small" text="Start reading" controls_text="start-reading" controls_uid=uuid focus="modal-title-start-reading" %}
{% else %}
<form name="shelve" action="/shelve/" method="post">
{% csrf_token %}
<input type="hidden" name="book" value="{{ active_shelf.book.id }}">
<input type="hidden" name="shelf" value="to-read">
<button class="button is-small" type="submit">Want to read</button>
</form>
{% endif %}
</div>
{% include 'snippets/shelve_button_dropdown.html' with class="is-small" button_uuid=uuid%}
{% endif %}
</div>
{% include 'snippets/start_reading_modal.html' with book=active_shelf.book %}
{% include 'snippets/finish_reading_modal.html' with book=active_shelf.book %}
{% include 'snippets/start_reading_modal.html' with book=active_shelf.book controls_text="start-reading" controls_uid=uuid %}
{% latest_read_through book request.user as readthrough %}
{% include 'snippets/finish_reading_modal.html' with book=active_shelf.book controls_text="finish-reading" controls_uid=uuid readthrough=readthrough %}
{% endwith %}
{% endif %}

View file

@ -0,0 +1,28 @@
{% extends 'snippets/components/dropdown.html' %}
{% block dropdown-trigger %}
<span class="icon icon-arrow-down">
<span class="is-sr-only">More shelves</span>
</span>
{% endblock %}
{% block dropdown-list %}
{% for shelf in request.user.shelf_set.all %}
<li role="menuitem">
{% if active_shelf.shelf.identifier != 'reading' and shelf.identifier == 'reading' %}
<div class="dropdown-item pt-0 pb-0">
{% include 'snippets/toggle/toggle_button.html' with class="is-fullwidth is-small" text="Start reading" controls_text="start-reading" controls_uid=button_uuid focus="modal-title-start-reading" %}
</div>
{% else %}
<form class="dropdown-item pt-0 pb-0" name="shelve" action="/shelve/" method="post">
{% csrf_token %}
<input type="hidden" name="book" value="{{ active_shelf.book.id }}">
<button class="button is-fullwidth is-small" name="shelf" type="submit" value="{{ shelf.identifier }}" {% if shelf in book.shelf_set.all %} disabled {% endif %}>
<span>{{ shelf.name }}</span>
{% if shelf in book.shelf_set.all %}<span class="icon icon-check"></span>{% endif %}
</button>
</form>
{% endif %}
</li>
{% endfor %}
{% endblock %}

View file

@ -1,39 +1,38 @@
<div>
<input class="toggle-control" type="checkbox" name="start-reading-{{ uuid }}" id="start-reading-{{ uuid }}">
<div class="modal toggle-content hidden">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Start "{{ book.title }}"</p>
{% include 'snippets/toggle/toggle_button.html' with label="close" controls_text="start-reading" controls_uid=uuid class="delete" %}
</header>
<form name="start-reading" action="/start-reading/{{ book.id }}" method="post">
<section class="modal-card-body">
{% csrf_token %}
<div class="field">
<label class="label">
Started reading
<input type="date" name="start_date" class="input" id="start_id_start_date-{{ uuid }}" value="{% now "Y-m-d" %}">
</label>
</div>
</section>
<footer class="modal-card-foot">
<div class="columns">
<div class="column field">
<label for="post_status_start-{{ uuid }}">
<input type="checkbox" name="post-status" class="checkbox" id="post_status_start-{{ uuid }}" checked>
Post to feed
</label>
{% include 'snippets/privacy_select.html' %}
</div>
<div class="column">
<button class="button is-success" type="submit">Save</button>
{% include 'snippets/toggle/toggle_button.html' with text="Cancel" controls_text="start-reading" controls_uid=uuid %}
</div>
</div>
</footer>
</form>
</div>
<label class="modal-close is-large" for="start-reading-{{ uuid }}" aria-label="close"></label>
{% extends 'snippets/components/modal.html' %}
{% block modal-title %}
Start "<em>{{ book.title }}</em>"
{% endblock %}
{% block modal-form-open %}
<form name="start-reading" action="/start-reading/{{ book.id }}" method="post">
{% endblock %}
{% block modal-body %}
<section class="modal-card-body">
{% csrf_token %}
<div class="field">
<label class="label">
Started reading
<input type="date" name="start_date" class="input" id="start_id_start_date-{{ uuid }}" value="{% now "Y-m-d" %}">
</label>
</div>
</section>
{% endblock %}
{% block modal-footer %}
<div class="columns">
<div class="column field">
<label for="post_status_start-{{ uuid }}">
<input type="checkbox" name="post-status" class="checkbox" id="post_status_start-{{ uuid }}" checked>
Post to feed
</label>
{% include 'snippets/privacy_select.html' %}
</div>
<div class="column">
<button class="button is-success" type="submit">Save</button>
{% include 'snippets/toggle/toggle_button.html' with text="Cancel" controls_text="start-reading" controls_uid=uuid %}
</div>
</div>
{% endblock %}
{% block modal-form-close %}</form>{% endblock %}

View file

@ -1,101 +1,77 @@
{% extends 'snippets/components/card.html' %}
{% load bookwyrm_tags %}
{% load humanize %}
{% if not status.deleted %}
<article class="card">
<header class="card-header">
<div class="card-header-title has-background-white-ter">
<div class="columns">
<div class="column is-narrow">
{% include 'snippets/status_header.html' with status=status %}
</div>
</div>
{% block card-header %}
<h3 class="card-header-title has-background-white-ter is-block">
{% include 'snippets/status_header.html' with status=status %}
</h3>
{% endblock %}
{% block card-content %}
{% include 'snippets/status_content.html' with status=status %}
{% endblock %}
{% block card-footer %}
<div class="card-footer-item">
{% if request.user.is_authenticated %}
<div class="field has-addons">
<div class="control">
{% include 'snippets/toggle/toggle_button.html' with controls_text="show-comment" controls_uid=status.id text="Reply" icon="comment" class="is-small" focus="id_content_reply" %}
</div>
</header>
<section class="card-content">
{% include 'snippets/status_content.html' with status=status %}
</section>
<footer>
<div class="card-footer has-background-white-bis">
<div class="card-footer-item">
{% if request.user.is_authenticated %}
{% include 'snippets/toggle/toggle_button.html' with controls_text="show-comment" controls_uid=status.id text="Reply" icon='comment' small=True %}
{% include 'snippets/boost_button.html' with status=status %}
{% include 'snippets/fav_button.html' with status=status %}
{% else %}
<a href="/login">
<span class="icon icon-comment" title="Reply">
<span class="is-sr-only">Reply</span>
</span>
<span class="icon icon-boost" title="Boost status">
<span class="is-sr-only">Boost status</span>
</span>
<span class="icon icon-heart" title="Like status">
<span class="is-sr-only">Like status</span>
</span>
</a>
{% endif %}
</div>
<div class="card-footer-item">
{% include 'snippets/privacy-icons.html' with item=status %}
</div>
<div class="card-footer-item">
<a href="{{ status.remote_id }}">{{ status.published_date | post_date }}</a>
</div>
{% if status.user == request.user %}
<div class="card-footer-item">
{% include 'snippets/toggle/toggle_button.html' with controls_text="more-info" controls_uid=status.id text="More options" icon="dots-three" small=True %}
</div>
{% endif %}
<div class="control">
{% include 'snippets/boost_button.html' with status=status %}
</div>
{% if request.user.is_authenticated %}
{% with status.id|uuid as uuid %}
<input class="toggle-control" type="checkbox" name="show-comment-{{ status.id }}" id="show-comment-{{ status.id }}" data-hover-target="id_content_{{ status.id }}-{{ uuid }}">
<div class="toggle-content hidden">
<div class="card-footer">
<div class="card-footer-item">
{% include 'snippets/reply_form.html' with status=status %}
</div>
</div>
<div class="control">
{% include 'snippets/fav_button.html' with status=status %}
</div>
{% endwith %}
{% endif %}
</div>
{% if status.user == request.user %}
<div>
<input class="toggle-control" type="checkbox" name="more-info-{{ status.id }}" id="more-info-{{ status.id }}">
<div class="toggle-content hidden card-footer">
{% if status.user == request.user %}
<div class="card-footer-item">
<form name="delete-{{status.id}}" action="/delete-status/{{ status.id }}" method="post">
{% csrf_token %}
<button class="button is-danger is-light" type="submit">
Delete post
</button>
</form>
</div>
{% endif %}
</div>
</div>
{% endif %}
</footer>
</article>
{% else %}
<article class="card">
<header class="card-header">
<p>
{% include 'snippets/avatar.html' with user=status.user %}
{% include 'snippets/username.html' with user=status.user %}
deleted this status
</p>
</header>
</article>
{% else %}
<a href="/login">
<span class="icon icon-comment" title="Reply">
<span class="is-sr-only">Reply</span>
</span>
<span class="icon icon-boost" title="Boost status">
<span class="is-sr-only">Boost status</span>
</span>
<span class="icon icon-heart" title="Like status">
<span class="is-sr-only">Like status</span>
</span>
</a>
{% endif %}
</div>
<div class="card-footer-item">
{% include 'snippets/privacy-icons.html' with item=status %}
</div>
<div class="card-footer-item">
<a href="{{ status.remote_id }}">{{ status.published_date | post_date }}</a>
</div>
{% if status.user == request.user %}
<div class="card-footer-item">
{% include 'snippets/status_options.html' with class="is-small" right=True %}
</div>
{% endif %}
{% endblock %}
{% block card-bonus %}
{% if request.user.is_authenticated %}
{% with status.id|uuid as uuid %}
<section class="hidden" id="show-comment-{{ status.id }}">
<div class="card-footer">
<div class="card-footer-item">
{% include 'snippets/create_status_form.html' with reply_parent=status type="reply" %}
</div>
</div>
</section>
{% endwith %}
{% endif %}
{% endblock %}

View file

@ -10,19 +10,15 @@
{% endif %}
{% if status.content_warning %}
<div class="toggle-content">
<div>
<p>{{ status.content_warning }}</p>
<input class="toggle-control" type="radio" name="toggle-status-cw-{{ status.id }}" id="hide-status-cw-{{ status.id }}" checked>
<div class="toggle-content hidden">
{% include 'snippets/toggle/toggle_button.html' with text="Show More" small=True controls_text="show-status-cw" controls_uid=status.id %}
</div>
{% include 'snippets/toggle/open_button.html' with text="show more" class="is-small" controls_text="show-status-cw" controls_uid=status.id %}
</div>
<input class="toggle-control" type="radio" name="toggle-status-cw-{{ status.id }}" id="show-status-cw-{{ status.id }}">
{% endif %}
<div{% if status.content_warning %} class="toggle-content hidden"{% endif %}>
<div{% if status.content_warning %} class="hidden" id="show-status-cw-{{ status.id }}"{% endif %}>
{% if status.content_warning %}
{% include 'snippets/toggle/toggle_button.html' with text="Show Less" small=True controls_text="hide-status-cw" controls_uid=status.id %}
{% include 'snippets/toggle/close_button.html' with text="show less" class="is-small" controls_text="show-status-cw" controls_uid=status.id %}
{% endif %}
{% if status.quote %}

View file

@ -0,0 +1,18 @@
{% extends 'snippets/components/dropdown.html' %}
{% block dropdown-trigger %}
<span class="icon icon-dots-three">
<span class="is-sr-only">More options</span>
</span>
{% endblock %}
{% block dropdown-list %}
<li role="menuitem">
<form class="dropdown-item pt-0 pb-0" name="delete-{{status.id}}" action="/delete-status/{{ status.id }}" method="post">
{% csrf_token %}
<button class="button is-danger is-light is-fullwidth is-small" type="submit">
Delete post
</button>
</form>
</li>
{% endblock %}

View file

@ -1,5 +1,5 @@
<form name="switch-edition" action="/switch-edition" method="POST">
{% csrf_token %}
<input type="hidden" name="edition" value="{{ edition.id }}">
<button class="button {{ size }}">Switch to this edition</button>
<button type="submit" class="button {{ size }}">Switch to this edition</button>
</form>

View file

@ -0,0 +1 @@
{% include 'snippets/toggle/toggle_button.html' with button_type='hide-inactive' %}

View file

@ -0,0 +1 @@
{% include 'snippets/toggle/toggle_button.html' with button_type='hide-active' %}

View file

@ -1,4 +1,13 @@
<label class="{% if class %}{{ class }}{% else %}button{% endif %}{% if small %} is-small{% endif %}" for="{{ controls_text }}{% if controls_uid %}-{{ controls_uid }}{% endif %}" tabindex="0" role="button"{% if label %} aria-label="{{ label }}"{% endif %}>
<button
type="button"
class="{% if not nonbutton %}button {% endif %}{{ class }}{% if button_type %} {{ button_type }}{% endif %}"
data-controls="{{ controls_text }}{% if controls_uid %}-{{ controls_uid }}{% endif %}"
{% if focus %}data-focus-target="{{ focus }}{% if controls_uid %}-{{ controls_uid }}{% endif %}"{% endif %}
{% if checkbox %}data-controls-checkbox="{{ checkbox }}{% if controls_uid %}-{{ controls_uid }}{% endif %}"{% endif %}
{% if label %}aria-label="{{ label }}"{% endif %}
aria-pressed="{% if pressed %}true{% else %}false{% endif %}"
>
{% if icon %}
<span class="icon icon-{{ icon }}" title="{{ text }}">
<span class="is-sr-only">{{ text }}</span>
@ -6,4 +15,4 @@
{% else %}
{{ text }}
{% endif %}
</label>
</button>

View file

@ -2,18 +2,16 @@
{% with 0|uuid as uuid %}
{% if full %}
{% with full|truncatewords_html:60 as trimmed %}
{% with full|to_markdown|safe|truncatewords_html:60 as trimmed %}
{% if trimmed != full %}
<div>
<input type="radio" name="show-hide-{{ uuid }}" id="show-{{ uuid }}" class="toggle-control" checked>
<blockquote class="content toggle-content hidden"><span dir="auto">{{ trimmed | to_markdown | safe }}</span>
{% include 'snippets/toggle/toggle_button.html' with text="show more" controls_text="hide" controls_uid=uuid class="has-text-link is-clickable" %}
<div id="hide-full-{{ uuid }}">
<blockquote class="content" id="trimmed-{{ uuid }}"><span dir="auto">{{ trimmed }}</span>
{% include 'snippets/toggle/open_button.html' with text="show more" controls_text="full" controls_uid=uuid class="is-small" %}
</blockquote>
</div>
<div>
<input type="radio" name="show-hide-{{ uuid }}" id="hide-{{ uuid }}" class="toggle-control">
<blockquote class="content toggle-content hidden"><span dir="auto">{{ full | to_markdown | safe }}</span>
{% include 'snippets/toggle/toggle_button.html' with text="show less" controls_text="show" controls_uid=uuid class="has-text-link is-clickable" %}
<div id="full-{{ uuid }}" class="hidden">
<blockquote class="content"><span dir="auto">{{ full | to_markdown | safe }}</span>
{% include 'snippets/toggle/close_button.html' with text="show less" controls_text="full" controls_uid=uuid class="is-small" %}
</blockquote>
</div>
{% else %}

View file

@ -32,7 +32,14 @@ class Login(View):
login_form = forms.LoginForm(request.POST)
localname = login_form.data['localname']
username = '%s@%s' % (localname, DOMAIN)
if '@' in localname: # looks like an email address to me
email = localname
try:
username = models.User.objects.get(email=email)
except models.User.DoesNotExist: # maybe it's a full username?
username = localname
else:
username = '%s@%s' % (localname, DOMAIN)
password = login_form.data['password']
user = authenticate(request, username=username, password=password)
if user is not None:

View file

@ -36,6 +36,8 @@ def is_bookworm_request(request):
def object_visible_to_user(viewer, obj):
''' is a user authorized to view an object? '''
if not obj:
return False
if viewer == obj.user or obj.privacy in ['public', 'unlisted']:
return True
if obj.privacy == 'followers' and \

View file

@ -65,12 +65,13 @@ class Shelf(View):
return TemplateResponse(request, 'shelf.html', data)
@method_decorator(login_required, name='dispatch')
def post(self, request, username, shelf_id):
''' user generated shelves '''
if not request.user.username == username:
return HttpResponseBadRequest()
def post(self, request, username, shelf_identifier):
''' edit a shelf '''
try:
shelf = request.user.shelf_set.get(identifier=shelf_identifier)
except models.Shelf.DoesNotExist:
return HttpResponseNotFound()
shelf = get_object_or_404(models.Shelf, id=shelf_id)
if request.user != shelf.user:
return HttpResponseBadRequest()
if not shelf.editable and request.POST.get('name') != shelf.name:

View file

@ -21,12 +21,13 @@ from .helpers import is_api_request, is_bookworm_request, object_visible_to_user
# pylint: disable= no-self-use
class Status(View):
''' the view for *posting* '''
''' get posting '''
def get(self, request, username, status_id):
''' display a particular status (and replies, etc) '''
try:
user = get_user_from_username(username)
status = models.Status.objects.select_subclasses().get(id=status_id)
status = models.Status.objects.select_subclasses().get(
id=status_id, deleted=False)
except ValueError:
return HttpResponseNotFound()
@ -51,10 +52,11 @@ class Status(View):
@method_decorator(login_required, name='dispatch')
class CreateStatus(View):
''' get posting '''
''' the view for *posting* '''
def post(self, request, status_type):
''' create status of whatever type '''
status_type = status_type[0].upper() + status_type[1:]
try:
form = getattr(forms, '%sForm' % status_type)(request.POST)
except AttributeError:

View file

@ -185,4 +185,4 @@ class EditUser(View):
user.save()
broadcast(user, user.to_update_activity(user))
return redirect('/user/%s' % request.user.localname)
return redirect(user.local_path)