Middelware update and footer content
All checks were successful
Build, Push, and Deploy to Nomad / docker-nomad (push) Successful in 39s

This commit is contained in:
2024-12-20 22:35:39 +01:00
parent 18181d7ce8
commit d58e5b0d12
10 changed files with 192 additions and 32 deletions

View File

@@ -3,6 +3,7 @@ import json
from fastapi import APIRouter, Request from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from fastapi.responses import JSONResponse
class CategoryController: class CategoryController:
@@ -22,6 +23,10 @@ class CategoryController:
methods=["GET"], methods=["GET"],
response_class=HTMLResponse, response_class=HTMLResponse,
) )
self.router.add_api_route(
"/categories", self.list_categories, methods = ["GET"], response_class = JSONResponse
)
def _load_data(self, data_file): def _load_data(self, data_file):
"""Load JSON data from a file.""" """Load JSON data from a file."""
with open(data_file, "r", encoding="utf-8") as file: with open(data_file, "r", encoding="utf-8") as file:
@@ -53,3 +58,11 @@ class CategoryController:
}, },
) )
return HTMLResponse("Kategori ikke fundet", status_code=404) return HTMLResponse("Kategori ikke fundet", status_code=404)
async def list_categories(self, request: Request):
"""Return a list of all categories with their name and path."""
categories = [
{ "name": category["name"], "path": category["path"] }
for category in self.data.get( "categories", [] )
]
return JSONResponse( content = categories )

View File

@@ -61,5 +61,4 @@ class DynamicController:
# Fallback: Return a 404 if no content is found # Fallback: Return a 404 if no content is found
return Response(f"No content found for {route_name}", status_code=404) return Response(f"No content found for {route_name}", status_code=404)
return route_handler return route_handler

View File

@@ -0,0 +1,89 @@
import json
import random
from fastapi import APIRouter, Request, FastAPI
from fastapi.templating import Jinja2Templates
from app.controllers.category_controller import CategoryController
class RouteToWeb:
def __init__(self, app: FastAPI):
"""Initialize the controller."""
self.router = APIRouter()
self.templates = Jinja2Templates(directory="templates")
self.app = app
self.category_controller = CategoryController()
self._add_routes()
self._add_global_middleware()
def _add_routes(self):
"""Add routes to the router."""
@self.router.get("/route-list", tags=["system"])
async def route_list(request: Request):
"""Render route list with categories."""
routes = [
{"path": route.path, "name": route.name or "Unnamed"}
for route in self.app.routes
]
categories = request.state.categories
return self.templates.TemplateResponse(
"route_list.html",
{"request": request, "routes": routes, "categories": categories, "page_title": "Route og Kategori Liste"},
)
def _add_global_middleware(self):
"""Middleware to add categories and next category globally to all requests."""
@self.app.middleware( "http" )
async def add_categories_to_request(request: Request, call_next):
def generate_dynamic_description(category_name: str) -> str:
"""Generate a dynamic and engaging link text for a category."""
templates = [
"Dyk ned i kategorien {category} og bliv inspireret!",
"Opdag alt, hvad du behøver at vide i kategorien {category}.",
"Udforsk {category}-kategorien og find noget nyt og spændende.",
"Lad dig fordybe i kategorien {category} der er meget at se!",
"Find din næste læseoplevelse i {category}-kategorien.",
"Gå på opdagelse i kategorien {category} og bliv klogere.",
"Der venter spændende indhold i {category}-kategorien klik her!",
"Vil du vide mere? Hele kategorien {category} er kun ét klik væk.",
"Læs videre i kategorien {category} og få ny inspiration.",
"Fordyb dig i {category}-kategorien og opdag nyt indhold.",
"Spring ind i {category}-kategorien og gå på opdagelse!",
"Find masser af viden og gode læseoplevelser i {category}-kategorien.",
"Udforsk hele kategorien {category} og bliv beriget med ny viden.",
"Der er mere at læse i {category}-kategorien gå ikke glip af det!",
"Tag et dybere kig i kategorien {category} og bliv inspireret!"
]
template = random.choice( templates )
return template.format( category = category_name.lower() )
"""Inject categories and next category into request.state globally."""
# Hent kategorier direkte fra CategoryController
categories_response = await self.category_controller.list_categories( request )
categories_data = categories_response.body.decode()
categories = json.loads( categories_data )
# Tilføj kategorier til request.state
request.state.categories = categories
# Find den aktuelle og næste kategori
current_path = request.url.path.split("/")[-1]
next_category = None
print(current_path)
for index, category in enumerate( categories ):
print(category)
if category["path"] == current_path:
# Find næste kategori (cirkulær, hvis det er den sidste)
next_index = (index + 1) % len( categories )
next_category = categories[next_index]
next_category["description"] = generate_dynamic_description( next_category["path"] )
break
# Tilføj næste kategori til request.state
request.state.next_category = next_category
response = await call_next( request )
return response

