Accessibility improvements in page structure (#1014)

* Change app link to not use heading

* Use main and h1 for main content

* Update settings page structure

* Fix responsive styles

* Update bookmark form page structure

* Update auth page structure

* Add some basic page titles

* Expose side panel section

* Add page title for bookmark details

* Expose more sections

* Improve region names
This commit is contained in:
Sascha Ißbrücker
2025-03-16 10:25:01 +01:00
committed by GitHub
parent b9bee24047
commit 226eb69f8b
28 changed files with 403 additions and 318 deletions

View File

@@ -34,7 +34,7 @@ class FilterDrawerTriggerBehavior extends Behavior {
</button> </button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<section class="content content-area"></div> <div class="content"></div>
</div> </div>
</div> </div>
`; `;
@@ -70,13 +70,13 @@ class FilterDrawerBehavior extends ModalBehavior {
teleport() { teleport() {
const content = this.element.querySelector(".content"); const content = this.element.querySelector(".content");
const sidePanel = document.querySelector("section.side-panel"); const sidePanel = document.querySelector(".side-panel");
content.append(...sidePanel.children); content.append(...sidePanel.children);
this.mapHeading(content, "h2", "h3"); this.mapHeading(content, "h2", "h3");
} }
teleportBack() { teleportBack() {
const sidePanel = document.querySelector("section.side-panel"); const sidePanel = document.querySelector(".side-panel");
const content = this.element.querySelector(".content"); const content = this.element.querySelector(".content");
sidePanel.append(...content.children); sidePanel.append(...content.children);
this.mapHeading(sidePanel, "h3", "h2"); this.mapHeading(sidePanel, "h3", "h2");

View File

@@ -1,5 +1,5 @@
.bookmarks-form-page { .bookmarks-form-page {
section { main {
max-width: 550px; max-width: 550px;
margin: 0 auto; margin: 0 auto;
} }

View File

@@ -30,11 +30,11 @@
} }
&.collapse-side-panel { &.collapse-side-panel {
section.main { main {
grid-column: span var(--grid-columns); grid-column: span var(--grid-columns);
} }
section.side-panel { .side-panel {
display: none; display: none;
} }
@@ -459,7 +459,7 @@ ul.bookmark-list {
/* Hide section border when bulk edit bar is opened, otherwise borders overlap in dark mode due to using contrast colors */ /* Hide section border when bulk edit bar is opened, otherwise borders overlap in dark mode due to using contrast colors */
&.active section:first-of-type .content-area-header { &.active .main .section-header {
border-bottom-color: transparent; border-bottom-color: transparent;
} }

View File

@@ -1,13 +1,7 @@
/* Shared components */ /* Shared components */
/* Content area component */ /* Section header component */
section.content-area { .section-header {
h2,
h3 {
font-size: var(--font-size-lg);
}
.content-area-header {
border-bottom: solid 1px var(--secondary-border-color); border-bottom: solid 1px var(--secondary-border-color);
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@@ -15,8 +9,10 @@ section.content-area {
padding-bottom: var(--unit-2); padding-bottom: var(--unit-2);
margin-bottom: var(--unit-4); margin-bottom: var(--unit-4);
h1,
h2, h2,
h3 { h3 {
font-size: var(--font-size-lg);
flex: 0 0 auto; flex: 0 0 auto;
line-height: var(--unit-9); line-height: var(--unit-9);
margin: 0; margin: 0;
@@ -27,10 +23,9 @@ section.content-area {
display: flex; display: flex;
} }
} }
}
@media (max-width: 600px) { @media (max-width: 600px) {
section.content-area .content-area-header { .section-header {
flex-direction: column; flex-direction: column;
} }
} }

View File

@@ -11,18 +11,20 @@ body {
header { header {
margin-bottom: var(--unit-9); margin-bottom: var(--unit-9);
.logo { a.app-link:hover {
text-decoration: none;
}
.app-logo {
width: 28px; width: 28px;
height: 28px; height: 28px;
} }
a:hover { .app-name {
text-decoration: none; margin-left: var(--unit-3);
}
h1 {
margin: 0 0 0 var(--unit-3);
font-size: var(--font-size-lg); font-size: var(--font-size-lg);
font-weight: 500;
line-height: 1.2;
} }
} }

View File

@@ -1,8 +1,14 @@
.settings-page { .settings-page {
section.content-area { h1 {
font-size: var(--font-size-xl);
margin-bottom: var(--unit-6);
}
section {
margin-bottom: var(--unit-10); margin-bottom: var(--unit-10);
h2 { h2 {
font-size: var(--font-size-lg);
margin-bottom: var(--unit-3); margin-bottom: var(--unit-3);
} }
} }

View File

@@ -87,6 +87,7 @@
--font-size: 0.7rem; --font-size: 0.7rem;
--font-size-sm: 0.65rem; --font-size-sm: 0.65rem;
--font-size-lg: 0.8rem; --font-size-lg: 0.8rem;
--font-size-xl: 1rem;
--line-height: 1rem; --line-height: 1rem;
/* Sizes */ /* Sizes */

View File

@@ -8,9 +8,9 @@
class="bookmarks-page grid columns-md-1 {% if bookmark_list.collapse_side_panel %}collapse-side-panel{% endif %}"> class="bookmarks-page grid columns-md-1 {% if bookmark_list.collapse_side_panel %}collapse-side-panel{% endif %}">
{# Bookmark list #} {# Bookmark list #}
<section class="main content-area col-2"> <main class="main col-2" aria-labelledby="main-heading">
<div class="content-area-header mb-0"> <div class="section-header mb-0">
<h2>Archived bookmarks</h2> <h1 id="main-heading">Archived bookmarks</h1>
<div class="header-controls"> <div class="header-controls">
{% bookmark_search bookmark_list.search mode='archived' %} {% bookmark_search bookmark_list.search mode='archived' %}
{% include 'bookmarks/bulk_edit/toggle.html' %} {% include 'bookmarks/bulk_edit/toggle.html' %}
@@ -28,18 +28,20 @@
{% include 'bookmarks/bookmark_list.html' %} {% include 'bookmarks/bookmark_list.html' %}
</div> </div>
</form> </form>
</section> </main>
{# Tag cloud #} {# Tag cloud #}
<section class="side-panel content-area col-1"> <div class="side-panel col-1">
<div class="content-area-header"> <section aria-labelledby="tags-heading">
<h2>Tags</h2> <div class="section-header">
<h2 id="tags-heading">Tags</h2>
</div> </div>
<div id="tag-cloud-container"> <div id="tag-cloud-container">
{% include 'bookmarks/tag_cloud.html' %} {% include 'bookmarks/tag_cloud.html' %}
</div> </div>
</section> </section>
</div> </div>
</div>
{% endblock %} {% endblock %}
{% block overlays %} {% block overlays %}

View File

@@ -5,6 +5,7 @@
{% if bookmark_list.is_empty %} {% if bookmark_list.is_empty %}
{% include 'bookmarks/empty_bookmarks.html' %} {% include 'bookmarks/empty_bookmarks.html' %}
{% else %} {% else %}
<section aria-label="Bookmark list">
<ul class="bookmark-list{% if bookmark_list.show_notes %} show-notes{% endif %}" <ul class="bookmark-list{% if bookmark_list.show_notes %} show-notes{% endif %}"
role="list" tabindex="-1" role="list" tabindex="-1"
style="--ld-bookmark-description-max-lines:{{ bookmark_list.description_max_lines }};" style="--ld-bookmark-description-max-lines:{{ bookmark_list.description_max_lines }};"
@@ -161,4 +162,5 @@
<div class="bookmark-pagination{% if request.user_profile.sticky_pagination %} sticky{% endif %}"> <div class="bookmark-pagination{% if request.user_profile.sticky_pagination %} sticky{% endif %}">
{% pagination bookmark_list.bookmarks_page %} {% pagination bookmark_list.bookmarks_page %}
</div> </div>
</section>
{% endif %} {% endif %}

View File

@@ -1,15 +1,21 @@
{% extends 'bookmarks/layout.html' %} {% extends 'bookmarks/layout.html' %}
{% block head %}
{% with page_title="Edit bookmark - Linkding" %}
{{ block.super }}
{% endwith %}
{% endblock %}
{% block content %} {% block content %}
<div class="bookmarks-form-page"> <div class="bookmarks-form-page">
<section class="content-area"> <main aria-labelledby="main-heading">
<div class="content-area-header"> <div class="section-header">
<h2>Edit bookmark</h2> <h1 id="main-heading">Edit bookmark</h1>
</div> </div>
<form action="{% url 'linkding:bookmarks.edit' bookmark_id %}?return_url={{ return_url|urlencode }}" method="post" <form action="{% url 'linkding:bookmarks.edit' bookmark_id %}?return_url={{ return_url|urlencode }}" method="post"
novalidate> novalidate>
{% include 'bookmarks/form.html' %} {% include 'bookmarks/form.html' %}
</form> </form>
</section> </main>
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -12,7 +12,7 @@
<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>{{ page_title|default:'Linkding' }}</title>
{# 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="{% static 'theme-light.css' %}?v={{ app_version }}" rel="stylesheet" type="text/css"/> <link href="{% static 'theme-light.css' %}?v={{ app_version }}" rel="stylesheet" type="text/css"/>

View File

@@ -3,14 +3,16 @@
{% load shared %} {% load shared %}
{% load bookmarks %} {% load bookmarks %}
{% block title %}Bookmarks - Linkding{% endblock %}
{% block content %} {% block content %}
<div ld-bulk-edit <div ld-bulk-edit
class="bookmarks-page grid columns-md-1 {% if bookmark_list.collapse_side_panel %}collapse-side-panel{% endif %}"> class="bookmarks-page grid columns-md-1 {% if bookmark_list.collapse_side_panel %}collapse-side-panel{% endif %}">
{# Bookmark list #} {# Bookmark list #}
<section class="main content-area col-2"> <main class="main col-2" aria-labelledby="main-heading">
<div class="content-area-header mb-0"> <div class="section-header mb-0">
<h2>Bookmarks</h2> <h1 id="main-heading">Bookmarks</h1>
<div class="header-controls"> <div class="header-controls">
{% bookmark_search bookmark_list.search %} {% bookmark_search bookmark_list.search %}
{% include 'bookmarks/bulk_edit/toggle.html' %} {% include 'bookmarks/bulk_edit/toggle.html' %}
@@ -28,18 +30,20 @@
{% include 'bookmarks/bookmark_list.html' %} {% include 'bookmarks/bookmark_list.html' %}
</div> </div>
</form> </form>
</section> </main>
{# Tag cloud #} {# Tag cloud #}
<section class="side-panel content-area col-1"> <div class="side-panel col-1">
<div class="content-area-header"> <section aria-labelledby="tags-heading">
<h2>Tags</h2> <div class="section-header">
<h2 id="tags-heading">Tags</h2>
</div> </div>
<div id="tag-cloud-container"> <div id="tag-cloud-container">
{% include 'bookmarks/tag_cloud.html' %} {% include 'bookmarks/tag_cloud.html' %}
</div> </div>
</section> </section>
</div> </div>
</div>
{% endblock %} {% endblock %}
{% block overlays %} {% block overlays %}

View File

@@ -3,7 +3,7 @@
<!DOCTYPE html> <!DOCTYPE html>
{# 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 'linkding:api-root' %}"> <html lang="en" data-api-base-url="{% url 'linkding:api-root' %}">
{% include 'bookmarks/head.html' %} {% block head %}{% include 'bookmarks/head.html' %}{% endblock %}
<body ld-global-shortcuts> <body ld-global-shortcuts>
<div class="d-none"> <div class="d-none">
@@ -80,10 +80,11 @@
</div> </div>
{% endif %} {% endif %}
<div class="d-flex justify-between"> <div class="d-flex justify-between">
<a href="{% url 'linkding:root' %}" class="d-flex align-center"> <a href="{% url 'linkding:root' %}" class="app-link d-flex align-center">
<img class="logo" src="{% static 'logo.png' %}" alt="Application logo"> <img class="app-logo" src="{% static 'logo.png' %}" alt="Application logo">
<h1>LINKDING</h1> <span class="app-name">LINKDING</span>
</a> </a>
<nav>
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
{# Only show nav items menu when logged in #} {# Only show nav items menu when logged in #}
{% include 'bookmarks/nav_menu.html' %} {% include 'bookmarks/nav_menu.html' %}
@@ -91,6 +92,7 @@
{# Otherwise show login link #} {# Otherwise show login link #}
<a href="{% url 'login' %}" class="btn btn-link">Login</a> <a href="{% url 'login' %}" class="btn btn-link">Login</a>
{% endif %} {% endif %}
</nav>
</div> </div>
</header> </header>
<div class="content container"> <div class="content container">

View File

@@ -27,7 +27,24 @@
</li> </li>
</ul> </ul>
</div> </div>
<a href="{% url 'linkding:settings.index' %}" class="btn btn-link">Settings</a> <div ld-dropdown class="dropdown">
<button class="btn btn-link dropdown-toggle" tabindex="0">
Settings
</button>
<ul class="menu" role="list" tabindex="-1">
<li class="menu-item">
<a href="{% url 'linkding:settings.general' %}" class="menu-link">General</a>
</li>
<li class="menu-item">
<a href="{% url 'linkding:settings.integrations' %}" class="menu-link">Integrations</a>
</li>
{% if request.user.is_superuser %}
<li class="menu-item">
<a href="{% url 'admin:index' %}" class="menu-link" data-turbo="false">Admin</a>
</li>
{% endif %}
</ul>
</div>
<form class="d-inline" action="{% url 'logout' %}" method="post" data-turbo="false"> <form class="d-inline" action="{% url 'logout' %}" method="post" data-turbo="false">
{% csrf_token %} {% csrf_token %}
<button type="submit" class="btn btn-link">Logout</button> <button type="submit" class="btn btn-link">Logout</button>
@@ -54,11 +71,11 @@
<a href="{% url 'linkding:bookmarks.index' %}" class="menu-link">Bookmarks</a> <a href="{% url 'linkding:bookmarks.index' %}" class="menu-link">Bookmarks</a>
</li> </li>
<li class="menu-item"> <li class="menu-item">
<a href="{% url 'linkding:bookmarks.archived' %}" class="menu-link">Archived</a> <a href="{% url 'linkding:bookmarks.archived' %}" class="menu-link">Archived bookmarks</a>
</li> </li>
{% if request.user_profile.enable_sharing %} {% if request.user_profile.enable_sharing %}
<li class="menu-item"> <li class="menu-item">
<a href="{% url 'linkding:bookmarks.shared' %}" class="menu-link">Shared</a> <a href="{% url 'linkding:bookmarks.shared' %}" class="menu-link">Shared bookmarks</a>
</li> </li>
{% endif %} {% endif %}
<li class="menu-item"> <li class="menu-item">
@@ -69,8 +86,17 @@
</li> </li>
<div class="divider"></div> <div class="divider"></div>
<li class="menu-item"> <li class="menu-item">
<a href="{% url 'linkding:settings.index' %}" class="menu-link">Settings</a> <a href="{% url 'linkding:settings.general' %}" class="menu-link">Settings</a>
</li> </li>
<li class="menu-item">
<a href="{% url 'linkding:settings.integrations' %}" class="menu-link">Integrations</a>
</li>
{% if request.user.is_superuser %}
<li class="menu-item">
<a href="{% url 'admin:index' %}" class="menu-link" data-turbo="false">Admin</a>
</li>
{% endif %}
<div class="divider"></div>
<li class="menu-item"> <li class="menu-item">
<form class="d-inline" action="{% url 'logout' %}" method="post" data-turbo="false"> <form class="d-inline" action="{% url 'logout' %}" method="post" data-turbo="false">
{% csrf_token %} {% csrf_token %}

View File

@@ -1,14 +1,20 @@
{% extends 'bookmarks/layout.html' %} {% extends 'bookmarks/layout.html' %}
{% block head %}
{% with page_title="New bookmark - Linkding" %}
{{ block.super }}
{% endwith %}
{% endblock %}
{% block content %} {% block content %}
<div class="bookmarks-form-page"> <div class="bookmarks-form-page">
<section class="content-area"> <main aria-labelledby="main-heading">
<div class="content-area-header"> <div class="section-header">
<h2>New bookmark</h2> <h1 id="main-heading">New bookmark</h1>
</div> </div>
<form action="{% url 'linkding:bookmarks.new' %}" method="post" novalidate> <form action="{% url 'linkding:bookmarks.new' %}" method="post" novalidate>
{% include 'bookmarks/form.html' %} {% include 'bookmarks/form.html' %}
</form> </form>
</section> </main>
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -8,9 +8,9 @@
class="bookmarks-page grid columns-md-1 {% if bookmark_list.collapse_side_panel %}collapse-side-panel{% endif %}"> class="bookmarks-page grid columns-md-1 {% if bookmark_list.collapse_side_panel %}collapse-side-panel{% endif %}">
{# Bookmark list #} {# Bookmark list #}
<section class="main content-area col-2"> <main class="main col-2" aria-labelledby="main-heading">
<div class="content-area-header"> <div class="section-header">
<h2>Shared bookmarks</h2> <h1 id="main-heading">Shared bookmarks</h1>
<div class="header-controls"> <div class="header-controls">
{% bookmark_search bookmark_list.search mode='shared' %} {% bookmark_search bookmark_list.search mode='shared' %}
<button ld-filter-drawer-trigger class="btn ml-2">Filters</button> <button ld-filter-drawer-trigger class="btn ml-2">Filters</button>
@@ -25,25 +25,29 @@
{% include 'bookmarks/bookmark_list.html' %} {% include 'bookmarks/bookmark_list.html' %}
</div> </div>
</form> </form>
</section> </main>
{# Filters #} {# Filters #}
<section class="side-panel content-area col-1"> <div class="side-panel col-1">
<div class="content-area-header"> <section aria-labelledby="user-heading">
<h2>User</h2> <div class="section-header">
<h2 id="user-heading">User</h2>
</div> </div>
<div> <div>
{% user_select bookmark_list.search users %} {% user_select bookmark_list.search users %}
<br> <br>
</div> </div>
<div class="content-area-header"> </section>
<h2>Tags</h2> <section aria-labelledby="tags-heading">
<div class="section-header">
<h2 id="tags-heading">Tags</h2>
</div> </div>
<div id="tag-cloud-container"> <div id="tag-cloud-container">
{% include 'bookmarks/tag_cloud.html' %} {% include 'bookmarks/tag_cloud.html' %}
</div> </div>
</section> </section>
</div> </div>
</div>
{% endblock %} {% endblock %}
{% block overlays %} {% block overlays %}

View File

@@ -1,8 +1,19 @@
{% extends 'bookmarks/layout.html' %} {% extends 'bookmarks/layout.html' %}
{% load widget_tweaks %} {% load widget_tweaks %}
{% block title %}Registration complete{% endblock %} {% block head %}
{% with page_title="Registration complete - Linkding" %}
{{ block.super }}
{% endwith %}
{% endblock %}
{% block content %} {% block content %}
<p>Registration complete. You can now use the application.</p> <main class="mx-auto width-50 width-md-100" aria-labelledby="main-heading">
<div class="section-header">
<h1 id="main-heading">Registration complete</h1>
</div>
<p class="text-success">
You can now use the application.
</p>
</main>
{% endblock %} {% endblock %}

View File

@@ -1,12 +1,16 @@
{% extends 'bookmarks/layout.html' %} {% extends 'bookmarks/layout.html' %}
{% load widget_tweaks %} {% load widget_tweaks %}
{% block title %}Registration{% endblock %} {% block head %}
{% with page_title="Registration - Linkding" %}
{{ block.super }}
{% endwith %}
{% endblock %}
{% block content %} {% block content %}
<section class="content-area mx-auto width-50 width-md-100"> <main class="mx-auto width-50 width-md-100" aria-labelledby="main-heading">
<div class="content-area-header"> <div class="section-header">
<h2>Register</h2> <h1 id="main-heading">Register</h1>
</div> </div>
<form method="post" action="{% url 'django_registration_register' %}" novalidate> <form method="post" action="{% url 'django_registration_register' %}" novalidate>
{% csrf_token %} {% csrf_token %}
@@ -34,5 +38,5 @@
<input type="submit" value="Register" class="btn btn-primary btn-wide"> <input type="submit" value="Register" class="btn btn-primary btn-wide">
<input type="hidden" name="next" value="{{ next }}"> <input type="hidden" name="next" value="{{ next }}">
</form> </form>
</section> </main>
{% endblock %} {% endblock %}

View File

@@ -1,12 +1,16 @@
{% extends 'bookmarks/layout.html' %} {% extends 'bookmarks/layout.html' %}
{% load widget_tweaks %} {% load widget_tweaks %}
{% block title %}Login{% endblock %} {% block head %}
{% with page_title="Login - Linkding" %}
{{ block.super }}
{% endwith %}
{% endblock %}
{% block content %} {% block content %}
<section class="content-area mx-auto width-50 width-md-100"> <main class="mx-auto width-50 width-md-100" aria-labelledby="main-heading">
<div class="content-area-header"> <div class="section-header">
<h2>Login</h2> <h1 id="main-heading">Login</h1>
</div> </div>
<form method="post" action="{% url 'login' %}"> <form method="post" action="{% url 'login' %}">
{% csrf_token %} {% csrf_token %}
@@ -36,5 +40,5 @@
{% endif %} {% endif %}
</div> </div>
</form> </form>
</section> </main>
{% endblock %} {% endblock %}

View File

@@ -1,15 +1,19 @@
{% extends 'bookmarks/layout.html' %} {% extends 'bookmarks/layout.html' %}
{% load widget_tweaks %} {% load widget_tweaks %}
{% block title %}Password changed{% endblock %} {% block head %}
{% with page_title="Password changed - Linkding" %}
{{ block.super }}
{% endwith %}
{% endblock %}
{% block content %} {% block content %}
<section class="content-area mx-auto width-50 width-md-100"> <main class="mx-auto width-50 width-md-100" aria-labelledby="main-heading">
<div class="content-area-header"> <div class="section-header">
<h2>Password Changed</h2> <h1 id="main-heading">Password Changed</h1>
</div> </div>
<p class="text-success"> <p class="text-success">
Your password was changed successfully. Your password was changed successfully.
</p> </p>
</section> </main>
{% endblock %} {% endblock %}

View File

@@ -1,12 +1,16 @@
{% extends 'bookmarks/layout.html' %} {% extends 'bookmarks/layout.html' %}
{% load widget_tweaks %} {% load widget_tweaks %}
{% block title %}Change Password{% endblock %} {% block head %}
{% with page_title="Change password - Linkding" %}
{{ block.super }}
{% endwith %}
{% endblock %}
{% block content %} {% block content %}
<section class="content-area mx-auto width-50 width-md-100"> <main class="mx-auto width-50 width-md-100" aria-labelledby="main-heading">
<div class="content-area-header"> <div class="section-header">
<h2>Change Password</h2> <h1 id="main-heading">Change Password</h1>
</div> </div>
<form method="post" action="{% url 'change_password' %}"> <form method="post" action="{% url 'change_password' %}">
{% csrf_token %} {% csrf_token %}
@@ -41,5 +45,5 @@
<br/> <br/>
<input type="submit" value="Change Password" class="btn btn-primary btn-wide"> <input type="submit" value="Change Password" class="btn btn-primary btn-wide">
</form> </form>
</section> </main>
{% endblock %} {% endblock %}

View File

@@ -1,10 +1,15 @@
{% extends "bookmarks/layout.html" %} {% extends "bookmarks/layout.html" %}
{% load widget_tweaks %} {% load widget_tweaks %}
{% block content %} {% block head %}
<div class="settings-page"> {% with page_title="Settings - Linkding" %}
{{ block.super }}
{% endwith %}
{% endblock %}
{% include 'settings/nav.html' %} {% block content %}
<main class="settings-page" aria-labelledby="main-heading">
<h1 id="main-heading">Settings</h1>
{# Profile section #} {# Profile section #}
{% if success_message %} {% if success_message %}
@@ -14,8 +19,8 @@
<div class="toast toast-error mb-4">{{ error_message }}</div> <div class="toast toast-error mb-4">{{ error_message }}</div>
{% endif %} {% endif %}
<section class="content-area"> <section aria-labelledby="profile-heading">
<h2>Profile</h2> <h2 id="profile-heading">Profile</h2>
<p> <p>
<a href="{% url 'change_password' %}">Change password</a> <a href="{% url 'change_password' %}">Change password</a>
</p> </p>
@@ -278,8 +283,8 @@ reddit.com/r/Music music reddit</pre>
{# Global settings section #} {# Global settings section #}
{% if global_settings_form %} {% if global_settings_form %}
<section class="content-area"> <section aria-labelledby="global-settings-heading">
<h2>Global settings</h2> <h2 id="global-settings-heading">Global settings</h2>
<form action="{% url 'linkding:settings.update' %}" method="post" novalidate data-turbo="false"> <form action="{% url 'linkding:settings.update' %}" method="post" novalidate data-turbo="false">
{% csrf_token %} {% csrf_token %}
<div class="form-group"> <div class="form-group">
@@ -318,8 +323,8 @@ reddit.com/r/Music music reddit</pre>
{% endif %} {% endif %}
{# Import section #} {# Import section #}
<section class="content-area"> <section aria-labelledby="import-heading">
<h2>Import</h2> <h2 id="import-heading">Import</h2>
<p>Import bookmarks and tags in the Netscape HTML format. This will execute a sync where new bookmarks are <p>Import bookmarks and tags in the Netscape HTML format. This will execute a sync where new bookmarks are
added and existing ones are updated.</p> added and existing ones are updated.</p>
<form method="post" enctype="multipart/form-data" action="{% url 'linkding:settings.import' %}"> <form method="post" enctype="multipart/form-data" action="{% url 'linkding:settings.import' %}">
@@ -346,8 +351,8 @@ reddit.com/r/Music music reddit</pre>
</section> </section>
{# Export section #} {# Export section #}
<section class="content-area"> <section aria-labelledby="export-heading">
<h2>Export</h2> <h2 id="export-heading">Export</h2>
<p>Export all bookmarks in Netscape HTML format.</p> <p>Export all bookmarks in Netscape HTML format.</p>
<a class="btn btn-primary" target="_blank" href="{% url 'linkding:settings.export' %}">Download (.html)</a> <a class="btn btn-primary" target="_blank" href="{% url 'linkding:settings.export' %}">Download (.html)</a>
{% if export_error %} {% if export_error %}
@@ -360,8 +365,8 @@ reddit.com/r/Music music reddit</pre>
</section> </section>
{# About section #} {# About section #}
<section class="content-area about"> <section class="about" aria-labelledby="about-heading">
<h2>About</h2> <h2 id="about-heading">About</h2>
<table class="table"> <table class="table">
<tbody> <tbody>
<tr> <tr>
@@ -384,7 +389,7 @@ reddit.com/r/Music music reddit</pre>
</tbody> </tbody>
</table> </table>
</section> </section>
</div> </main>
<script> <script>
(function init() { (function init() {

View File

@@ -1,12 +1,17 @@
{% extends "bookmarks/layout.html" %} {% extends "bookmarks/layout.html" %}
{% block head %}
{% with page_title="Integrations - Linkding" %}
{{ block.super }}
{% endwith %}
{% endblock %}
{% block content %} {% block content %}
<div class="settings-page"> <main class="settings-page" aria-labelledby="main-heading">
<h1 id="main-heading">Integrations</h1>
{% include 'settings/nav.html' %} <section aria-labelledby="browser-extension-heading">
<h2 id="browser-extension-heading">Browser Extension</h2>
<section class="content-area">
<h2>Browser Extension</h2>
<p>The browser extension allows you to quickly add new bookmarks without leaving the page that you are on. The <p>The browser extension allows you to quickly add new bookmarks without leaving the page that you are on. The
extension is available in the official extension stores for:</p> extension is available in the official extension stores for:</p>
<ul> <ul>
@@ -31,8 +36,8 @@
class="btn btn-primary">📎 Add bookmark</a> class="btn btn-primary">📎 Add bookmark</a>
</section> </section>
<section class="content-area"> <section aria-labelledby="rest-api-heading">
<h2>REST API</h2> <h2 id="rest-api-heading">REST API</h2>
<p>The following token can be used to authenticate 3rd-party applications against the REST API:</p> <p>The following token can be used to authenticate 3rd-party applications against the REST API:</p>
<div class="form-group"> <div class="form-group">
<div class="width-50 width-md-100"> <div class="width-50 width-md-100">
@@ -48,8 +53,8 @@
</p> </p>
</section> </section>
<section class="content-area"> <section aria-labelledby="rss-feeds-heading">
<h2>RSS Feeds</h2> <h2 id="rss-feeds-heading">RSS Feeds</h2>
<p>The following URLs provide RSS feeds for your bookmarks:</p> <p>The following URLs provide RSS feeds for your bookmarks:</p>
<ul style="list-style-position: outside;"> <ul style="list-style-position: outside;">
<li><a target="_blank" href="{{ all_feed_url }}">All bookmarks</a></li> <li><a target="_blank" href="{{ all_feed_url }}">All bookmarks</a></li>
@@ -84,5 +89,5 @@
After deleting the feed token, new URLs will be generated when you reload this settings page. After deleting the feed token, new URLs will be generated when you reload this settings page.
</p> </p>
</section> </section>
</div> </main>
{% endblock %} {% endblock %}

View File

@@ -1,24 +0,0 @@
{% url 'linkding:settings.index' as index_url %}
{% url 'linkding:settings.general' as general_url %}
{% url 'linkding:settings.integrations' as integrations_url %}
<ul class="tab tab-block">
<li class="tab-item {% if request.get_full_path == index_url or request.get_full_path == general_url%}active{% endif %}">
<a href="{{ general_url }}">General</a>
</li>
<li class="tab-item {% if request.get_full_path == integrations_url %}active{% endif %}">
<a href="{{ integrations_url }}">Integrations</a>
</li>
{% if request.user.is_superuser %}
<li class="tab-item">
<a href="{% url 'admin:index' %}" target="_blank">
<span>Admin</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="ml-1" style="width: 1.2em; height: 1.2em; vertical-align: -0.2em;">
<path d="M11 3a1 1 0 100 2h2.586l-6.293 6.293a1 1 0 101.414 1.414L15 6.414V9a1 1 0 102 0V4a1 1 0 00-1-1h-5z" />
<path d="M5 5a2 2 0 00-2 2v8a2 2 0 002 2h8a2 2 0 002-2v-3a1 1 0 10-2 0v3H5V7h3a1 1 0 000-2H5z" />
</svg>
</a>
</li>
{% endif %}
</ul>
<br>

View File

@@ -24,6 +24,13 @@ class LayoutTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
html, html,
count=0, count=0,
) )
self.assertInHTML(
f"""
<a href="{reverse('linkding:bookmarks.shared')}" class="menu-link">Shared bookmarks</a>
""",
html,
count=0,
)
self.user.profile.enable_sharing = True self.user.profile.enable_sharing = True
self.user.profile.save() self.user.profile.save()
@@ -35,7 +42,14 @@ class LayoutTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
<a href="{reverse('linkding:bookmarks.shared')}" class="menu-link">Shared</a> <a href="{reverse('linkding:bookmarks.shared')}" class="menu-link">Shared</a>
""", """,
html, html,
count=2, count=1,
)
self.assertInHTML(
f"""
<a href="{reverse('linkding:bookmarks.shared')}" class="menu-link">Shared bookmarks</a>
""",
html,
count=1,
) )
def test_metadata_should_respect_prefetch_links_setting(self): def test_metadata_should_respect_prefetch_links_setting(self):

View File

@@ -593,7 +593,7 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
html = response.content.decode() html = response.content.decode()
self.assertInHTML( self.assertInHTML(
"<h2>Global settings</h2>", '<h2 id="global-settings-heading">Global settings</h2>',
html, html,
count=0, count=0,
) )
@@ -605,7 +605,7 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
html = response.content.decode() html = response.content.decode()
self.assertInHTML( self.assertInHTML(
"<h2>Global settings</h2>", '<h2 id="global-settings-heading">Global settings</h2>',
html, html,
count=1, count=1,
) )

View File

@@ -16,9 +16,7 @@ class FilterDrawerE2ETestCase(LinkdingE2ETestCase):
page.set_viewport_size({"width": 375, "height": 812}) page.set_viewport_size({"width": 375, "height": 812})
# open drawer # open drawer
drawer_trigger = page.locator(".content-area-header").get_by_role( drawer_trigger = page.locator(".main").get_by_role("button", name="Filters")
"button", name="Filters"
)
drawer_trigger.click() drawer_trigger.click()
# verify drawer is visible # verify drawer is visible
@@ -49,9 +47,7 @@ class FilterDrawerE2ETestCase(LinkdingE2ETestCase):
page.set_viewport_size({"width": 375, "height": 812}) page.set_viewport_size({"width": 375, "height": 812})
# open tag cloud modal # open tag cloud modal
drawer_trigger = page.locator(".content-area-header").get_by_role( drawer_trigger = page.locator(".main").get_by_role("button", name="Filters")
"button", name="Filters"
)
drawer_trigger.click() drawer_trigger.click()
# verify tags are displayed # verify tags are displayed

View File

@@ -51,6 +51,7 @@ def index(request: HttpRequest):
request, request,
"bookmarks/index.html", "bookmarks/index.html",
{ {
"page_title": "Bookmarks - Linkding",
"bookmark_list": bookmark_list, "bookmark_list": bookmark_list,
"tag_cloud": tag_cloud, "tag_cloud": tag_cloud,
"details": bookmark_details, "details": bookmark_details,
@@ -73,6 +74,7 @@ def archived(request: HttpRequest):
request, request,
"bookmarks/archive.html", "bookmarks/archive.html",
{ {
"page_title": "Archived bookmarks - Linkding",
"bookmark_list": bookmark_list, "bookmark_list": bookmark_list,
"tag_cloud": tag_cloud, "tag_cloud": tag_cloud,
"details": bookmark_details, "details": bookmark_details,
@@ -97,6 +99,7 @@ def shared(request: HttpRequest):
request, request,
"bookmarks/shared.html", "bookmarks/shared.html",
{ {
"page_title": "Shared bookmarks - Linkding",
"bookmark_list": bookmark_list, "bookmark_list": bookmark_list,
"tag_cloud": tag_cloud, "tag_cloud": tag_cloud,
"details": bookmark_details, "details": bookmark_details,
@@ -107,6 +110,9 @@ def shared(request: HttpRequest):
def render_bookmarks_view(request: HttpRequest, template_name, context): def render_bookmarks_view(request: HttpRequest, template_name, context):
if context["details"]:
context["page_title"] = "Bookmark details - Linkding"
if turbo.is_frame(request, "details-modal"): if turbo.is_frame(request, "details-modal"):
return render( return render(
request, request,