Merge branch 'main' into production

This commit is contained in:
Mouse Reeve 2021-03-31 15:19:40 -07:00
commit fd91a79558
21 changed files with 2411 additions and 51 deletions

View file

@ -29,3 +29,8 @@ trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
max_line_length = off
[{package.json,yarn.lock}]
indent_size = unset
indent_style = unset
max_line_length = unset

10
.eslintrc.js Normal file
View file

@ -0,0 +1,10 @@
/* global module */
module.exports = {
"env": {
"browser": true,
"es6": true
},
"extends": "eslint:recommended"
};

29
.github/workflows/lint-frontend.yaml vendored Normal file
View file

@ -0,0 +1,29 @@
# @url https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
name: Lint Frontend
on:
push:
branches: [ main, ci ]
paths:
- '.github/workflows/**'
- 'static/**'
pull_request:
branches: [ main, ci ]
jobs:
lint:
name: Lint with stylelint and ESLint.
runs-on: ubuntu-20.04
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Install modules
run: yarn
- name: Run stylelint
run: yarn stylelint **/static/**/*.css --report-needless-disables --report-invalid-scope-disables
- name: Run ESLint
run: yarn eslint . --ext .js,.jsx,.ts,.tsx

View file

@ -1,5 +1,5 @@
# @url https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
name: Lint Project
name: Lint project globally
on:
push:
@ -8,8 +8,8 @@ on:
branches: [ main, ci ]
jobs:
linters:
name: linters
lint:
name: Lint with EditorConfig.
runs-on: ubuntu-20.04
# Steps represent a sequence of tasks that will be executed as part of the job

3
.gitignore vendored
View file

@ -21,3 +21,6 @@
#PyCharm
.idea
#Node tools
/node_modules/

2
.stylelintignore Normal file
View file

@ -0,0 +1,2 @@
bookwyrm/static/css/bulma.*.css*
bookwyrm/static/css/icons.css

17
.stylelintrc.js Normal file
View file

@ -0,0 +1,17 @@
/* global module */
module.exports = {
"extends": "stylelint-config-standard",
"plugins": [
"stylelint-order"
],
"rules": {
"order/order": [
"custom-properties",
"declarations"
],
"indentation": 4
}
};

View file

@ -15,6 +15,8 @@ class ConnectorException(HTTPError):
def search(query, min_confidence=0.1):
""" find books based on arbitary keywords """
if not query:
return []
results = []
# Have we got a ISBN ?

View file

