Compare commits

..

3 Commits

20 changed files with 158 additions and 190 deletions

1
.gitignore vendored
View File

@@ -364,3 +364,4 @@ Temporary Items
.apdisk
.kateproject*
.*.kate-swp

Binary file not shown.

View File

@@ -141,9 +141,19 @@ def render_image(request, path_text, full_path, special=None):
except Exception:
dir_text = ""
# For special galleries hide the Back control but still present Home
# Back (directory) and Home (root) links and thumbnails
# For special galleries we still want to show a Back link that points
# to the special gallery root — populate `back_thumb` with the
# thumbnail of the first image in that special gallery so the UI can
# display a representative image. For non-special views keep the
# existing behavior (thumbnail for parent directory).
if special is not None:
back_url = None
# images_sorted is already the special list in the requested order
try:
first_image = images_sorted[0] if len(images_sorted) > 0 else None
back_thumb = thumb_for(first_image)
except Exception:
back_thumb = None
else:
back_url = gallery_url(

View File

@@ -1,128 +0,0 @@
/****************************************************************************
* Specific elements. *
****************************************************************************/
html {
height:100%;
}
body {
height: 100%;
margin: 0px;
}
#id_username {
width: 100%;
}
#id_password {
width: 100%;
}
a:link {
color: #ffff00;
}
a:visited {
color: #009CD9;
}
/****************************************************************************
* Containers. *
****************************************************************************/
.centered-container {
width: 100%;
text-align: center;
margin-bottom: 0.5em;
}
.background {
background-color: darkslategray;
color: lightgray;
}
.image-container {
max-width: 900px;
max-height: 600px;
}
.fc {
width: fit-content;
}
.h90 {
height: 90%;
}
.full-width {
width: 100%;
}
.fixed-width {
width: 300px;
}
/****************************************************************************
* Content. *
****************************************************************************/
.image {
max-width: 100%;
max-height: 600px;
width: auto;
}
.mauto {
margin: auto;
}
.mauto-top {
margin: 200px auto;
}
.navigation-icon {
width: 100px;
}
.small-nav-icon {
width: 3em;
}
.mb-2 {
margin-bottom: 2em;
}
.mr-2 {
margin-right: 2em;
}
.ml-4 {
margin-left: 4em;
}
.ml-2 {
margin-left: 2em;
}
.clear-btn {
border: none;
background-color: #00000000;
}
.search-box {
height: 2.5em;
}
.float-right {
float: right;
}
/****************************************************************************
* Grid. *
****************************************************************************/
.column {
text-align: center;
border: black 1px solid;
}

View File

