mirror of
https://github.com/sissbruecker/linkding.git
synced 2025-08-11 20:57:49 +02:00
Minify bookmark list HTML (#332)
This commit is contained in:
@@ -5,42 +5,42 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{% include 'bookmarks/bulk_edit/state.html' %}
|
{% include 'bookmarks/bulk_edit/state.html' %}
|
||||||
|
|
||||||
<div class="bookmarks-page columns">
|
<div class="bookmarks-page columns">
|
||||||
|
|
||||||
{# Bookmark list #}
|
{# Bookmark list #}
|
||||||
<section class="content-area column col-8 col-md-12">
|
<section class="content-area column col-8 col-md-12">
|
||||||
<div class="content-area-header">
|
<div class="content-area-header">
|
||||||
<h2>Archived bookmarks</h2>
|
<h2>Archived bookmarks</h2>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
{% bookmark_search filters tags mode='archived' %}
|
{% bookmark_search filters tags mode='archived' %}
|
||||||
{% include 'bookmarks/bulk_edit/toggle.html' %}
|
{% include 'bookmarks/bulk_edit/toggle.html' %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="bookmark-actions" action="{% url 'bookmarks:action' %}?return_url={{ return_url }}"
|
<form class="bookmark-actions" action="{% url 'bookmarks:action' %}?return_url={{ return_url }}"
|
||||||
method="post">
|
method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% include 'bookmarks/bulk_edit/bar.html' with mode='archive' %}
|
{% include 'bookmarks/bulk_edit/bar.html' with mode='archive' %}
|
||||||
|
|
||||||
{% if empty %}
|
{% if empty %}
|
||||||
{% include 'bookmarks/empty_bookmarks.html' %}
|
{% include 'bookmarks/empty_bookmarks.html' %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% bookmark_list bookmarks return_url link_target %}
|
{% bookmark_list bookmarks return_url link_target %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{# Tag list #}
|
{# Tag list #}
|
||||||
<section class="content-area column col-4 hide-md">
|
<section class="content-area column col-4 hide-md">
|
||||||
<div class="content-area-header">
|
<div class="content-area-header">
|
||||||
<h2>Tags</h2>
|
<h2>Tags</h2>
|
||||||
</div>
|
</div>
|
||||||
{% tag_cloud tags selected_tags %}
|
{% tag_cloud tags selected_tags %}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="{% static "bundle.js" %}"></script>
|
<script src="{% static "bundle.js" %}"></script>
|
||||||
<script src="{% static "shared.js" %}"></script>
|
<script src="{% static "shared.js" %}"></script>
|
||||||
<script src="{% static "bookmark_list.js" %}"></script>
|
<script src="{% static "bookmark_list.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -1,91 +1,98 @@
|
|||||||
{% load shared %}
|
{% load shared %}
|
||||||
{% load pagination %}
|
{% load pagination %}
|
||||||
|
{% htmlmin %}
|
||||||
<ul class="bookmark-list">
|
<ul class="bookmark-list">
|
||||||
{% for bookmark in bookmarks %}
|
{% for bookmark in bookmarks %}
|
||||||
<li data-is-bookmark-item>
|
<li data-is-bookmark-item>
|
||||||
<label class="form-checkbox bulk-edit-toggle">
|
<label class="form-checkbox bulk-edit-toggle">
|
||||||
<input type="checkbox" name="bookmark_id" value="{{ bookmark.id }}">
|
<input type="checkbox" name="bookmark_id" value="{{ bookmark.id }}">
|
||||||
<i class="form-icon"></i>
|
<i class="form-icon"></i>
|
||||||
</label>
|
</label>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<a href="{{ bookmark.url }}" target="{{ link_target }}" rel="noopener"
|
<a href="{{ bookmark.url }}" target="{{ link_target }}" rel="noopener"
|
||||||
class="{% if bookmark.unread %}text-italic{% endif %}">
|
class="{% if bookmark.unread %}text-italic{% endif %}">
|
||||||
{{ bookmark.resolved_title }}
|
{{ bookmark.resolved_title }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="description truncate">
|
||||||
|
{% if bookmark.tag_names %}
|
||||||
|
<span>
|
||||||
|
{% for tag_name in bookmark.tag_names %}
|
||||||
|
<a href="?{% append_to_query_param q=tag_name|hash_tag %}">{{ tag_name|hash_tag }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if bookmark.tag_names and bookmark.resolved_description %} | {% endif %}
|
||||||
|
{% if bookmark.resolved_description %}
|
||||||
|
<span>{{ bookmark.resolved_description }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
{% if request.user.profile.bookmark_date_display == 'relative' %}
|
||||||
|
<span class="date-label text-gray text-sm">
|
||||||
|
{% if bookmark.web_archive_snapshot_url %}
|
||||||
|
<a href="{{ bookmark.web_archive_snapshot_url }}"
|
||||||
|
title="Show snapshot on the Internet Archive Wayback Machine" target="{{ link_target }}"
|
||||||
|
rel="noopener">
|
||||||
|
{% endif %}
|
||||||
|
<span>{{ bookmark.date_added|humanize_relative_date }}</span>
|
||||||
|
{% if bookmark.web_archive_snapshot_url %}
|
||||||
|
<span>∞</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
{% endif %}
|
||||||
<div class="description truncate">
|
</span>
|
||||||
{% if bookmark.tag_names %}
|
<span class="text-gray text-sm">|</span>
|
||||||
<span>
|
{% endif %}
|
||||||
{% for tag_name in bookmark.tag_names %}
|
{% if request.user.profile.bookmark_date_display == 'absolute' %}
|
||||||
<a href="?{% append_to_query_param q=tag_name|hash_tag %}">{{ tag_name|hash_tag }}</a>
|
<span class="date-label text-gray text-sm">
|
||||||
{% endfor %}
|
{% if bookmark.web_archive_snapshot_url %}
|
||||||
</span>
|
<a href="{{ bookmark.web_archive_snapshot_url }}"
|
||||||
{% endif %}
|
title="Show snapshot on the Internet Archive Wayback Machine" target="{{ link_target }}"
|
||||||
{% if bookmark.tag_names and bookmark.resolved_description %} | {% endif %}
|
rel="noopener">
|
||||||
|
{% endif %}
|
||||||
{% if bookmark.resolved_description %}
|
<span>{{ bookmark.date_added|humanize_absolute_date }}</span>
|
||||||
<span>{{ bookmark.resolved_description }}</span>
|
{% if bookmark.web_archive_snapshot_url %}
|
||||||
{% endif %}
|
<span>∞</span>
|
||||||
</div>
|
</a>
|
||||||
<div class="actions">
|
{% endif %}
|
||||||
{% if request.user.profile.bookmark_date_display == 'relative' %}
|
</span>
|
||||||
<span class="date-label text-gray text-sm">
|
<span class="text-gray text-sm">|</span>
|
||||||
{% if bookmark.web_archive_snapshot_url %}
|
{% endif %}
|
||||||
<a href="{{ bookmark.web_archive_snapshot_url }}"
|
{% if bookmark.owner == request.user %}
|
||||||
title="Show snapshot on the Internet Archive Wayback Machine" target="{{ link_target }}" rel="noopener">
|
{# Bookmark owner actions #}
|
||||||
{% endif %}
|
<a href="{% url 'bookmarks:edit' bookmark.id %}?return_url={{ return_url }}"
|
||||||
<span>{{ bookmark.date_added|humanize_relative_date }}</span>
|
class="btn btn-link btn-sm">Edit</a>
|
||||||
{% if bookmark.web_archive_snapshot_url %}
|
{% if bookmark.is_archived %}
|
||||||
<span>∞</span>
|
<button type="submit" name="unarchive" value="{{ bookmark.id }}"
|
||||||
</a>
|
class="btn btn-link btn-sm">Unarchive
|
||||||
{% endif %}
|
</button>
|
||||||
</span>
|
{% else %}
|
||||||
<span class="text-gray text-sm">|</span>
|
<button type="submit" name="archive" value="{{ bookmark.id }}"
|
||||||
{% endif %}
|
class="btn btn-link btn-sm">Archive
|
||||||
{% if request.user.profile.bookmark_date_display == 'absolute' %}
|
</button>
|
||||||
<span class="date-label text-gray text-sm">
|
{% endif %}
|
||||||
{% if bookmark.web_archive_snapshot_url %}
|
<button type="submit" name="remove" value="{{ bookmark.id }}"
|
||||||
<a href="{{ bookmark.web_archive_snapshot_url }}"
|
class="btn btn-link btn-sm btn-confirmation">Remove
|
||||||
title="Show snapshot on the Internet Archive Wayback Machine" target="{{ link_target }}" rel="noopener">
|
</button>
|
||||||
{% endif %}
|
{% if bookmark.unread %}
|
||||||
<span>{{ bookmark.date_added|humanize_absolute_date }}</span>
|
<span class="text-gray text-sm">|</span>
|
||||||
{% if bookmark.web_archive_snapshot_url %}
|
<button type="submit" name="mark_as_read" value="{{ bookmark.id }}"
|
||||||
<span>∞</span>
|
class="btn btn-link btn-sm">Mark as read
|
||||||
</a>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
{% else %}
|
||||||
<span class="text-gray text-sm">|</span>
|
{# Shared bookmark actions #}
|
||||||
{% endif %}
|
<span class="text-gray text-sm">Shared by
|
||||||
{% if bookmark.owner == request.user %}
|
<a class="text-gray"
|
||||||
{# Bookmark owner actions #}
|
href="?{% replace_query_param user=bookmark.owner.username %}">{{ bookmark.owner.username }}</a>
|
||||||
<a href="{% url 'bookmarks:edit' bookmark.id %}?return_url={{ return_url }}"
|
</span>
|
||||||
class="btn btn-link btn-sm">Edit</a>
|
{% endif %}
|
||||||
{% if bookmark.is_archived %}
|
</div>
|
||||||
<button type="submit" name="unarchive" value="{{ bookmark.id }}"
|
</li>
|
||||||
class="btn btn-link btn-sm">Unarchive</button>
|
|
||||||
{% else %}
|
|
||||||
<button type="submit" name="archive" value="{{ bookmark.id }}"
|
|
||||||
class="btn btn-link btn-sm">Archive</button>
|
|
||||||
{% endif %}
|
|
||||||
<button type="submit" name="remove" value="{{ bookmark.id }}"
|
|
||||||
class="btn btn-link btn-sm btn-confirmation">Remove</button>
|
|
||||||
{% if bookmark.unread %}
|
|
||||||
<span class="text-gray text-sm">|</span>
|
|
||||||
<button type="submit" name="mark_as_read" value="{{ bookmark.id }}"
|
|
||||||
class="btn btn-link btn-sm">Mark as read</button>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
{# Shared bookmark actions #}
|
|
||||||
<span class="text-gray text-sm">Shared by
|
|
||||||
<a class="text-gray" href="?{% replace_query_param user=bookmark.owner.username %}">{{ bookmark.owner.username }}</a>
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="bookmark-pagination">
|
<div class="bookmark-pagination">
|
||||||
{% pagination bookmarks %}
|
{% pagination bookmarks %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endhtmlmin %}
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
(function() {
|
(function () {
|
||||||
var bookmarkUrl = window.location;
|
var bookmarkUrl = window.location;
|
||||||
var applicationUrl = '{{ application_url }}';
|
var applicationUrl = '{{ application_url }}';
|
||||||
|
|
||||||
applicationUrl += '?url=' + encodeURIComponent(bookmarkUrl);
|
applicationUrl += '?url=' + encodeURIComponent(bookmarkUrl);
|
||||||
applicationUrl += '&auto_close';
|
applicationUrl += '&auto_close';
|
||||||
|
|
||||||
window.open(applicationUrl);
|
window.open(applicationUrl);
|
||||||
})();
|
})();
|
||||||
|
@@ -1,31 +1,34 @@
|
|||||||
|
{% load shared %}
|
||||||
|
{% htmlmin %}
|
||||||
<div class="bulk-edit-bar">
|
<div class="bulk-edit-bar">
|
||||||
<div class="bulk-edit-actions bg-gray">
|
<div class="bulk-edit-actions bg-gray">
|
||||||
<label class="form-checkbox bulk-edit-all-toggle">
|
<label class="form-checkbox bulk-edit-all-toggle">
|
||||||
<input type="checkbox" style="display: none">
|
<input type="checkbox" style="display: none">
|
||||||
<i class="form-icon"></i>
|
<i class="form-icon"></i>
|
||||||
</label>
|
</label>
|
||||||
{% if mode == 'archive' %}
|
{% if mode == 'archive' %}
|
||||||
<button type="submit" name="bulk_unarchive" class="btn btn-link btn-sm btn-confirmation"
|
<button type="submit" name="bulk_unarchive" class="btn btn-link btn-sm btn-confirmation"
|
||||||
title="Unarchive selected bookmarks">Unarchive
|
title="Unarchive selected bookmarks">Unarchive
|
||||||
</button>
|
</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button type="submit" name="bulk_archive" class="btn btn-link btn-sm btn-confirmation"
|
<button type="submit" name="bulk_archive" class="btn btn-link btn-sm btn-confirmation"
|
||||||
title="Archive selected bookmarks">Archive
|
title="Archive selected bookmarks">Archive
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span class="text-sm text-gray-dark">•</span>
|
<span class="text-sm text-gray-dark">•</span>
|
||||||
<button type="submit" name="bulk_delete" class="btn btn-link btn-sm btn-confirmation"
|
<button type="submit" name="bulk_delete" class="btn btn-link btn-sm btn-confirmation"
|
||||||
title="Delete selected bookmarks">Delete
|
title="Delete selected bookmarks">Delete
|
||||||
</button>
|
</button>
|
||||||
<span class="text-sm text-gray-dark">•</span>
|
<span class="text-sm text-gray-dark">•</span>
|
||||||
<span class="text-sm text-gray-dark"><label for="bulk-edit-tags-input">Tags:</label></span>
|
<span class="text-sm text-gray-dark"><label for="bulk-edit-tags-input">Tags:</label></span>
|
||||||
<input id="bulk-edit-tags-input" name="bulk_tag_string" class="form-input input-sm"
|
<input id="bulk-edit-tags-input" name="bulk_tag_string" class="form-input input-sm"
|
||||||
placeholder=" ">
|
placeholder=" ">
|
||||||
<button type="submit" name="bulk_tag" class="btn btn-link btn-sm"
|
<button type="submit" name="bulk_tag" class="btn btn-link btn-sm"
|
||||||
title="Add tags to selected bookmarks">Add
|
title="Add tags to selected bookmarks">Add
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" name="bulk_untag" class="btn btn-link btn-sm"
|
<button type="submit" name="bulk_untag" class="btn btn-link btn-sm"
|
||||||
title="Remove tags from selected bookmarks">Remove
|
title="Remove tags from selected bookmarks">Remove
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endhtmlmin %}
|
||||||
|
@@ -2,7 +2,8 @@
|
|||||||
<span class="btn" title="Bulk edit">
|
<span class="btn" title="Bulk edit">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20px"
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" width="20px"
|
||||||
height="20px">
|
height="20px">
|
||||||
<path d="M7 3a1 1 0 000 2h6a1 1 0 100-2H7zM4 7a1 1 0 011-1h10a1 1 0 110 2H5a1 1 0 01-1-1zM2 11a2 2 0 012-2h12a2 2 0 012 2v4a2 2 0 01-2 2H4a2 2 0 01-2-2v-4z"/>
|
<path
|
||||||
|
d="M7 3a1 1 0 000 2h6a1 1 0 100-2H7zM4 7a1 1 0 011-1h10a1 1 0 110 2H5a1 1 0 01-1-1zM2 11a2 2 0 012-2h12a2 2 0 012 2v4a2 2 0 01-2 2H4a2 2 0 01-2-2v-4z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
{% extends "bookmarks/layout.html" %}
|
{% extends "bookmarks/layout.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
window.close()
|
window.close()
|
||||||
</script>
|
</script>
|
||||||
<p>You can now close this window.</p>
|
<p>You can now close this window.</p>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@@ -2,14 +2,15 @@
|
|||||||
{% load bookmarks %}
|
{% load bookmarks %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<section class="content-area column col-12">
|
<section class="content-area column col-12">
|
||||||
<div class="content-area-header">
|
<div class="content-area-header">
|
||||||
<h2>Edit bookmark</h2>
|
<h2>Edit bookmark</h2>
|
||||||
</div>
|
</div>
|
||||||
<form action="{% url 'bookmarks:edit' bookmark_id %}?return_url={{ return_url|urlencode }}" method="post" class="col-6 col-md-12" novalidate>
|
<form action="{% url 'bookmarks:edit' bookmark_id %}?return_url={{ return_url|urlencode }}" method="post"
|
||||||
{% bookmark_form form return_url bookmark_id %}
|
class="col-6 col-md-12" novalidate>
|
||||||
</form>
|
{% bookmark_form form return_url bookmark_id %}
|
||||||
</section>
|
</form>
|
||||||
</div>
|
</section>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
<div class="empty">
|
<div class="empty">
|
||||||
<p class="empty-title h5">You have no bookmarks yet</p>
|
<p class="empty-title h5">You have no bookmarks yet</p>
|
||||||
<p class="empty-subtitle">
|
<p class="empty-subtitle">
|
||||||
You can get started by <a href="{% url 'bookmarks:new' %}">adding</a> bookmarks,
|
You can get started by <a href="{% url 'bookmarks:new' %}">adding</a> bookmarks,
|
||||||
<a href="{% url 'bookmarks:settings.general' %}">importing</a> your existing bookmarks or configuring the
|
<a href="{% url 'bookmarks:settings.general' %}">importing</a> your existing bookmarks or configuring the
|
||||||
<a href="{% url 'bookmarks:settings.integrations' %}">browser extension</a> or the <a href="{% url 'bookmarks:settings.integrations' %}">bookmarklet</a>.
|
<a href="{% url 'bookmarks:settings.integrations' %}">browser extension</a> or the <a
|
||||||
</p>
|
href="{% url 'bookmarks:settings.integrations' %}">bookmarklet</a>.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -2,205 +2,205 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
<div class="bookmarks-form">
|
<div class="bookmarks-form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.website_title }}
|
{{ form.website_title }}
|
||||||
{{ form.website_description }}
|
{{ form.website_description }}
|
||||||
{{ form.auto_close|attr:"type:hidden" }}
|
{{ form.auto_close|attr:"type:hidden" }}
|
||||||
<div class="form-group {% if form.url.errors %}has-error{% endif %}">
|
<div class="form-group {% if form.url.errors %}has-error{% endif %}">
|
||||||
<label for="{{ form.url.id_for_label }}" class="form-label">URL</label>
|
<label for="{{ form.url.id_for_label }}" class="form-label">URL</label>
|
||||||
{{ form.url|add_class:"form-input"|attr:"autofocus"|attr:"placeholder: " }}
|
{{ form.url|add_class:"form-input"|attr:"autofocus"|attr:"placeholder: " }}
|
||||||
{% if form.url.errors %}
|
{% if form.url.errors %}
|
||||||
<div class="form-input-hint">
|
|
||||||
{{ form.url.errors }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="form-input-hint bookmark-exists">
|
|
||||||
This URL is already bookmarked. You can <a href="#">edit</a> it or you can overwrite the existing bookmark
|
|
||||||
by saving this form.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="{{ form.tag_string.id_for_label }}" class="form-label">Tags</label>
|
|
||||||
{{ form.tag_string|add_class:"form-input"|attr:"autocomplete:off" }}
|
|
||||||
<div class="form-input-hint">
|
|
||||||
Enter any number of tags separated by space and <strong>without</strong> the hash (#). If a tag does not
|
|
||||||
exist it will be
|
|
||||||
automatically created.
|
|
||||||
</div>
|
|
||||||
{{ form.tag_string.errors }}
|
|
||||||
</div>
|
|
||||||
<div class="form-group has-icon-right">
|
|
||||||
<label for="{{ form.title.id_for_label }}" class="form-label">Title</label>
|
|
||||||
<div class="has-icon-right">
|
|
||||||
{{ form.title|add_class:"form-input"|attr:"autocomplete:off" }}
|
|
||||||
<i class="form-icon loading"></i>
|
|
||||||
<a class="btn btn-link form-icon" title="Edit title from website">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
|
||||||
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"/>
|
|
||||||
<path fill-rule="evenodd"
|
|
||||||
d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"
|
|
||||||
clip-rule="evenodd"/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="form-input-hint">
|
|
||||||
Optional, leave empty to use title from website.
|
|
||||||
</div>
|
|
||||||
{{ form.title.errors }}
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="{{ form.description.id_for_label }}" class="form-label">Description</label>
|
|
||||||
<div class="has-icon-right">
|
|
||||||
{{ form.description|add_class:"form-input"|attr:"rows:2" }}
|
|
||||||
<i class="form-icon loading"></i>
|
|
||||||
<a class="btn btn-link form-icon" title="Edit description from website">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
|
||||||
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"/>
|
|
||||||
<path fill-rule="evenodd"
|
|
||||||
d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"
|
|
||||||
clip-rule="evenodd"/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="form-input-hint">
|
|
||||||
Optional, leave empty to use description from website.
|
|
||||||
</div>
|
|
||||||
{{ form.description.errors }}
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="{{ form.unread.id_for_label }}" class="form-checkbox">
|
|
||||||
{{ form.unread }}
|
|
||||||
<i class="form-icon"></i>
|
|
||||||
<span>Mark as unread</span>
|
|
||||||
</label>
|
|
||||||
<div class="form-input-hint">
|
<div class="form-input-hint">
|
||||||
Unread bookmarks can be filtered for, and marked as read after you had a chance to look at them.
|
{{ form.url.errors }}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% if request.user.profile.enable_sharing %}
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="{{ form.shared.id_for_label }}" class="form-checkbox">
|
|
||||||
{{ form.shared }}
|
|
||||||
<i class="form-icon"></i>
|
|
||||||
<span>Share</span>
|
|
||||||
</label>
|
|
||||||
<div class="form-input-hint">
|
|
||||||
Share this bookmark with other users.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<br/>
|
<div class="form-input-hint bookmark-exists">
|
||||||
<div class="form-group">
|
This URL is already bookmarked. You can <a href="#">edit</a> it or you can overwrite the existing bookmark
|
||||||
{% if auto_close %}
|
by saving this form.
|
||||||
<input type="submit" value="Save and close" class="btn btn-primary mr-2">
|
|
||||||
{% else %}
|
|
||||||
<input type="submit" value="Save" class="btn btn-primary mr-2">
|
|
||||||
{% endif %}
|
|
||||||
<a href="{{ cancel_url }}" class="btn">Nevermind</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="{{ form.tag_string.id_for_label }}" class="form-label">Tags</label>
|
||||||
|
{{ form.tag_string|add_class:"form-input"|attr:"autocomplete:off" }}
|
||||||
|
<div class="form-input-hint">
|
||||||
|
Enter any number of tags separated by space and <strong>without</strong> the hash (#). If a tag does not
|
||||||
|
exist it will be
|
||||||
|
automatically created.
|
||||||
|
</div>
|
||||||
|
{{ form.tag_string.errors }}
|
||||||
|
</div>
|
||||||
|
<div class="form-group has-icon-right">
|
||||||
|
<label for="{{ form.title.id_for_label }}" class="form-label">Title</label>
|
||||||
|
<div class="has-icon-right">
|
||||||
|
{{ form.title|add_class:"form-input"|attr:"autocomplete:off" }}
|
||||||
|
<i class="form-icon loading"></i>
|
||||||
|
<a class="btn btn-link form-icon" title="Edit title from website">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"/>
|
||||||
|
<path fill-rule="evenodd"
|
||||||
|
d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"
|
||||||
|
clip-rule="evenodd"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="form-input-hint">
|
||||||
|
Optional, leave empty to use title from website.
|
||||||
|
</div>
|
||||||
|
{{ form.title.errors }}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="{{ form.description.id_for_label }}" class="form-label">Description</label>
|
||||||
|
<div class="has-icon-right">
|
||||||
|
{{ form.description|add_class:"form-input"|attr:"rows:2" }}
|
||||||
|
<i class="form-icon loading"></i>
|
||||||
|
<a class="btn btn-link form-icon" title="Edit description from website">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"/>
|
||||||
|
<path fill-rule="evenodd"
|
||||||
|
d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"
|
||||||
|
clip-rule="evenodd"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="form-input-hint">
|
||||||
|
Optional, leave empty to use description from website.
|
||||||
|
</div>
|
||||||
|
{{ form.description.errors }}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="{{ form.unread.id_for_label }}" class="form-checkbox">
|
||||||
|
{{ form.unread }}
|
||||||
|
<i class="form-icon"></i>
|
||||||
|
<span>Mark as unread</span>
|
||||||
|
</label>
|
||||||
|
<div class="form-input-hint">
|
||||||
|
Unread bookmarks can be filtered for, and marked as read after you had a chance to look at them.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if request.user.profile.enable_sharing %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="{{ form.shared.id_for_label }}" class="form-checkbox">
|
||||||
|
{{ form.shared }}
|
||||||
|
<i class="form-icon"></i>
|
||||||
|
<span>Share</span>
|
||||||
|
</label>
|
||||||
|
<div class="form-input-hint">
|
||||||
|
Share this bookmark with other users.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<br/>
|
||||||
|
<div class="form-group">
|
||||||
|
{% if auto_close %}
|
||||||
|
<input type="submit" value="Save and close" class="btn btn-primary mr-2">
|
||||||
|
{% else %}
|
||||||
|
<input type="submit" value="Save" class="btn btn-primary mr-2">
|
||||||
|
{% endif %}
|
||||||
|
<a href="{{ cancel_url }}" class="btn">Nevermind</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
{# Replace tag input with auto-complete component #}
|
{# Replace tag input with auto-complete component #}
|
||||||
<script src="{% static "bundle.js" %}"></script>
|
<script src="{% static "bundle.js" %}"></script>
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
const wrapper = document.createElement('div');
|
const wrapper = document.createElement('div');
|
||||||
const tagInput = document.getElementById('{{ form.tag_string.id_for_label }}');
|
const tagInput = document.getElementById('{{ form.tag_string.id_for_label }}');
|
||||||
const apiClient = new linkding.ApiClient('{% url 'bookmarks:api-root' %}')
|
const apiClient = new linkding.ApiClient('{% url 'bookmarks:api-root' %}')
|
||||||
|
|
||||||
new linkding.TagAutoComplete({
|
new linkding.TagAutoComplete({
|
||||||
target: wrapper,
|
target: wrapper,
|
||||||
props: {
|
props: {
|
||||||
id: '{{ form.tag_string.id_for_label }}',
|
id: '{{ form.tag_string.id_for_label }}',
|
||||||
name: '{{ form.tag_string.name }}',
|
name: '{{ form.tag_string.name }}',
|
||||||
value: tagInput.value,
|
value: tagInput.value,
|
||||||
apiClient: apiClient
|
apiClient: apiClient
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tagInput.parentElement.replaceChild(wrapper, tagInput);
|
||||||
|
</script>
|
||||||
|
<script type="application/javascript">
|
||||||
|
/**
|
||||||
|
* - Pre-fill title and description placeholders with metadata from website as soon as URL changes
|
||||||
|
* - Show hint if URL is already bookmarked
|
||||||
|
* - Setup buttons that allow editing of scraped website values
|
||||||
|
*/
|
||||||
|
(function init() {
|
||||||
|
const urlInput = document.getElementById('{{ form.url.id_for_label }}');
|
||||||
|
const titleInput = document.getElementById('{{ form.title.id_for_label }}');
|
||||||
|
const descriptionInput = document.getElementById('{{ form.description.id_for_label }}');
|
||||||
|
const websiteTitleInput = document.getElementById('{{ form.website_title.id_for_label }}');
|
||||||
|
const websiteDescriptionInput = document.getElementById('{{ form.website_description.id_for_label }}');
|
||||||
|
const editedBookmarkId = {{ bookmark_id }};
|
||||||
|
|
||||||
|
function toggleLoadingIcon(input, show) {
|
||||||
|
const icon = input.parentNode.querySelector('i.form-icon');
|
||||||
|
icon.style['visibility'] = show ? 'visible' : 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePlaceholder(input, value) {
|
||||||
|
if (value) {
|
||||||
|
input.setAttribute('placeholder', value);
|
||||||
|
} else {
|
||||||
|
input.removeAttribute('placeholder');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkUrl() {
|
||||||
|
toggleLoadingIcon(titleInput, true);
|
||||||
|
toggleLoadingIcon(descriptionInput, true);
|
||||||
|
updatePlaceholder(titleInput, null);
|
||||||
|
updatePlaceholder(descriptionInput, null);
|
||||||
|
|
||||||
|
const websiteUrl = encodeURIComponent(urlInput.value);
|
||||||
|
const requestUrl = `{% url 'bookmarks:api-root' %}bookmarks/check?url=${websiteUrl}`;
|
||||||
|
fetch(requestUrl)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
const metadata = data.metadata;
|
||||||
|
updatePlaceholder(titleInput, metadata.title);
|
||||||
|
updatePlaceholder(descriptionInput, metadata.description);
|
||||||
|
toggleLoadingIcon(titleInput, false);
|
||||||
|
toggleLoadingIcon(descriptionInput, false);
|
||||||
|
|
||||||
|
// Display hint if URL is already bookmarked
|
||||||
|
const bookmarkExistsHint = document.querySelector('.form-input-hint.bookmark-exists');
|
||||||
|
const editExistingBookmarkLink = bookmarkExistsHint.querySelector('a');
|
||||||
|
|
||||||
|
if (data.bookmark && data.bookmark.id !== editedBookmarkId) {
|
||||||
|
bookmarkExistsHint.style['display'] = 'block';
|
||||||
|
editExistingBookmarkLink.href = data.bookmark.edit_url;
|
||||||
|
} else {
|
||||||
|
bookmarkExistsHint.style['display'] = 'none';
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupEditAutoValueButton(input) {
|
||||||
|
const editAutoValueButton = input.parentNode.querySelector('.btn.form-icon');
|
||||||
|
if (!editAutoValueButton) return;
|
||||||
|
editAutoValueButton.addEventListener('click', function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
input.value = input.getAttribute('placeholder');
|
||||||
|
input.focus();
|
||||||
|
input.select();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
tagInput.parentElement.replaceChild(wrapper, tagInput);
|
// Fetch initial website data if we have a URL, and we are not editing an existing bookmark
|
||||||
</script>
|
// For existing bookmarks we get the website metadata through hidden inputs
|
||||||
<script type="application/javascript">
|
if (urlInput.value && !editedBookmarkId) {
|
||||||
/**
|
checkUrl();
|
||||||
* - Pre-fill title and description placeholders with metadata from website as soon as URL changes
|
}
|
||||||
* - Show hint if URL is already bookmarked
|
urlInput.addEventListener('input', checkUrl);
|
||||||
* - Setup buttons that allow editing of scraped website values
|
|
||||||
*/
|
|
||||||
(function init() {
|
|
||||||
const urlInput = document.getElementById('{{ form.url.id_for_label }}');
|
|
||||||
const titleInput = document.getElementById('{{ form.title.id_for_label }}');
|
|
||||||
const descriptionInput = document.getElementById('{{ form.description.id_for_label }}');
|
|
||||||
const websiteTitleInput = document.getElementById('{{ form.website_title.id_for_label }}');
|
|
||||||
const websiteDescriptionInput = document.getElementById('{{ form.website_description.id_for_label }}');
|
|
||||||
const editedBookmarkId = {{ bookmark_id }};
|
|
||||||
|
|
||||||
function toggleLoadingIcon(input, show) {
|
// Set initial website title and description for edited bookmarks
|
||||||
const icon = input.parentNode.querySelector('i.form-icon');
|
if (editedBookmarkId) {
|
||||||
icon.style['visibility'] = show ? 'visible' : 'hidden';
|
updatePlaceholder(titleInput, websiteTitleInput.value);
|
||||||
}
|
updatePlaceholder(descriptionInput, websiteDescriptionInput.value);
|
||||||
|
}
|
||||||
|
|
||||||
function updatePlaceholder(input, value) {
|
setupEditAutoValueButton(titleInput);
|
||||||
if (value) {
|
setupEditAutoValueButton(descriptionInput);
|
||||||
input.setAttribute('placeholder', value);
|
})();
|
||||||
} else {
|
</script>
|
||||||
input.removeAttribute('placeholder');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkUrl() {
|
|
||||||
toggleLoadingIcon(titleInput, true);
|
|
||||||
toggleLoadingIcon(descriptionInput, true);
|
|
||||||
updatePlaceholder(titleInput, null);
|
|
||||||
updatePlaceholder(descriptionInput, null);
|
|
||||||
|
|
||||||
const websiteUrl = encodeURIComponent(urlInput.value);
|
|
||||||
const requestUrl = `{% url 'bookmarks:api-root' %}bookmarks/check?url=${websiteUrl}`;
|
|
||||||
fetch(requestUrl)
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
const metadata = data.metadata;
|
|
||||||
updatePlaceholder(titleInput, metadata.title);
|
|
||||||
updatePlaceholder(descriptionInput, metadata.description);
|
|
||||||
toggleLoadingIcon(titleInput, false);
|
|
||||||
toggleLoadingIcon(descriptionInput, false);
|
|
||||||
|
|
||||||
// Display hint if URL is already bookmarked
|
|
||||||
const bookmarkExistsHint = document.querySelector('.form-input-hint.bookmark-exists');
|
|
||||||
const editExistingBookmarkLink = bookmarkExistsHint.querySelector('a');
|
|
||||||
|
|
||||||
if (data.bookmark && data.bookmark.id !== editedBookmarkId) {
|
|
||||||
bookmarkExistsHint.style['display'] = 'block';
|
|
||||||
editExistingBookmarkLink.href = data.bookmark.edit_url;
|
|
||||||
} else {
|
|
||||||
bookmarkExistsHint.style['display'] = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupEditAutoValueButton(input) {
|
|
||||||
const editAutoValueButton = input.parentNode.querySelector('.btn.form-icon');
|
|
||||||
if (!editAutoValueButton) return;
|
|
||||||
editAutoValueButton.addEventListener('click', function (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
input.value = input.getAttribute('placeholder');
|
|
||||||
input.focus();
|
|
||||||
input.select();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch initial website data if we have a URL, and we are not editing an existing bookmark
|
|
||||||
// For existing bookmarks we get the website metadata through hidden inputs
|
|
||||||
if (urlInput.value && !editedBookmarkId) {
|
|
||||||
checkUrl();
|
|
||||||
}
|
|
||||||
urlInput.addEventListener('input', checkUrl);
|
|
||||||
|
|
||||||
// Set initial website title and description for edited bookmarks
|
|
||||||
if (editedBookmarkId) {
|
|
||||||
updatePlaceholder(titleInput, websiteTitleInput.value);
|
|
||||||
updatePlaceholder(descriptionInput, websiteDescriptionInput.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
setupEditAutoValueButton(titleInput);
|
|
||||||
setupEditAutoValueButton(descriptionInput);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</div>
|
</div>
|
||||||
|
@@ -5,42 +5,42 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{% include 'bookmarks/bulk_edit/state.html' %}
|
{% include 'bookmarks/bulk_edit/state.html' %}
|
||||||
|
|
||||||
<div class="bookmarks-page columns">
|
<div class="bookmarks-page columns">
|
||||||
|
|
||||||
{# Bookmark list #}
|
{# Bookmark list #}
|
||||||
<section class="content-area column col-8 col-md-12">
|
<section class="content-area column col-8 col-md-12">
|
||||||
<div class="content-area-header">
|
<div class="content-area-header">
|
||||||
<h2>Bookmarks</h2>
|
<h2>Bookmarks</h2>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
{% bookmark_search filters tags %}
|
{% bookmark_search filters tags %}
|
||||||
{% include 'bookmarks/bulk_edit/toggle.html' %}
|
{% include 'bookmarks/bulk_edit/toggle.html' %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="bookmark-actions" action="{% url 'bookmarks:action' %}?return_url={{ return_url }}"
|
<form class="bookmark-actions" action="{% url 'bookmarks:action' %}?return_url={{ return_url }}"
|
||||||
method="post">
|
method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% include 'bookmarks/bulk_edit/bar.html' with mode='default' %}
|
{% include 'bookmarks/bulk_edit/bar.html' with mode='default' %}
|
||||||
|
|
||||||
{% if empty %}
|
{% if empty %}
|
||||||
{% include 'bookmarks/empty_bookmarks.html' %}
|
{% include 'bookmarks/empty_bookmarks.html' %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% bookmark_list bookmarks return_url link_target %}
|
{% bookmark_list bookmarks return_url link_target %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{# Tag list #}
|
{# Tag list #}
|
||||||
<section class="content-area column col-4 hide-md">
|
<section class="content-area column col-4 hide-md">
|
||||||
<div class="content-area-header">
|
<div class="content-area-header">
|
||||||
<h2>Tags</h2>
|
<h2>Tags</h2>
|
||||||
</div>
|
</div>
|
||||||
{% tag_cloud tags selected_tags %}
|
{% tag_cloud tags selected_tags %}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="{% static "bundle.js" %}"></script>
|
<script src="{% static "bundle.js" %}"></script>
|
||||||
<script src="{% static "shared.js" %}"></script>
|
<script src="{% static "shared.js" %}"></script>
|
||||||
<script src="{% static "bookmark_list.js" %}"></script>
|
<script src="{% static "bookmark_list.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -5,61 +5,61 @@
|
|||||||
{# Use data attributes as storage for access in static scripts #}
|
{# Use data attributes as storage for access in static scripts #}
|
||||||
<html lang="en" data-api-base-url="{% url 'bookmarks:api-root' %}">
|
<html lang="en" data-api-base-url="{% url 'bookmarks:api-root' %}">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="icon" href="{% static 'favicon.png' %}"/>
|
<link rel="icon" href="{% static 'favicon.png' %}"/>
|
||||||
<link rel="apple-touch-icon" href="{% static 'apple-touch-icon.png' %}">
|
<link rel="apple-touch-icon" href="{% static 'apple-touch-icon.png' %}">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimal-ui">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimal-ui">
|
||||||
<meta name="description" content="Self-hosted bookmark service">
|
<meta name="description" content="Self-hosted bookmark service">
|
||||||
<meta name="robots" content="index,follow">
|
<meta name="robots" content="index,follow">
|
||||||
<meta name="author" content="Sascha Ißbrücker">
|
<meta name="author" content="Sascha Ißbrücker">
|
||||||
<title>linkding</title>
|
<title>linkding</title>
|
||||||
{# Include SASS styles, files are resolved from bookmarks/styles #}
|
{# Include SASS styles, files are resolved from bookmarks/styles #}
|
||||||
{# Include specific theme variant based on user profile setting #}
|
{# Include specific theme variant based on user profile setting #}
|
||||||
{% if request.user.profile.theme == 'light' %}
|
{% if request.user.profile.theme == 'light' %}
|
||||||
<link href="{% sass_src 'theme-light.scss' %}" rel="stylesheet" type="text/css"/>
|
<link href="{% sass_src 'theme-light.scss' %}" rel="stylesheet" type="text/css"/>
|
||||||
{% elif request.user.profile.theme == 'dark' %}
|
{% elif request.user.profile.theme == 'dark' %}
|
||||||
<link href="{% sass_src 'theme-dark.scss' %}" rel="stylesheet" type="text/css"/>
|
<link href="{% sass_src 'theme-dark.scss' %}" rel="stylesheet" type="text/css"/>
|
||||||
{% else %}
|
{% else %}
|
||||||
{# Use auto theme as fallback #}
|
{# Use auto theme as fallback #}
|
||||||
<link href="{% sass_src 'theme-dark.scss' %}" rel="stylesheet" type="text/css"
|
<link href="{% sass_src 'theme-dark.scss' %}" rel="stylesheet" type="text/css"
|
||||||
media="(prefers-color-scheme: dark)"/>
|
media="(prefers-color-scheme: dark)"/>
|
||||||
<link href="{% sass_src 'theme-light.scss' %}" rel="stylesheet" type="text/css"
|
<link href="{% sass_src 'theme-light.scss' %}" rel="stylesheet" type="text/css"
|
||||||
media="(prefers-color-scheme: light)"/>
|
media="(prefers-color-scheme: light)"/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
{% if has_toasts %}
|
{% if has_toasts %}
|
||||||
<div class="toasts container grid-lg">
|
<div class="toasts container grid-lg">
|
||||||
<form action="{% url 'bookmarks:toasts.acknowledge' %}?return_url={{ request.path | urlencode }}" method="post">
|
<form action="{% url 'bookmarks:toasts.acknowledge' %}?return_url={{ request.path | urlencode }}" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% for toast in toast_messages %}
|
{% for toast in toast_messages %}
|
||||||
<div class="toast">
|
<div class="toast">
|
||||||
{{ toast.message }}
|
{{ toast.message }}
|
||||||
<button type="submit" name="toast" value="{{ toast.id }}" class="btn btn-clear float-right"></button>
|
<button type="submit" name="toast" value="{{ toast.id }}" class="btn btn-clear float-right"></button>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="navbar container grid-lg">
|
||||||
|
<section class="navbar-section">
|
||||||
|
<a href="{% url 'bookmarks:index' %}" class="navbar-brand text-bold">
|
||||||
|
<img class="logo" src="{% static 'logo.png' %}" alt="Application logo">
|
||||||
|
<h1>linkding</h1>
|
||||||
|
</a>
|
||||||
|
</section>
|
||||||
|
{# Only show nav items menu when logged in #}
|
||||||
|
{% if request.user.is_authenticated %}
|
||||||
|
<section class="navbar-section">
|
||||||
|
{% include 'bookmarks/nav_menu.html' %}
|
||||||
|
</section>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="navbar container grid-lg">
|
</div>
|
||||||
<section class="navbar-section">
|
|
||||||
<a href="{% url 'bookmarks:index' %}" class="navbar-brand text-bold">
|
|
||||||
<img class="logo" src="{% static 'logo.png' %}" alt="Application logo">
|
|
||||||
<h1>linkding</h1>
|
|
||||||
</a>
|
|
||||||
</section>
|
|
||||||
{# Only show nav items menu when logged in #}
|
|
||||||
{% if request.user.is_authenticated %}
|
|
||||||
<section class="navbar-section">
|
|
||||||
{% include 'bookmarks/nav_menu.html' %}
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</header>
|
</header>
|
||||||
<div class="content container grid-lg">
|
<div class="content container grid-lg">
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@@ -1,93 +1,101 @@
|
|||||||
|
{% load shared %}
|
||||||
|
{% htmlmin %}
|
||||||
{# Basic menu list #}
|
{# Basic menu list #}
|
||||||
<div class="hide-md">
|
<div class="hide-md">
|
||||||
<a href="{% url 'bookmarks:new' %}" class="btn btn-primary mr-2">Add bookmark</a>
|
<a href="{% url 'bookmarks:new' %}" class="btn btn-primary mr-2">Add bookmark</a>
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<a href="#" class="btn btn-link dropdown-toggle" tabindex="0" style="padding-right: 0.2rem">
|
<a href="#" class="btn btn-link dropdown-toggle" tabindex="0" style="padding-right: 0.2rem">
|
||||||
Bookmarks
|
Bookmarks
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" style="height:1rem;width:1rem;vertical-align: text-bottom;">
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"
|
||||||
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
|
style="height:1rem;width:1rem;vertical-align: text-bottom;">
|
||||||
</svg>
|
<path fill-rule="evenodd"
|
||||||
</a>
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
<ul class="menu">
|
clip-rule="evenodd"/>
|
||||||
<li>
|
</svg>
|
||||||
<a href="{% url 'bookmarks:index' %}" class="btn btn-link">Active</a>
|
</a>
|
||||||
</li>
|
<ul class="menu">
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'bookmarks:archived' %}" class="btn btn-link">Archived</a>
|
<a href="{% url 'bookmarks:index' %}" class="btn btn-link">Active</a>
|
||||||
</li>
|
</li>
|
||||||
{% if request.user.profile.enable_sharing %}
|
<li>
|
||||||
<li>
|
<a href="{% url 'bookmarks:archived' %}" class="btn btn-link">Archived</a>
|
||||||
<a href="{% url 'bookmarks:shared' %}" class="btn btn-link">Shared</a>
|
</li>
|
||||||
</li>
|
{% if request.user.profile.enable_sharing %}
|
||||||
{% endif %}
|
<li>
|
||||||
<li>
|
<a href="{% url 'bookmarks:shared' %}" class="btn btn-link">Shared</a>
|
||||||
<a href="{% url 'bookmarks:index' %}?q=!unread" class="btn btn-link">Unread</a>
|
</li>
|
||||||
</li>
|
{% endif %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'bookmarks:index' %}?q=!untagged" class="btn btn-link">Untagged</a>
|
<a href="{% url 'bookmarks:index' %}?q=!unread" class="btn btn-link">Unread</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
<li>
|
||||||
</div>
|
<a href="{% url 'bookmarks:index' %}?q=!untagged" class="btn btn-link">Untagged</a>
|
||||||
<a href="{% url 'bookmarks:settings.index' %}" class="btn btn-link">Settings</a>
|
</li>
|
||||||
<a href="{% url 'logout' %}" class="btn btn-link">Logout</a>
|
</ul>
|
||||||
|
</div>
|
||||||
|
<a href="{% url 'bookmarks:settings.index' %}" class="btn btn-link">Settings</a>
|
||||||
|
<a href="{% url 'logout' %}" class="btn btn-link">Logout</a>
|
||||||
</div>
|
</div>
|
||||||
{# Menu drop-down for smaller devices #}
|
{# Menu drop-down for smaller devices #}
|
||||||
<div class="show-md">
|
<div class="show-md">
|
||||||
<a href="{% url 'bookmarks:new' %}" class="btn btn-primary">
|
<a href="{% url 'bookmarks:new' %}" class="btn btn-primary">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" style="width: 24px; height: 24px">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
style="width: 24px; height: 24px">
|
||||||
</svg>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown dropdown-right">
|
||||||
|
<a href="#" id="mobile-nav-menu-trigger" class="btn btn-link dropdown-toggle" tabindex="0">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
|
||||||
|
style="width: 24px; height: 24px">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
|
||||||
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown dropdown-right">
|
<!-- menu component -->
|
||||||
<a href="#" id="mobile-nav-menu-trigger" class="btn btn-link dropdown-toggle" tabindex="0">
|
<ul class="menu">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" style="width: 24px; height: 24px">
|
<li>
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
<a href="{% url 'bookmarks:index' %}" class="btn btn-link">Bookmarks</a>
|
||||||
</svg>
|
</li>
|
||||||
</a>
|
<li style="padding-left: 1rem">
|
||||||
<!-- menu component -->
|
<a href="{% url 'bookmarks:archived' %}" class="btn btn-link">Archived</a>
|
||||||
<ul class="menu">
|
</li>
|
||||||
<li>
|
{% if request.user.profile.enable_sharing %}
|
||||||
<a href="{% url 'bookmarks:index' %}" class="btn btn-link">Bookmarks</a>
|
<li style="padding-left: 1rem">
|
||||||
</li>
|
<a href="{% url 'bookmarks:shared' %}" class="btn btn-link">Shared</a>
|
||||||
<li style="padding-left: 1rem">
|
</li>
|
||||||
<a href="{% url 'bookmarks:archived' %}" class="btn btn-link">Archived</a>
|
{% endif %}
|
||||||
</li>
|
<li style="padding-left: 1rem">
|
||||||
{% if request.user.profile.enable_sharing %}
|
<a href="{% url 'bookmarks:index' %}?q=!unread" class="btn btn-link">Unread</a>
|
||||||
<li style="padding-left: 1rem">
|
</li>
|
||||||
<a href="{% url 'bookmarks:shared' %}" class="btn btn-link">Shared</a>
|
<li style="padding-left: 1rem">
|
||||||
</li>
|
<a href="{% url 'bookmarks:index' %}?q=!untagged" class="btn btn-link">Untagged</a>
|
||||||
{% endif %}
|
</li>
|
||||||
<li style="padding-left: 1rem">
|
<li>
|
||||||
<a href="{% url 'bookmarks:index' %}?q=!unread" class="btn btn-link">Unread</a>
|
<a href="{% url 'bookmarks:settings.index' %}" class="btn btn-link">Settings</a>
|
||||||
</li>
|
</li>
|
||||||
<li style="padding-left: 1rem">
|
<li>
|
||||||
<a href="{% url 'bookmarks:index' %}?q=!untagged" class="btn btn-link">Untagged</a>
|
<a href="{% url 'logout' %}" class="btn btn-link">Logout</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
</ul>
|
||||||
<a href="{% url 'bookmarks:settings.index' %}" class="btn btn-link">Settings</a>
|
</div>
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="{% url 'logout' %}" class="btn btn-link">Logout</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
{% endhtmlmin %}
|
||||||
<script>
|
<script>
|
||||||
// Hide mobile menu on outside click
|
// Hide mobile menu on outside click
|
||||||
// The Spectre CSS component relies on focus changes to show/hide the dropdown, however mobile browsers like
|
// The Spectre CSS component relies on focus changes to show/hide the dropdown, however mobile browsers like
|
||||||
// Safari will not trigger a blur event when clicking on a non-focusable element, so we have to simulate the
|
// Safari will not trigger a blur event when clicking on a non-focusable element, so we have to simulate the
|
||||||
// behaviour through Javascript
|
// behaviour through Javascript
|
||||||
const mobileNavMenuTrigger = document.getElementById('mobile-nav-menu-trigger');
|
const mobileNavMenuTrigger = document.getElementById('mobile-nav-menu-trigger');
|
||||||
|
|
||||||
function mobileNavMenuOutsideClickHandler(clickEvent) {
|
function mobileNavMenuOutsideClickHandler(clickEvent) {
|
||||||
if (mobileNavMenuTrigger.parentElement.contains(clickEvent.target)) return
|
if (mobileNavMenuTrigger.parentElement.contains(clickEvent.target)) return
|
||||||
mobileNavMenuTrigger.blur();
|
mobileNavMenuTrigger.blur();
|
||||||
}
|
}
|
||||||
|
|
||||||
mobileNavMenuTrigger.addEventListener('focus', function () {
|
mobileNavMenuTrigger.addEventListener('focus', function () {
|
||||||
document.addEventListener('click', mobileNavMenuOutsideClickHandler);
|
document.addEventListener('click', mobileNavMenuOutsideClickHandler);
|
||||||
})
|
})
|
||||||
mobileNavMenuTrigger.addEventListener('blur', function () {
|
mobileNavMenuTrigger.addEventListener('blur', function () {
|
||||||
document.removeEventListener('click', mobileNavMenuOutsideClickHandler);
|
document.removeEventListener('click', mobileNavMenuOutsideClickHandler);
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@@ -2,14 +2,14 @@
|
|||||||
{% load bookmarks %}
|
{% load bookmarks %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<section class="content-area column col-12">
|
<section class="content-area column col-12">
|
||||||
<div class="content-area-header">
|
<div class="content-area-header">
|
||||||
<h2>New bookmark</h2>
|
<h2>New bookmark</h2>
|
||||||
</div>
|
</div>
|
||||||
<form action="{% url 'bookmarks:new' %}" method="post" class="col-6 col-md-12" novalidate>
|
<form action="{% url 'bookmarks:new' %}" method="post" class="col-6 col-md-12" novalidate>
|
||||||
{% bookmark_form form return_url auto_close=auto_close %}
|
{% bookmark_form form return_url auto_close=auto_close %}
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -1,35 +1,35 @@
|
|||||||
{% load shared %}
|
{% load shared %}
|
||||||
|
|
||||||
<ul class="pagination">
|
<ul class="pagination">
|
||||||
{% if page.has_previous %}
|
{% if page.has_previous %}
|
||||||
<li class="page-item">
|
<li class="page-item">
|
||||||
<a href="?{% update_query_string page=page.previous_page_number %}" tabindex="-1">Previous</a>
|
<a href="?{% update_query_string page=page.previous_page_number %}" tabindex="-1">Previous</a>
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="page-item disabled">
|
<li class="page-item disabled">
|
||||||
<a href="#" tabindex="-1">Previous</a>
|
<a href="#" tabindex="-1">Previous</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% for page_number in visible_page_numbers %}
|
{% for page_number in visible_page_numbers %}
|
||||||
{% if page_number >= 0 %}
|
{% if page_number >= 0 %}
|
||||||
<li class="page-item {% if page.number == page_number %}active{% endif %}">
|
<li class="page-item {% if page.number == page_number %}active{% endif %}">
|
||||||
<a href="?{% update_query_string page=page_number %}">{{ page_number }}</a>
|
<a href="?{% update_query_string page=page_number %}">{{ page_number }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
|
||||||
<li class="page-item">
|
|
||||||
<span>...</span>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% if page.has_next %}
|
|
||||||
<li class="page-item">
|
|
||||||
<a href="?{% update_query_string page=page.next_page_number %}" tabindex="-1">Next</a>
|
|
||||||
</li>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="page-item disabled">
|
<li class="page-item">
|
||||||
<a href="#" tabindex="-1">Next</a>
|
<span>...</span>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if page.has_next %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a href="?{% update_query_string page=page.next_page_number %}" tabindex="-1">Next</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled">
|
||||||
|
<a href="#" tabindex="-1">Next</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
@@ -1,43 +1,43 @@
|
|||||||
<div class="search">
|
<div class="search">
|
||||||
<form action="" method="get" role="search">
|
<form action="" method="get" role="search">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span id="search-input-wrap">
|
<span id="search-input-wrap">
|
||||||
<input type="search" class="form-input" name="q" placeholder="Search for words or #tags"
|
<input type="search" class="form-input" name="q" placeholder="Search for words or #tags"
|
||||||
value="{{ filters.query }}">
|
value="{{ filters.query }}">
|
||||||
</span>
|
</span>
|
||||||
<input type="submit" value="Search" class="btn input-group-btn">
|
<input type="submit" value="Search" class="btn input-group-btn">
|
||||||
</div>
|
</div>
|
||||||
{% if filters.user %}
|
{% if filters.user %}
|
||||||
<input type="hidden" name="user" value="{{ filters.user }}">
|
<input type="hidden" name="user" value="{{ filters.user }}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Replace search input with auto-complete component #}
|
{# Replace search input with auto-complete component #}
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
window.addEventListener("load", function() {
|
window.addEventListener("load", function () {
|
||||||
const currentTagsString = '{{ tags_string }}';
|
const currentTagsString = '{{ tags_string }}';
|
||||||
const currentTags = currentTagsString.split(' ');
|
const currentTags = currentTagsString.split(' ');
|
||||||
const uniqueTags = [...new Set(currentTags)]
|
const uniqueTags = [...new Set(currentTags)]
|
||||||
const filters = {
|
const filters = {
|
||||||
q: '{{ filters.query }}',
|
q: '{{ filters.query }}',
|
||||||
user: '{{ filters.user }}',
|
user: '{{ filters.user }}',
|
||||||
}
|
}
|
||||||
const apiClient = new linkding.ApiClient('{% url 'bookmarks:api-root' %}')
|
const apiClient = new linkding.ApiClient('{% url 'bookmarks:api-root' %}')
|
||||||
const wrapper = document.getElementById('search-input-wrap')
|
const wrapper = document.getElementById('search-input-wrap')
|
||||||
const newWrapper = document.createElement('div')
|
const newWrapper = document.createElement('div')
|
||||||
new linkding.SearchAutoComplete({
|
new linkding.SearchAutoComplete({
|
||||||
target: newWrapper,
|
target: newWrapper,
|
||||||
props: {
|
props: {
|
||||||
name: 'q',
|
name: 'q',
|
||||||
placeholder: 'Search for words or #tags',
|
placeholder: 'Search for words or #tags',
|
||||||
value: '{{ filters.query }}',
|
value: '{{ filters.query }}',
|
||||||
tags: uniqueTags,
|
tags: uniqueTags,
|
||||||
mode: '{{ mode }}',
|
mode: '{{ mode }}',
|
||||||
apiClient,
|
apiClient,
|
||||||
filters,
|
filters,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
wrapper.parentElement.replaceChild(newWrapper, wrapper)
|
wrapper.parentElement.replaceChild(newWrapper, wrapper)
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
@@ -5,44 +5,44 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="bookmarks-page columns">
|
<div class="bookmarks-page columns">
|
||||||
|
|
||||||
{# Bookmark list #}
|
{# Bookmark list #}
|
||||||
<section class="content-area column col-8 col-md-12">
|
<section class="content-area column col-8 col-md-12">
|
||||||
<div class="content-area-header">
|
<div class="content-area-header">
|
||||||
<h2>Shared bookmarks</h2>
|
<h2>Shared bookmarks</h2>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
{% bookmark_search filters tags mode='shared' %}
|
{% bookmark_search filters tags mode='shared' %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="bookmark-actions" action="{% url 'bookmarks:action' %}?return_url={{ return_url }}"
|
<form class="bookmark-actions" action="{% url 'bookmarks:action' %}?return_url={{ return_url }}"
|
||||||
method="post">
|
method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
{% if empty %}
|
{% if empty %}
|
||||||
{% include 'bookmarks/empty_bookmarks.html' %}
|
{% include 'bookmarks/empty_bookmarks.html' %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% bookmark_list bookmarks return_url link_target %}
|
{% bookmark_list bookmarks return_url link_target %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{# Filters #}
|
{# Filters #}
|
||||||
<section class="content-area column col-4 hide-md">
|
<section class="content-area column col-4 hide-md">
|
||||||
<div class="content-area-header">
|
<div class="content-area-header">
|
||||||
<h2>User</h2>
|
<h2>User</h2>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{% user_select filters users %}
|
{% user_select filters users %}
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
<div class="content-area-header">
|
<div class="content-area-header">
|
||||||
<h2>Tags</h2>
|
<h2>Tags</h2>
|
||||||
</div>
|
</div>
|
||||||
{% tag_cloud tags selected_tags %}
|
{% tag_cloud tags selected_tags %}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="{% static "bundle.js" %}"></script>
|
<script src="{% static "bundle.js" %}"></script>
|
||||||
<script src="{% static "shared.js" %}"></script>
|
<script src="{% static "shared.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -1,35 +1,37 @@
|
|||||||
{% load shared %}
|
{% load shared %}
|
||||||
|
{% htmlmin %}
|
||||||
<div class="tag-cloud">
|
<div class="tag-cloud">
|
||||||
{% if has_selected_tags %}
|
{% if has_selected_tags %}
|
||||||
<p class="selected-tags">
|
<p class="selected-tags">
|
||||||
{% for tag in selected_tags %}
|
{% for tag in selected_tags %}
|
||||||
<a href="?{% remove_from_query_param q=tag.name|hash_tag %}"
|
<a href="?{% remove_from_query_param q=tag.name|hash_tag %}"
|
||||||
class="text-bold mr-2">
|
class="text-bold mr-2">
|
||||||
<span>-{{ tag.name }}</span>
|
<span>-{{ tag.name }}</span>
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="unselected-tags">
|
<div class="unselected-tags">
|
||||||
{% for group in groups %}
|
{% for group in groups %}
|
||||||
<p class="group">
|
<p class="group">
|
||||||
{% for tag in group.tags %}
|
{% for tag in group.tags %}
|
||||||
{# Highlight first char of first tag in group #}
|
{# Highlight first char of first tag in group #}
|
||||||
{% if forloop.counter == 1 %}
|
{% if forloop.counter == 1 %}
|
||||||
<a href="?{% append_to_query_param q=tag.name|hash_tag %}"
|
<a href="?{% append_to_query_param q=tag.name|hash_tag %}"
|
||||||
class="mr-2" data-is-tag-item>
|
class="mr-2" data-is-tag-item>
|
||||||
<span class="highlight-char">{{ tag.name|first_char }}</span><span>{{ tag.name|remaining_chars:1 }}</span>
|
<span
|
||||||
</a>
|
class="highlight-char">{{ tag.name|first_char }}</span><span>{{ tag.name|remaining_chars:1 }}</span>
|
||||||
{% else %}
|
</a>
|
||||||
{# Render remaining tags normally #}
|
{% else %}
|
||||||
<a href="?{% append_to_query_param q=tag.name|hash_tag %}"
|
{# Render remaining tags normally #}
|
||||||
class="mr-2" data-is-tag-item>
|
<a href="?{% append_to_query_param q=tag.name|hash_tag %}"
|
||||||
<span>{{ tag.name }}</span>
|
class="mr-2" data-is-tag-item>
|
||||||
</a>
|
<span>{{ tag.name }}</span>
|
||||||
{% endif %}
|
</a>
|
||||||
{% endfor %}
|
{% endif %}
|
||||||
</p>
|
{% endfor %}
|
||||||
{% endfor %}
|
</p>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endhtmlmin %}
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
from django import template
|
from django import template
|
||||||
|
|
||||||
from bookmarks import utils
|
from bookmarks import utils
|
||||||
@@ -48,6 +50,7 @@ def remove_from_query_param(context, **kwargs):
|
|||||||
|
|
||||||
return query.urlencode()
|
return query.urlencode()
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag(takes_context=True)
|
@register.simple_tag(takes_context=True)
|
||||||
def replace_query_param(context, **kwargs):
|
def replace_query_param(context, **kwargs):
|
||||||
query = context.request.GET.copy()
|
query = context.request.GET.copy()
|
||||||
@@ -87,3 +90,22 @@ def humanize_relative_date(value):
|
|||||||
if value in (None, ''):
|
if value in (None, ''):
|
||||||
return ''
|
return ''
|
||||||
return utils.humanize_relative_date(value)
|
return utils.humanize_relative_date(value)
|
||||||
|
|
||||||
|
|
||||||
|
@register.tag
|
||||||
|
def htmlmin(parser, token):
|
||||||
|
nodelist = parser.parse(('endhtmlmin',))
|
||||||
|
parser.delete_first_token()
|
||||||
|
return HtmlMinNode(nodelist)
|
||||||
|
|
||||||
|
|
||||||
|
class HtmlMinNode(template.Node):
|
||||||
|
def __init__(self, nodelist):
|
||||||
|
self.nodelist = nodelist
|
||||||
|
|
||||||
|
def render(self, context):
|
||||||
|
output = self.nodelist.render(context)
|
||||||
|
|
||||||
|
output = re.sub(r'\s+', ' ', output)
|
||||||
|
|
||||||
|
return output
|
||||||
|
Reference in New Issue
Block a user