mirror of
https://github.com/wowlikon/LiB.git
synced 2026-02-04 04:31:09 +00:00
Добавление мета-тэгов
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
# Postgres
|
||||
POSTGRES_HOST="localhost"
|
||||
POSTGRES_PORT="5432"
|
||||
POSTGRES_USER="postgres"
|
||||
POSTGRES_PASSWORD="postgres"
|
||||
POSTGRES_DB="lib"
|
||||
POSTGRES_HOST=localhost
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
POSTGRES_DB=lib
|
||||
|
||||
# Ollama
|
||||
OLLAMA_URL="http://localhost:11434"
|
||||
@@ -16,28 +16,29 @@ OLLAMA_KEEP_ALIVE=5m
|
||||
# DEFAULT_ADMIN_EMAIL="admin@example.com"
|
||||
# DEFAULT_ADMIN_PASSWORD="password-is-generated-randomly-on-first-launch"
|
||||
SECRET_KEY="your-secret-key-change-in-production"
|
||||
DOMAIN=localhost
|
||||
|
||||
# JWT
|
||||
ALGORITHM="HS256"
|
||||
REFRESH_TOKEN_EXPIRE_DAYS="7"
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES="15"
|
||||
PARTIAL_TOKEN_EXPIRE_MINUTES="5"
|
||||
ALGORITHM=HS256
|
||||
REFRESH_TOKEN_EXPIRE_DAYS=7
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES=15
|
||||
PARTIAL_TOKEN_EXPIRE_MINUTES=5
|
||||
|
||||
# Hash
|
||||
ARGON2_TYPE="id"
|
||||
ARGON2_TIME_COST="3"
|
||||
ARGON2_MEMORY_COST="65536"
|
||||
ARGON2_PARALLELISM="4"
|
||||
ARGON2_SALT_LENGTH="16"
|
||||
ARGON2_HASH_LENGTH="48"
|
||||
ARGON2_TYPE=id
|
||||
ARGON2_TIME_COST=3
|
||||
ARGON2_MEMORY_COST=65536
|
||||
ARGON2_PARALLELISM=4
|
||||
ARGON2_SALT_LENGTH=16
|
||||
ARGON2_HASH_LENGTH=48
|
||||
|
||||
# Recovery codes
|
||||
RECOVERY_CODES_COUNT="10"
|
||||
RECOVERY_CODE_SEGMENTS="4"
|
||||
RECOVERY_CODE_SEGMENT_BYTES="2"
|
||||
RECOVERY_MIN_REMAINING_WARNING="3"
|
||||
RECOVERY_MAX_AGE_DAYS="365"
|
||||
RECOVERY_CODES_COUNT=10
|
||||
RECOVERY_CODE_SEGMENTS=4
|
||||
RECOVERY_CODE_SEGMENT_BYTES=2
|
||||
RECOVERY_MIN_REMAINING_WARNING=3
|
||||
RECOVERY_MAX_AGE_DAYS=365
|
||||
|
||||
# TOTP_2FA
|
||||
TOTP_ISSUER="LiB"
|
||||
TOTP_VALID_WINDOW="1"
|
||||
TOTP_ISSUER=LiB
|
||||
TOTP_VALID_WINDOW=1
|
||||
|
||||
+23
-22
@@ -1,9 +1,9 @@
|
||||
# Postgres
|
||||
POSTGRES_HOST="db"
|
||||
POSTGRES_PORT="5432"
|
||||
POSTGRES_USER="postgres"
|
||||
POSTGRES_PASSWORD="postgres"
|
||||
POSTGRES_DB="lib"
|
||||
POSTGRES_HOST=db
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
POSTGRES_DB=lib
|
||||
REMOTE_HOST=
|
||||
REMOTE_PORT=
|
||||
NODE_ID=
|
||||
@@ -19,28 +19,29 @@ DEFAULT_ADMIN_USERNAME="admin"
|
||||
DEFAULT_ADMIN_EMAIL="admin@example.com"
|
||||
DEFAULT_ADMIN_PASSWORD="Password12345"
|
||||
SECRET_KEY="your-secret-key-change-in-production"
|
||||
DOMAIN="mydomain.com"
|
||||
|
||||
# JWT
|
||||
ALGORITHM="HS256"
|
||||
REFRESH_TOKEN_EXPIRE_DAYS="7"
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES="15"
|
||||
PARTIAL_TOKEN_EXPIRE_MINUTES="5"
|
||||
ALGORITHM=HS256
|
||||
REFRESH_TOKEN_EXPIRE_DAYS=7
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES=15
|
||||
PARTIAL_TOKEN_EXPIRE_MINUTES=5
|
||||
|
||||
# Hash
|
||||
ARGON2_TYPE="id"
|
||||
ARGON2_TIME_COST="3"
|
||||
ARGON2_MEMORY_COST="65536"
|
||||
ARGON2_PARALLELISM="4"
|
||||
ARGON2_SALT_LENGTH="16"
|
||||
ARGON2_HASH_LENGTH="48"
|
||||
ARGON2_TYPE=id
|
||||
ARGON2_TIME_COST=3
|
||||
ARGON2_MEMORY_COST=65536
|
||||
ARGON2_PARALLELISM=4
|
||||
ARGON2_SALT_LENGTH=16
|
||||
ARGON2_HASH_LENGTH=48
|
||||
|
||||
# Recovery codes
|
||||
RECOVERY_CODES_COUNT="10"
|
||||
RECOVERY_CODE_SEGMENTS="4"
|
||||
RECOVERY_CODE_SEGMENT_BYTES="2"
|
||||
RECOVERY_MIN_REMAINING_WARNING="3"
|
||||
RECOVERY_MAX_AGE_DAYS="365"
|
||||
RECOVERY_CODES_COUNT=10
|
||||
RECOVERY_CODE_SEGMENTS=4
|
||||
RECOVERY_CODE_SEGMENT_BYTES=2
|
||||
RECOVERY_MIN_REMAINING_WARNING=3
|
||||
RECOVERY_MAX_AGE_DAYS=365
|
||||
|
||||
# TOTP_2FA
|
||||
TOTP_ISSUER="LiB"
|
||||
TOTP_VALID_WINDOW="1"
|
||||
TOTP_ISSUER=LiB
|
||||
TOTP_VALID_WINDOW=1
|
||||
|
||||
+23
-22
@@ -1,9 +1,9 @@
|
||||
# Postgres
|
||||
POSTGRES_HOST="localhost"
|
||||
POSTGRES_PORT="5432"
|
||||
POSTGRES_USER="postgres"
|
||||
POSTGRES_PASSWORD="postgres"
|
||||
POSTGRES_DB="lib"
|
||||
POSTGRES_HOST=localhost
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
POSTGRES_DB=lib
|
||||
|
||||
# Ollama
|
||||
OLLAMA_URL="http://localhost:11434"
|
||||
@@ -16,28 +16,29 @@ DEFAULT_ADMIN_USERNAME="admin"
|
||||
DEFAULT_ADMIN_EMAIL="admin@example.com"
|
||||
DEFAULT_ADMIN_PASSWORD="Password12345"
|
||||
SECRET_KEY="your-secret-key-change-in-production"
|
||||
DOMAIN="mydomain.com"
|
||||
|
||||
# JWT
|
||||
ALGORITHM="HS256"
|
||||
REFRESH_TOKEN_EXPIRE_DAYS="7"
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES="15"
|
||||
PARTIAL_TOKEN_EXPIRE_MINUTES="5"
|
||||
ALGORITHM=HS256
|
||||
REFRESH_TOKEN_EXPIRE_DAYS=7
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES=15
|
||||
PARTIAL_TOKEN_EXPIRE_MINUTES=5
|
||||
|
||||
# Hash
|
||||
ARGON2_TYPE="id"
|
||||
ARGON2_TIME_COST="3"
|
||||
ARGON2_MEMORY_COST="65536"
|
||||
ARGON2_PARALLELISM="4"
|
||||
ARGON2_SALT_LENGTH="16"
|
||||
ARGON2_HASH_LENGTH="48"
|
||||
ARGON2_TYPE=id
|
||||
ARGON2_TIME_COST=3
|
||||
ARGON2_MEMORY_COST=65536
|
||||
ARGON2_PARALLELISM=4
|
||||
ARGON2_SALT_LENGTH=16
|
||||
ARGON2_HASH_LENGTH=48
|
||||
|
||||
# Recovery codes
|
||||
RECOVERY_CODES_COUNT="10"
|
||||
RECOVERY_CODE_SEGMENTS="4"
|
||||
RECOVERY_CODE_SEGMENT_BYTES="2"
|
||||
RECOVERY_MIN_REMAINING_WARNING="3"
|
||||
RECOVERY_MAX_AGE_DAYS="365"
|
||||
RECOVERY_CODES_COUNT=10
|
||||
RECOVERY_CODE_SEGMENTS=4
|
||||
RECOVERY_CODE_SEGMENT_BYTES=2
|
||||
RECOVERY_MIN_REMAINING_WARNING=3
|
||||
RECOVERY_MAX_AGE_DAYS=365
|
||||
|
||||
# TOTP_2FA
|
||||
TOTP_ISSUER="LiB"
|
||||
TOTP_VALID_WINDOW="1"
|
||||
TOTP_ISSUER=LiB
|
||||
TOTP_VALID_WINDOW=1
|
||||
|
||||
@@ -81,7 +81,7 @@ async def custom_not_found_handler(request: Request, exc: HTTPException):
|
||||
content={"detail": "API endpoint not found", "path": path},
|
||||
)
|
||||
|
||||
return await unknown(request)
|
||||
return await unknown(request, app)
|
||||
|
||||
|
||||
@app.middleware("http")
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
"""Модуль прочих эндпоинтов и веб-страниц"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
@@ -31,115 +33,116 @@ def get_info(app) -> Dict:
|
||||
"description": app.description.rsplit("|", 1)[0],
|
||||
},
|
||||
"server_time": datetime.now().isoformat(),
|
||||
"domain": os.getenv("DOMAIN", ""),
|
||||
}
|
||||
|
||||
|
||||
@router.get("/", include_in_schema=False)
|
||||
async def root(request: Request):
|
||||
async def root(request: Request, app=Depends(lambda: get_app())):
|
||||
"""Рендерит главную страницу"""
|
||||
return templates.TemplateResponse(request, "index.html")
|
||||
return templates.TemplateResponse(request, "index.html", get_info(app) | {"title": "LiB - Библиотека"})
|
||||
|
||||
|
||||
@router.get("/unknown", include_in_schema=False)
|
||||
async def unknown(request: Request):
|
||||
async def unknown(request: Request, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу 404 ошибки"""
|
||||
return templates.TemplateResponse(request, "unknown.html")
|
||||
return templates.TemplateResponse(request, "unknown.html", get_info(app) | {"title": "LiB - Страница не найдена"})
|
||||
|
||||
|
||||
@router.get("/genre/create", include_in_schema=False)
|
||||
async def create_genre(request: Request):
|
||||
async def create_genre(request: Request, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу создания жанра"""
|
||||
return templates.TemplateResponse(request, "create_genre.html")
|
||||
return templates.TemplateResponse(request, "create_genre.html", get_info(app) | {"title": "LiB - Создать жанр"})
|
||||
|
||||
|
||||
@router.get("/genre/{genre_id}/edit", include_in_schema=False)
|
||||
async def edit_genre(request: Request, genre_id: int):
|
||||
async def edit_genre(request: Request, genre_id: int, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу редактирования жанра"""
|
||||
return templates.TemplateResponse(request, "edit_genre.html")
|
||||
return templates.TemplateResponse(request, "edit_genre.html", get_info(app) | {"id": genre_id} | {"id": genre_id, "title": "LiB - Редактировать жанр"})
|
||||
|
||||
|
||||
@router.get("/authors", include_in_schema=False)
|
||||
async def authors(request: Request):
|
||||
async def authors(request: Request, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу списка авторов"""
|
||||
return templates.TemplateResponse(request, "authors.html")
|
||||
return templates.TemplateResponse(request, "authors.html", get_info(app) | {"title": "LiB - Авторы"})
|
||||
|
||||
|
||||
@router.get("/author/create", include_in_schema=False)
|
||||
async def create_author(request: Request):
|
||||
async def create_author(request: Request, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу создания автора"""
|
||||
return templates.TemplateResponse(request, "create_author.html")
|
||||
return templates.TemplateResponse(request, "create_author.html", get_info(app) | {"title": "LiB - Создать автора"})
|
||||
|
||||
|
||||
@router.get("/author/{author_id}/edit", include_in_schema=False)
|
||||
async def edit_author(request: Request, author_id: int):
|
||||
async def edit_author(request: Request, author_id: int, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу редактирования автора"""
|
||||
return templates.TemplateResponse(request, "edit_author.html")
|
||||
return templates.TemplateResponse(request, "edit_author.html", get_info(app) | {"id": author_id, "title": "LiB - Редактировать автора"})
|
||||
|
||||
|
||||
@router.get("/author/{author_id}", include_in_schema=False)
|
||||
async def author(request: Request, author_id: int):
|
||||
async def author(request: Request, author_id: int, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу просмотра автора"""
|
||||
return templates.TemplateResponse(request, "author.html")
|
||||
return templates.TemplateResponse(request, "author.html", get_info(app) | {"id": author_id, "title": "LiB - Автор"})
|
||||
|
||||
|
||||
@router.get("/books", include_in_schema=False)
|
||||
async def books(request: Request):
|
||||
async def books(request: Request, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу списка книг"""
|
||||
return templates.TemplateResponse(request, "books.html")
|
||||
return templates.TemplateResponse(request, "books.html", get_info(app) | {"title": "LiB - Книги"})
|
||||
|
||||
|
||||
@router.get("/book/create", include_in_schema=False)
|
||||
async def create_book(request: Request):
|
||||
async def create_book(request: Request, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу создания книги"""
|
||||
return templates.TemplateResponse(request, "create_book.html")
|
||||
return templates.TemplateResponse(request, "create_book.html", get_info(app) | {"title": "LiB - Создать книгу"})
|
||||
|
||||
|
||||
@router.get("/book/{book_id}/edit", include_in_schema=False)
|
||||
async def edit_book(request: Request, book_id: int):
|
||||
async def edit_book(request: Request, book_id: int, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу редактирования книги"""
|
||||
return templates.TemplateResponse(request, "edit_book.html")
|
||||
return templates.TemplateResponse(request, "edit_book.html", get_info(app) | {"id": book_id, "title": "LiB - Редактировать книгу"})
|
||||
|
||||
|
||||
@router.get("/book/{book_id}", include_in_schema=False)
|
||||
async def book(request: Request, book_id: int):
|
||||
async def book(request: Request, book_id: int, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу просмотра книги"""
|
||||
return templates.TemplateResponse(request, "book.html")
|
||||
return templates.TemplateResponse(request, "book.html", get_info(app) | {"id": book_id, "title": "LiB - Книга"})
|
||||
|
||||
|
||||
@router.get("/auth", include_in_schema=False)
|
||||
async def auth(request: Request):
|
||||
async def auth(request: Request, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу авторизации"""
|
||||
return templates.TemplateResponse(request, "auth.html")
|
||||
return templates.TemplateResponse(request, "auth.html", get_info(app) | {"title": "LiB - Авторизация"})
|
||||
|
||||
|
||||
@router.get("/2fa", include_in_schema=False)
|
||||
async def set2fa(request: Request):
|
||||
async def set2fa(request: Request, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу установки двухфакторной аутентификации"""
|
||||
return templates.TemplateResponse(request, "2fa.html")
|
||||
return templates.TemplateResponse(request, "2fa.html", get_info(app) | {"title": "LiB - Двухфакторная аутентификация"})
|
||||
|
||||
|
||||
@router.get("/profile", include_in_schema=False)
|
||||
async def profile(request: Request):
|
||||
async def profile(request: Request, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу профиля пользователя"""
|
||||
return templates.TemplateResponse(request, "profile.html")
|
||||
return templates.TemplateResponse(request, "profile.html", get_info(app) | {"title": "LiB - Профиль"})
|
||||
|
||||
|
||||
@router.get("/users", include_in_schema=False)
|
||||
async def users(request: Request):
|
||||
async def users(request: Request, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу управления пользователями"""
|
||||
return templates.TemplateResponse(request, "users.html")
|
||||
return templates.TemplateResponse(request, "users.html", get_info(app) | {"title": "LiB - Пользователи"})
|
||||
|
||||
|
||||
@router.get("/my-books", include_in_schema=False)
|
||||
async def my_books(request: Request):
|
||||
async def my_books(request: Request, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу моих книг пользователя"""
|
||||
return templates.TemplateResponse(request, "my_books.html")
|
||||
return templates.TemplateResponse(request, "my_books.html", get_info(app) | {"title": "LiB - Мои книги"})
|
||||
|
||||
|
||||
@router.get("/analytics", include_in_schema=False)
|
||||
async def analytics(request: Request):
|
||||
async def analytics(request: Request, app=Depends(lambda: get_app())):
|
||||
"""Рендерит страницу аналитики выдач"""
|
||||
return templates.TemplateResponse(request, "analytics.html")
|
||||
return templates.TemplateResponse(request, "analytics.html", get_info(app) | {"title": "LiB - Аналитика"})
|
||||
|
||||
|
||||
@router.get("/favicon.ico", include_in_schema=False)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Настройка 2FA{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="flex flex-1 items-center justify-center p-4 bg-gray-100">
|
||||
<div
|
||||
class="w-full max-w-4xl bg-white rounded-lg shadow-md overflow-hidden flex flex-col md:flex-row"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Аналитика{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="container mx-auto p-4 max-w-7xl">
|
||||
<div class="mb-8">
|
||||
<h1 class="text-2xl font-semibold text-gray-900 mb-1">Аналитика выдач и возвратов</h1>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Авторизация{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="flex flex-1 items-center justify-center p-4">
|
||||
<div class="w-full max-w-md">
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Автор{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="container mx-auto p-4 max-w-4xl">
|
||||
<div id="author-card" class="bg-white rounded-lg shadow-md p-6 mb-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Авторы{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="container mx-auto p-4">
|
||||
<div
|
||||
class="flex flex-col md:flex-row justify-between items-center mb-6 gap-4"
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
<!doctype html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<title>{% block title %}LiB{% endblock %}</title>
|
||||
<title>{{ title }}</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta property="og:title" content="{{ title }}" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:description" content="Ваша персональная библиотека книг" />
|
||||
<meta property="og:url" content="//{{ domain }}/" />
|
||||
<!--<meta property="og:image" content="//{{ domain }}/img/{{ img }}.png" />-->
|
||||
|
||||
<script
|
||||
defer
|
||||
src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Книга{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="container mx-auto p-4 max-w-6xl">
|
||||
<div id="book-card" class="bg-white rounded-lg shadow-md p-6 mb-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Книги{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<style>
|
||||
.range-double {
|
||||
height: 0;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Создание автора{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="container mx-auto p-4 max-w-xl">
|
||||
<div class="bg-white rounded-lg shadow-md p-6 md:p-8">
|
||||
<div class="mb-8 border-b border-gray-100 pb-4">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Создание книги{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="container mx-auto p-4 max-w-3xl">
|
||||
<div class="bg-white rounded-lg shadow-md p-6 md:p-8">
|
||||
<div class="mb-8 border-b border-gray-100 pb-4">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Создание жанра{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="container mx-auto p-4 max-w-xl">
|
||||
<div class="bg-white rounded-lg shadow-md p-6 md:p-8">
|
||||
<div class="mb-8 border-b border-gray-100 pb-4">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Редактирование автора{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="container mx-auto p-4 max-w-2xl">
|
||||
<div class="bg-white rounded-lg shadow-md p-6 md:p-8">
|
||||
<div class="mb-8 border-b border-gray-100 pb-4">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Редактирование книги{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="container mx-auto p-4 max-w-3xl">
|
||||
<div class="bg-white rounded-lg shadow-md p-6 md:p-8">
|
||||
<div class="mb-8 border-b border-gray-100 pb-4">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Редактирование жанра{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="container mx-auto p-4 max-w-2xl">
|
||||
<div class="bg-white rounded-lg shadow-md p-6 md:p-8">
|
||||
<div class="mb-8 border-b border-gray-100 pb-4">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Библиотека{% endblock %}
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="flex flex-1 items-center justify-center p-4">
|
||||
<div class="w-full max-w-4xl">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Мои книги{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="container mx-auto p-4 max-w-6xl">
|
||||
<div class="mb-6">
|
||||
<h1 class="text-3xl font-bold text-gray-900 mb-2">Мои книги</h1>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Профиль{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="container mx-auto p-4 max-w-2xl"
|
||||
x-data="{ showPasswordModal: false, showDisable2FAModal: false, showRecoveryCodesModal: false, is2FAEnabled: false, recoveryCodesRemaining: null }"
|
||||
@update-2fa.window="is2FAEnabled = $event.detail"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Страница не найдена{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="flex flex-1 items-center justify-center p-4 min-h-[70vh]">
|
||||
<div class="w-full max-w-2xl">
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}LiB - Пользователи{% endblock %}
|
||||
{% block content %}
|
||||
{% extends "base.html" %}{% block content %}
|
||||
<div class="container mx-auto p-4">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h1 class="text-2xl font-bold text-gray-800">
|
||||
|
||||
Reference in New Issue
Block a user