View File

@@ -1,6 +1,8 @@
from fastapi import FastAPI from fastapi import FastAPI
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from app.controllers.route_to_web import RouteToWeb
from app.services.markdown_processor import MarkdownProcessor from app.services.markdown_processor import MarkdownProcessor
from app.services.metadata_processor import MetadataProcessor from app.services.metadata_processor import MetadataProcessor
from app.controllers.dynamic_controller import DynamicController from app.controllers.dynamic_controller import DynamicController
@@ -38,11 +40,13 @@ class Application:
def _include_routers(self): def _include_routers(self):
"""Include all route controllers.""" """Include all route controllers."""
category_controller = CategoryController() category_controller = CategoryController()
dynamic_controller = DynamicController( "./data" ) #dynamic_controller = DynamicController( "./data" )
route_to_web = RouteToWeb(self.app)
self.app.include_router( category_controller.router ) self.app.include_router( category_controller.router )
self.app.include_router( dynamic_controller.router ) #self.app.include_router( dynamic_controller.router )
self.app.include_router(route_to_web.router)

View File

@@ -54,29 +54,29 @@
<li><strong>UCI El Corte Inglés</strong>: Den moderne biografoplevelse med de nyeste blockbusters. Sammenligneligt med Palads i København, men med en lidt mere luksuriøs oplevelse i selve komplekset.</li> <li><strong>UCI El Corte Inglés</strong>: Den moderne biografoplevelse med de nyeste blockbusters. Sammenligneligt med Palads i København, men med en lidt mere luksuriøs oplevelse i selve komplekset.</li>
</ul> </ul>
<p><div class="button-stack"> <p><div class="button-stack">
<button onclick="openModal('modal7F1670_0')" class="stacked-button"> <img src="https://lifecooler.com/files/registos/imagens/404151/158177.jpg" class="thumbnail"></button> <button onclick="openModal('modal6E3E27_0')" class="stacked-button"> <img src="https://lifecooler.com/files/registos/imagens/404151/158177.jpg" class="thumbnail"></button>
<div class="modal" id="modal7F1670_0"> <div class="modal-content"> <div class="modal" id="modal6E3E27_0"> <div class="modal-content">
<h2>Modal 0</h2> <h2>Modal 0</h2>
<img src="https://lifecooler.com/files/registos/imagens/404151/158177.jpg"> <img src="https://lifecooler.com/files/registos/imagens/404151/158177.jpg">
<div class="modal-buttons"> <div class="modal-buttons">
<button onclick="closeModal('modal7F1670_0')">Close</button> <button onclick="closeModal('modal6E3E27_0')">Close</button>
<button class="next-btn" onclick="nextModal('modal7F1670_0', 'modal7F1670_0_1')">Next</button> <button class="next-btn" onclick="nextModal('modal6E3E27_0', 'modal6E3E27_0_1')">Next</button>
</div> </div></div> </div> </div></div>
<button onclick="openModal('modal7F1670_0_1')" class="stacked-button"> <img src="https://lifecooler.com/files/registos/imagens/404151/158170.jpg" class="thumbnail" ></button> <button onclick="openModal('modal6E3E27_0_1')" class="stacked-button"> <img src="https://lifecooler.com/files/registos/imagens/404151/158170.jpg" class="thumbnail" ></button>
<div class="modal" id="modal7F1670_0_1"> <div class="modal-content"> <div class="modal" id="modal6E3E27_0_1"> <div class="modal-content">
<h2>Modal 1</h2> <h2>Modal 1</h2>
<img src="https://lifecooler.com/files/registos/imagens/404151/158170.jpg"> <img src="https://lifecooler.com/files/registos/imagens/404151/158170.jpg">
<div class="modal-buttons"> <div class="modal-buttons">
<button onclick="closeModal('modal7F1670_0_1')">Close</button> <button onclick="closeModal('modal6E3E27_0_1')">Close</button>
<button class="next-btn" onclick="nextModal('modal7F1670_0_1', 'modal7F1670_0_1_2')">Next</button> <button class="next-btn" onclick="nextModal('modal6E3E27_0_1', 'modal6E3E27_0_1_2')">Next</button>
</div> </div></div> </div> </div></div>
<button onclick="openModal('modal7F1670_0_1_2')" class="stacked-button"> <img src="https://upload.wikimedia.org/wikipedia/commons/8/88/Fachada_S%C3%A3oJorge.jpg" class="thumbnail"></button> <button onclick="openModal('modal6E3E27_0_1_2')" class="stacked-button"> <img src="https://upload.wikimedia.org/wikipedia/commons/8/88/Fachada_S%C3%A3oJorge.jpg" class="thumbnail"></button>
<div class="modal" id="modal7F1670_0_1_2"> <div class="modal-content"> <div class="modal" id="modal6E3E27_0_1_2"> <div class="modal-content">
<h2>Modal 2</h2> <h2>Modal 2</h2>
<img src="https://upload.wikimedia.org/wikipedia/commons/8/88/Fachada_S%C3%A3oJorge.jpg"> <img src="https://upload.wikimedia.org/wikipedia/commons/8/88/Fachada_S%C3%A3oJorge.jpg">
<div class="modal-buttons"> <div class="modal-buttons">
<button onclick="closeModal('modal7F1670_0_1_2')">Close</button> <button onclick="closeModal('modal6E3E27_0_1_2')">Close</button>
<button class="next-btn" onclick="nextModal('modal7F1670_0_1_2', 'modal7F1670_0_1_2_0')">Next</button> <button class="next-btn" onclick="nextModal('modal6E3E27_0_1_2', 'modal6E3E27_0_1_2_0')">Next</button>
</div> </div></div> </div> </div></div>
</div></p> </div></p>
<p>Biografbesøg i Lissabon er en afslappet måde at tilbringe tid med familien. Jeg nyder selv at tage afsted med Erika for at dele både film og hygge.</p> <p>Biografbesøg i Lissabon er en afslappet måde at tilbringe tid med familien. Jeg nyder selv at tage afsted med Erika for at dele både film og hygge.</p>
@@ -104,37 +104,37 @@
<p>Samtidig er mange oplevelser billigere end i København, og her er en atmosfære, der er svær at finde nordpå: Lissabon har en unik blanding af tradition og modernitet, som gør den til en by, der bliver ved med at fascinere.</p> <p>Samtidig er mange oplevelser billigere end i København, og her er en atmosfære, der er svær at finde nordpå: Lissabon har en unik blanding af tradition og modernitet, som gør den til en by, der bliver ved med at fascinere.</p>
<h3>Lidt billeder</h3> <h3>Lidt billeder</h3>
<p><div class="button-stack"> <p><div class="button-stack">
<button onclick="openModal('modalBA6A40_0')" class="stacked-button"> <img src="https://picsum.photos/id/34/500/375" class="thumbnail"></button> <button onclick="openModal('modal28D1BC_0')" class="stacked-button"> <img src="https://picsum.photos/id/34/500/375" class="thumbnail"></button>
<div class="modal" id="modalBA6A40_0"> <div class="modal-content"> <div class="modal" id="modal28D1BC_0"> <div class="modal-content">
<h2>Modal 0</h2> <h2>Modal 0</h2>
<img src="https://picsum.photos/id/34/500/375"> <img src="https://picsum.photos/id/34/500/375">
<div class="modal-buttons"> <div class="modal-buttons">
<button onclick="closeModal('modalBA6A40_0')">Close</button> <button onclick="closeModal('modal28D1BC_0')">Close</button>
<button class="next-btn" onclick="nextModal('modalBA6A40_0', 'modalBA6A40_0_1')">Next</button> <button class="next-btn" onclick="nextModal('modal28D1BC_0', 'modal28D1BC_0_1')">Next</button>
</div> </div></div> </div> </div></div>
<button onclick="openModal('modalBA6A40_0_1')" class="stacked-button"> <img src="https://picsum.photos/id/42/500/375" class="thumbnail" ></button> <button onclick="openModal('modal28D1BC_0_1')" class="stacked-button"> <img src="https://picsum.photos/id/42/500/375" class="thumbnail" ></button>
<div class="modal" id="modalBA6A40_0_1"> <div class="modal-content"> <div class="modal" id="modal28D1BC_0_1"> <div class="modal-content">
<h2>Modal 1</h2> <h2>Modal 1</h2>
<img src="https://picsum.photos/id/42/500/375"> <img src="https://picsum.photos/id/42/500/375">
<div class="modal-buttons"> <div class="modal-buttons">
<button onclick="closeModal('modalBA6A40_0_1')">Close</button> <button onclick="closeModal('modal28D1BC_0_1')">Close</button>
<button class="next-btn" onclick="nextModal('modalBA6A40_0_1', 'modalBA6A40_0_1_2')">Next</button> <button class="next-btn" onclick="nextModal('modal28D1BC_0_1', 'modal28D1BC_0_1_2')">Next</button>
</div> </div></div> </div> </div></div>
<button onclick="openModal('modalBA6A40_0_1_2')" class="stacked-button"> <img src="https://picsum.photos/id/72/500/375" class="thumbnail"></button> <button onclick="openModal('modal28D1BC_0_1_2')" class="stacked-button"> <img src="https://picsum.photos/id/72/500/375" class="thumbnail"></button>
<div class="modal" id="modalBA6A40_0_1_2"> <div class="modal-content"> <div class="modal" id="modal28D1BC_0_1_2"> <div class="modal-content">
<h2>Modal 2</h2> <h2>Modal 2</h2>
<img src="https://picsum.photos/id/72/500/375"> <img src="https://picsum.photos/id/72/500/375">
<div class="modal-buttons"> <div class="modal-buttons">
<button onclick="closeModal('modalBA6A40_0_1_2')">Close</button> <button onclick="closeModal('modal28D1BC_0_1_2')">Close</button>
<button class="next-btn" onclick="nextModal('modalBA6A40_0_1_2', 'modalBA6A40_0_1_2_3')">Next</button> <button class="next-btn" onclick="nextModal('modal28D1BC_0_1_2', 'modal28D1BC_0_1_2_3')">Next</button>
</div> </div></div> </div> </div></div>
<button onclick="openModal('modalBA6A40_0_1_2_3')" class="stacked-button"> <img src="https://picsum.photos/id/94/500/375" class="thumbnail" ></button> <button onclick="openModal('modal28D1BC_0_1_2_3')" class="stacked-button"> <img src="https://picsum.photos/id/94/500/375" class="thumbnail" ></button>
<div class="modal" id="modalBA6A40_0_1_2_3"> <div class="modal-content"> <div class="modal" id="modal28D1BC_0_1_2_3"> <div class="modal-content">
<h2>Modal 3</h2> <h2>Modal 3</h2>
<img src="https://picsum.photos/id/94/500/375"> <img src="https://picsum.photos/id/94/500/375">
<div class="modal-buttons"> <div class="modal-buttons">
<button onclick="closeModal('modalBA6A40_0_1_2_3')">Close</button> <button onclick="closeModal('modal28D1BC_0_1_2_3')">Close</button>
<button class="next-btn" onclick="nextModal('modalBA6A40_0_1_2_3', 'modalBA6A40_0_1_2_3_0')">Next</button> <button class="next-btn" onclick="nextModal('modal28D1BC_0_1_2_3', 'modal28D1BC_0_1_2_3_0')">Next</button>
</div> </div></div> </div> </div></div>
</div></p> </div></p>
</div> </div>

