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.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from fastapi.responses import JSONResponse
class CategoryController:
@@ -22,6 +23,10 @@ class CategoryController:
methods=["GET"],
response_class=HTMLResponse,
)
self.router.add_api_route(
"/categories", self.list_categories, methods = ["GET"], response_class = JSONResponse
)
def _load_data(self, data_file):
"""Load JSON data from a 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)
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
return Response(f"No content found for {route_name}", status_code=404)
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 contextlib import asynccontextmanager
from fastapi.staticfiles import StaticFiles
from app.controllers.route_to_web import RouteToWeb
from app.services.markdown_processor import MarkdownProcessor
from app.services.metadata_processor import MetadataProcessor
from app.controllers.dynamic_controller import DynamicController
@@ -38,11 +40,13 @@ class Application:
def _include_routers(self):
"""Include all route controllers."""
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( 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>
</ul>
<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>
<div class="modal" id="modal7F1670_0"> <div class="modal-content">
<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="modal6E3E27_0"> <div class="modal-content">
<h2>Modal 0</h2>
<img src="https://lifecooler.com/files/registos/imagens/404151/158177.jpg">
<div class="modal-buttons">
<button onclick="closeModal('modal7F1670_0')">Close</button>
<button class="next-btn" onclick="nextModal('modal7F1670_0', 'modal7F1670_0_1')">Next</button>
<button onclick="closeModal('modal6E3E27_0')">Close</button>
<button class="next-btn" onclick="nextModal('modal6E3E27_0', 'modal6E3E27_0_1')">Next</button>
</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>
<div class="modal" id="modal7F1670_0_1"> <div class="modal-content">
<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="modal6E3E27_0_1"> <div class="modal-content">
<h2>Modal 1</h2>
<img src="https://lifecooler.com/files/registos/imagens/404151/158170.jpg">
<div class="modal-buttons">
<button onclick="closeModal('modal7F1670_0_1')">Close</button>
<button class="next-btn" onclick="nextModal('modal7F1670_0_1', 'modal7F1670_0_1_2')">Next</button>
<button onclick="closeModal('modal6E3E27_0_1')">Close</button>
<button class="next-btn" onclick="nextModal('modal6E3E27_0_1', 'modal6E3E27_0_1_2')">Next</button>
</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>
<div class="modal" id="modal7F1670_0_1_2"> <div class="modal-content">
<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="modal6E3E27_0_1_2"> <div class="modal-content">
<h2>Modal 2</h2>
<img src="https://upload.wikimedia.org/wikipedia/commons/8/88/Fachada_S%C3%A3oJorge.jpg">
<div class="modal-buttons">
<button onclick="closeModal('modal7F1670_0_1_2')">Close</button>
<button class="next-btn" onclick="nextModal('modal7F1670_0_1_2', 'modal7F1670_0_1_2_0')">Next</button>
<button onclick="closeModal('modal6E3E27_0_1_2')">Close</button>
<button class="next-btn" onclick="nextModal('modal6E3E27_0_1_2', 'modal6E3E27_0_1_2_0')">Next</button>
</div> </div></div>
</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>
@@ -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>
<h3>Lidt billeder</h3>
<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>
<div class="modal" id="modalBA6A40_0"> <div class="modal-content">
<button onclick="openModal('modal28D1BC_0')" class="stacked-button"> <img src="https://picsum.photos/id/34/500/375" class="thumbnail"></button>
<div class="modal" id="modal28D1BC_0"> <div class="modal-content">
<h2>Modal 0</h2>
<img src="https://picsum.photos/id/34/500/375">
<div class="modal-buttons">
<button onclick="closeModal('modalBA6A40_0')">Close</button>
<button class="next-btn" onclick="nextModal('modalBA6A40_0', 'modalBA6A40_0_1')">Next</button>
<button onclick="closeModal('modal28D1BC_0')">Close</button>
<button class="next-btn" onclick="nextModal('modal28D1BC_0', 'modal28D1BC_0_1')">Next</button>
</div> </div></div>
<button onclick="openModal('modalBA6A40_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">
<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="modal28D1BC_0_1"> <div class="modal-content">
<h2>Modal 1</h2>
<img src="https://picsum.photos/id/42/500/375">
<div class="modal-buttons">
<button onclick="closeModal('modalBA6A40_0_1')">Close</button>
<button class="next-btn" onclick="nextModal('modalBA6A40_0_1', 'modalBA6A40_0_1_2')">Next</button>
<button onclick="closeModal('modal28D1BC_0_1')">Close</button>
<button class="next-btn" onclick="nextModal('modal28D1BC_0_1', 'modal28D1BC_0_1_2')">Next</button>
</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>
<div class="modal" id="modalBA6A40_0_1_2"> <div class="modal-content">
<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="modal28D1BC_0_1_2"> <div class="modal-content">
<h2>Modal 2</h2>
<img src="https://picsum.photos/id/72/500/375">
<div class="modal-buttons">
<button onclick="closeModal('modalBA6A40_0_1_2')">Close</button>
<button class="next-btn" onclick="nextModal('modalBA6A40_0_1_2', 'modalBA6A40_0_1_2_3')">Next</button>
<button onclick="closeModal('modal28D1BC_0_1_2')">Close</button>
<button class="next-btn" onclick="nextModal('modal28D1BC_0_1_2', 'modal28D1BC_0_1_2_3')">Next</button>
</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>
<div class="modal" id="modalBA6A40_0_1_2_3"> <div class="modal-content">
<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="modal28D1BC_0_1_2_3"> <div class="modal-content">
<h2>Modal 3</h2>
<img src="https://picsum.photos/id/94/500/375">
<div class="modal-buttons">
<button onclick="closeModal('modalBA6A40_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 onclick="closeModal('modal28D1BC_0_1_2_3')">Close</button>
<button class="next-btn" onclick="nextModal('modal28D1BC_0_1_2_3', 'modal28D1BC_0_1_2_3_0')">Next</button>
</div> </div></div>
</div></p>
</div>

View File

@@ -3063,6 +3063,21 @@ button:disabled,
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 ul {
-moz-user-select: none;

File diff suppressed because one or more lines are too long

View File

@@ -16,3 +16,20 @@
}
}
}
.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 -->
{% 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>

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 %}