@@ -378,7 +378,16 @@ body.theme-dark .small.text-muted {
background: transparent;
}
@media (max-width: 991.98px) {
.login-form {
background: var(--panel-strong);
border-radius: 0 1rem 1rem 0;
}
.card {
background: var(--bg);
}
media (max-width: 991.98px) {
.app-shell {
padding: 0px;
gap: 12px;
@@ -405,6 +414,12 @@ body.theme-dark .small.text-muted {
padding-right: 16px;
}
}
@media (max-width: 767px) {
.login-form {
background: var(--panel-strong);
border-radius: 1rem 1rem 1rem 1rem;
}
}
@media (max-width: 575.98px) {
/* On narrow viewports keep the fixed 128px thumbnails but allow the

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

BIN
viewer/static/imgs/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -206,6 +206,7 @@
{% endfor %}
</div>
{% if not is_special %}
<div class="dropdown ms-auto">
<button class="btn btn-sm btn-plain" type="button" data-bs-toggle="dropdown" aria-expanded="false" title="{{ sort_label }}" aria-label="Sort options">
<i class="fa-solid fa-arrow-down-short-wide"></i>
@@ -218,8 +219,10 @@
{% endfor %}
</ul>
</div>
{% endif %}
</div>
{% if not is_special %}
<noscript>
<div class="pt-2">
{% for option in sort_options %}
@@ -227,6 +230,7 @@
{% endfor %}
</div>
</noscript>
{% endif %}
<section class="gallery-scroll flex-grow-1">
<div class="gallery-grid">

View File

@@ -205,13 +205,14 @@
</div>
</div>
<div class="offcanvas-body pt-0 d-flex flex-column">
<a href="#" class="sidebar-link">Favorites</a>
<a href="#" class="sidebar-link">Most visited</a>
<a href="#" class="sidebar-link">Recently visited</a>
<a href="/gallery/favorites/" class="sidebar-link {% if is_special and breadcrumbs.0.label == 'Favorites' %}active-sort{% endif %}">Favorites</a>
<a href="/gallery/most-visited/" class="sidebar-link {% if is_special and breadcrumbs.0.label == 'Most Visited' %}active-sort{% endif %}">Most visited</a>
<a href="/gallery/recent/" class="sidebar-link {% if is_special and breadcrumbs.0.label == 'Recent' %}active-sort{% endif %}">Recently visited</a>
<hr>
<div class="sidebar-scroll flex-grow-1">
{% if not is_special or is_special and 'favorites' in breadcrumbs.0.path %}
{% if prev_url %}
<a href="{{ prev_url }}" class="subdir-item">
{% if prev_thumb %}
@@ -233,6 +234,7 @@
<span>Next</span>
</a>
{% endif %}
{% endif %}
{% if is_special %}
<a href="{{ breadcrumbs.0.path }}" class="subdir-item">

View File

@@ -1,43 +1,74 @@
{% load static %}
{% load static form_tags %}
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, height=device-height" />
<title>
NibasaViewer login
</title>
<link href="{% static 'css/old_styles.css' %}" rel="stylesheet">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>NibasaViewer — Login</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer">
<link href="{% static 'css/styles.css' %}" rel="stylesheet">
</head>
<body class="background">
<div class="fixed-width mauto-top">
<form method="post" action="{% url 'login' %}" class="full-width">
{% csrf_token %}
<table class="full-width">
<tr>
<td>
{{ form.username.label_tag }}
</td>
<td>
{{ form.username }}
</td>
</tr>
<tr>
<td>
{{ form.password.label_tag }}
</td>
<td>
{{ form.password }}
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="login" class="float-right">
<input type="hidden" name="next" value="{{ next }}">
</td>
</tr>
</table>
</form>
<body class="theme-{{ theme|default:'dark' }}">
<section class="vh-100">
<div class="container py-5 h-100">
<div class="row d-flex justify-content-center align-items-center h-100">
<div class="col col-xl-10">
<div class="card shadow" style="border-radius: 1rem;">
<div class="row g-0">
<div class="col-md-6 col-lg-5 d-none d-md-block">
<img src="{% static 'imgs/login.jpg' %}"
alt="login image" class="img-fluid" style="height:100%; object-fit:cover; border-radius: 1rem 0 0 1rem;" />
</div>
<div class="col-md-6 col-lg-7 d-flex align-items-center">
<div class="card-body p-4 p-lg-5 text-black h-100 login-form">
<form method="post" action="{% url 'login' %}" class="w-100">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-danger">{{ form.non_field_errors }}</div>
{% endif %}
<div class="d-flex align-items-center mb-3 pb-1">
<img src="{% static 'imgs/logo.png' %}" alt="Logo" style="width:44px; height:44px; object-fit:contain;" class="me-3">
<span class="h1 fw-bold mb-0 text-light">Nibasa Viewer</span>
</div>
<h5 class="fw-normal mb-1 mt-4 pb-3" style="letter-spacing: 1px; color:var(--muted);">Sign in</h5>
<div class="mb-4">
{% render_field form.username class="form-control form-control-lg" placeholder="User name" autocomplete="username" %}
{% if form.username.errors %}
<div class="text-danger small mt-1">{{ form.username.errors|striptags }}</div>
{% endif %}
</div>
<div class="mb-4">
{% render_field form.password class="form-control form-control-lg" placeholder="Password" autocomplete="current-password" %}
{% if form.password.errors %}
<div class="text-danger small mt-1">{{ form.password.errors|striptags }}</div>
{% endif %}
</div>
<div class="pt-1 mb-4">
<button class="btn btn-dark btn-lg btn-block w-100" type="submit">LOGIN</button>
</div>
{% if next %}
<input type="hidden" name="next" value="{{ next }}">
{% endif %}
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>

View File

View File

@@ -0,0 +1,33 @@
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
@register.simple_tag
def render_field(field, **attrs):
"""Render a bound field with temporary widget attributes.
Usage in template:
{% render_field form.username class="form-control" placeholder="Email" %}
This updates the widget attrs just for the duration of rendering and
restores the original attrs afterwards to avoid side effects.
"""
try:
widget = field.field.widget
except Exception:
return ""
# preserve original attrs and update temporarily
original_attrs = widget.attrs.copy()
# Convert all attr values to strings (template passes them as strings)
for k, v in attrs.items():
widget.attrs[str(k)] = str(v)
rendered = field.as_widget()
# restore original attrs
widget.attrs = original_attrs
return mark_safe(rendered)