@ -7,6 +7,7 @@ html {
.image {
overflow: hidden;
}
.navbar .logo {
max-height: 50px;
}
@ -21,25 +22,33 @@ html {
}
/* --- SHELVING --- */
/** @todo Replace icons with SVG symbols.
@see https://www.youtube.com/watch?v=9xXBYcWgCHA */
.shelf-option:disabled > *::after {
font-family: "icomoon";
font-family: "icomoon"; /* stylelint-disable font-family-no-missing-generic-family-keyword */
content: "\e918";
margin-left: 0.5em;
}
/* --- TOGGLES --- */
.toggle-button[aria-pressed=true], .toggle-button[aria-pressed=true]:hover {
.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] {
.hide-active[aria-pressed=true],
.hide-inactive[aria-pressed=false] {
display: none;
}
.hidden {
display: none !important;
}
.hidden.transition-y, .hidden.transition-x {
.hidden.transition-y,
.hidden.transition-x {
display: block !important;
visibility: hidden !important;
height: 0;
@ -47,18 +56,22 @@ html {
margin: 0;
padding: 0;
}
.transition-y {
transition-property: height, margin-top, margin-bottom, padding-top, padding-bottom;
transition-duration: 0.5s;
transition-timing-function: ease;
}
.transition-x {
transition-property: width, margin-left, margin-right, padding-left, padding-right;
transition-duration: 0.5s;
transition-timing-function: ease;
}
@media (prefers-reduced-motion: reduce) {
.transition-x, .transition-y {
.transition-x,
.transition-y {
transition-duration: 0.001ms !important;
}
}
@ -71,36 +84,46 @@ html {
margin: 0;
display: inline;
}
.rate-stars:hover .icon:before {
.rate-stars:hover .icon::before {
content: '\e9d9';
}
.rate-stars form:hover ~ form .icon:before{
.rate-stars form:hover ~ form .icon::before {
content: '\e9d7';
}
/* stars in a review form */
.form-rate-stars:hover .icon:before {
/** stars in a review form
*
* @todo Simplify the logic for those icons.
*/
.form-rate-stars input + .icon.icon::before {
content: '\e9d9';
}
.form-rate-stars input + .icon:before {
.form-rate-stars:hover .icon.icon::before {
content: '\e9d9';
}
.form-rate-stars input:checked + .icon:before {
.form-rate-stars input:checked + .icon.icon::before {
content: '\e9d9';
}
.form-rate-stars input:checked + * ~ .icon:before {
content: '\e9d7';
}
.form-rate-stars:hover label.icon:before {
content: '\e9d9';
}
.form-rate-stars label.icon:hover:before {
content: '\e9d9';
}
.form-rate-stars label.icon:hover ~ label.icon:before{
.form-rate-stars input:checked + * ~ .icon.icon::before {
content: '\e9d7';
}
.form-rate-stars:hover label.icon.icon::before {
content: '\e9d9';
}
.form-rate-stars label.icon:hover::before {
content: '\e9d9';
}
.form-rate-stars label.icon:hover ~ label.icon.icon::before {
content: '\e9d7';
}
/* --- BOOK COVERS --- */
.cover-container {
@ -108,46 +131,46 @@ html {
width: max-content;
max-width: 250px;
}
.cover-container.is-large {
height: max-content;
max-width: 330px;
}
.cover-container.is-large img {
max-height: 500px;
height: auto;
}
.cover-container.is-medium {
height: 150px;
}
.cover-container.is-small {
height: 100px;
}
@media only screen and (max-width: 768px) {
.cover-container {
height: 200px;
width: max-content;
}
.cover-container.is-medium {
height: 100px;
}
}
.cover-container.is-medium .no-cover div {
font-size: 0.9em;
padding: 0.3em;
}
.cover-container.is-small .no-cover div {
font-size: 0.7em;
padding: 0.1em;
}
.book-cover {
height: 100%;
object-fit: scale-down;
}
.no-cover {
position: relative;
white-space: normal;
}
.no-cover div {
position: absolute;
padding: 1em;
@ -157,38 +180,51 @@ html {
text-align: center;
}
.cover-container.is-medium .no-cover div {
font-size: 0.9em;
padding: 0.3em;
}
.cover-container.is-small .no-cover div {
font-size: 0.7em;
padding: 0.1em;
}
/* --- AVATAR --- */
.avatar {
vertical-align: middle;
display: inline;
}
.is-32x32 {
min-width: 32px;
min-height: 32px;
}
.is-96x96 {
min-width: 96px;
min-height: 96px;
}
/* --- QUOTES --- */
.quote blockquote {
position: relative;
padding-left: 2em;
}
.quote blockquote:before, .quote blockquote:after {
.quote blockquote::before,
.quote blockquote::after {
font-family: 'icomoon';
position: absolute;
}
.quote blockquote:before {
.quote blockquote::before {
content: "\e906";
top: 0;
left: 0;
}
.quote blockquote:after {
.quote blockquote::after {
content: "\e905";
right: 0;
}

View file

@ -1,4 +1,4 @@
// Toggle all checkboxes.
/* exported toggleAllCheckboxes */
/**
* Toggle all descendant checkboxes of a target.

View file

@ -1,3 +1,6 @@
/* exported updateDisplay */
/* globals addRemoveClass */
// set javascript listeners
function updateDisplay(e) {
// used in set reading goal

View file

@ -1,3 +1,5 @@
/* globals setDisplay TabGroup toggleAllCheckboxes updateDisplay */
// set up javascript listeners
window.onload = function() {
// buttons that display or hide content
@ -93,7 +95,7 @@ function toggleAction(e) {
// show/hide container
var container = document.getElementById('hide-' + targetId);
if (!!container) {
if (container) {
addRemoveClass(container, 'hidden', pressed);
}

View file

@ -1,3 +1,5 @@
/* exported TabGroup */
/*
* The content below is licensed according to the W3C Software License at
* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document

View file

@ -55,11 +55,9 @@
</h2>
<div class="columns is-multiline">
{% for book in goal.books %}
<div class="column is-narrow">
<div class="box">
<a href="{{ book.book.local_path }}">
{% include 'discover/small-book.html' with book=book.book rating=goal.ratings %}
</a>
<div class="column is-one-fifth">
<div class="is-clipped">
<a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=book.book %}</a>
</div>
</div>
{% endfor %}

View file

@ -1,7 +1,7 @@
{% load bookwyrm_tags %}
<div class="cover-container is-{{ size }}">
{% if book.cover %}
<img class="book-cover" src="/images/{{ book.cover }}" alt="{{ book.alt_text }}">
<img class="book-cover" src="/images/{{ book.cover }}" alt="{{ book.alt_text }}" title="{{ book.alt_text }}">
{% else %}
<div class="no-cover book-cover">
<img class="book-cover" src="/static/images/no_cover.jpg" alt="No cover">

View file

@ -12,7 +12,7 @@
<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="change-shelf-from" value={{ current.identifier }}>
<input type="hidden" name="change-shelf-from" value="{{ current.identifier }}">
<input type="hidden" name="shelf" value="{{ shelf.identifier }}">
<button class="button is-fullwidth is-small" type="submit">{{ shelf.name }}</button>
</form>

View file

@ -111,7 +111,12 @@
{% endif %}
{% if shelf.user == request.user %}
<td>
{% include 'snippets/shelf_selector.html' with current=shelf %}
{% if not shelf.id %}
{% active_shelf book as current %}
{% include 'snippets/shelf_selector.html' with current=current.shelf class="is-small" %}
{% else %}
{% include 'snippets/shelf_selector.html' with current=shelf class="is-small" %}
{% endif %}
</td>
{% endif %}
</tr>

View file

@ -31,7 +31,7 @@ class Search(View):
return JsonResponse([r.json() for r in book_results], safe=False)
# use webfinger for mastodon style account@domain.com username
if re.match(r"\B%s" % regex.full_username, query):
if query and re.match(regex.full_username, query):
handle_remote_webfinger(query)
# do a user search
@ -73,6 +73,6 @@ class Search(View):
"book_results": book_results,
"user_results": user_results,
"list_results": list_results,
"query": query,
"query": query or "",
}
return TemplateResponse(request, "search_results.html", data)

View file

@ -102,7 +102,7 @@ def create_shelf(request):
return redirect(request.headers.get("Referer", "/"))
shelf = form.save()
return redirect("/user/%s/shelf/%s" % (request.user.localname, shelf.identifier))
return redirect(shelf.local_path)
@login_required
@ -114,7 +114,7 @@ def delete_shelf(request, shelf_id):
return HttpResponseBadRequest()
shelf.delete()
return redirect("/user/%s/shelves" % request.user.localname)
return redirect("user-shelves", request.user.localname)
@login_required

8
package.json Normal file
View file

@ -0,0 +1,8 @@
{
"devDependencies": {
"eslint": "^7.23.0",
"stylelint": "^13.12.0",
"stylelint-config-standard": "^21.0.0",
"stylelint-order": "^4.1.0"
}
}

2238
yarn.lock Normal file

File diff suppressed because it is too large Load diff