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