View File

@@ -3063,6 +3063,21 @@ button:disabled,
color: inherit; color: inherit;
} }
.footer-link {
font-size: 0.9rem; /* Reduceret skriftstørrelse */
font-weight: normal; /* Normal vægt, ikke fed */
text-decoration: none; /* Fjerner understregning */
display: inline-block; /* Bedre layoutjustering */
margin: 8px 0; /* Lidt luft omkring linket */
text-align: center; /* Centreret, hvis relevant */
transition: color 0.3s ease; /* Glidende farveskift ved hover */
}
.footer-link:hover {
color: #000; /* Mørkere farve ved hover */
text-decoration: none; /* Understregning ved hover */
transition: color 0.5s ease; /* Glidende farveskift ved hover */
}
/* Menu */ /* Menu */
#menu ul { #menu ul {
-moz-user-select: none; -moz-user-select: none;

File diff suppressed because one or more lines are too long

View File

@@ -15,4 +15,21 @@
color: inherit; color: inherit;
} }
} }
}
.footer-link {
font-size: 0.9rem; /* Reduceret skriftstørrelse */
font-weight: normal; /* Normal vægt, ikke fed */
text-decoration: none; /* Fjerner understregning */
display: inline-block; /* Bedre layoutjustering */
margin: 8px 0; /* Lidt luft omkring linket */
text-align: center; /* Centreret, hvis relevant */
transition: color 0.3s ease; /* Glidende farveskift ved hover */
&:hover {
color: #000; /* Mørkere farve ved hover */
text-decoration: none; /* Understregning ved hover */
transition: color 0.5s ease; /* Glidende farveskift ved hover */
}
} }

View File

@@ -21,6 +21,18 @@
<!-- Content --> <!-- Content -->
{% block content %}{% endblock %} {% block content %}{% endblock %}
<footer>
{% if request.state.next_category %}
<p>
<a href="/category/{{ request.state.next_category.path }}" class="footer-link">
{{ request.state.next_category.description }}
</a>
</p>
{% else %}
<p>Ingen næste kategori.</p>
{% endif %}
</footer>
</div> </div>
</div> </div>

11
templates/route_list.html Normal file
View File

@@ -0,0 +1,11 @@
<h3>Næste Kategori</h3>
{% if request.state.next_category %}
<p>
<a href="/category/{{ request.state.next_category.path }}">
{{ request.state.next_category.name }}
</a>
</p>
{% else %}
<p>Ingen næste kategori.</p>
{% endif %}