diff --git a/app/main.py b/app/main.py index 7061c0b..3d58cd3 100644 --- a/app/main.py +++ b/app/main.py @@ -7,29 +7,30 @@ from app.services.markdown_processor import MarkdownProcessor from app.services.metadata_processor import MetadataProcessor from app.controllers.category_controller import CategoryController from fastapi.middleware.gzip import GZipMiddleware -from app.services.image_controller import ImageHandler +from app.services.image_service import ImageService class Application: def __init__(self): """Initialize the FastAPI app and configure it.""" self.app = FastAPI(lifespan=self._lifespan_event) + self._set_image_sizes() self._setup_static_files() self._include_routers() self._include_middelware() + + @asynccontextmanager async def _lifespan_event(self, app: FastAPI): """Lifespan event for startup and shutdown logic.""" print("App startup: Processing Markdown files...") # Generate dynamic JSON data - metadata_processor = MetadataProcessor(input_dir="./data", output_file="generated_data.json") + metadata_processor = MetadataProcessor(input_dir="./data", output_file="generated_data.json",app=self.app) metadata_processor.generate_json() print("Generated dynamic data file.") - print("Markdown processing complete!") - # Process Markdown files into HTML - processor = MarkdownProcessor(input_dir="./data", templates_dir="./templates") + processor = MarkdownProcessor(input_dir="./data", templates_dir="./templates",app=self.app) processor.run() yield print("App shutdown: Cleanup complete.") @@ -38,24 +39,30 @@ class Application: """Mount static file directories.""" self.app.mount("/data", StaticFiles(directory="data"), name="data") self.app.mount("/static", StaticFiles(directory="static"), name="static") + self.app.mount( "/images", StaticFiles( directory = "static/images" ), name = "images" ) def _include_routers(self): """Include all route controllers.""" category_controller = CategoryController() - #dynamic_controller = DynamicController( "./data" ) + image_service = ImageService(self.app) route_to_web = RouteToWeb(self.app) - - self.app.include_router( category_controller.router ) - #self.app.include_router( dynamic_controller.router ) self.app.include_router(route_to_web.router) - + self.app.include_router( image_service.router ) def _include_middelware(self): self.app.add_middleware( GZipMiddleware, minimum_size = 500 ) + def _set_image_sizes(self): + self.app.state.IMAGE_SIZES = { + 'thumbnails': {'width': 100, 'height': 100}, + 'large': {'width': 800, 'height': 600}, + 'small': {'width': 300, 'height': 200}, + 'original': {'width': None, 'height': None}, # Original størrelse + } + def get_app(self): """Return the FastAPI app instance.""" return self.app diff --git a/app/services/image_controller.py b/app/services/image_controller.py deleted file mode 100644 index 8b4e550..0000000 --- a/app/services/image_controller.py +++ /dev/null @@ -1,72 +0,0 @@ -import os -from PIL import Image - -class ImageHandler: - def __init__(self, base_dir: str): - """ - Initialize the ImageHandler. - - :param base_dir: Base directory for storing and retrieving images. - """ - self.base_dir = base_dir - - def get_image_path(self, filename: str) -> str: - """ - Construct the full path for a given image file. - - :param filename: Relative filename of the image. - :return: Full path to the image. - """ - return os.path.join(self.base_dir, filename) - - def get_resized_image_path(self, filename: str, width: int, height: int) -> str: - """ - Construct the path for a resized image. - - :param filename: Original image filename. - :param width: Desired width. - :param height: Desired height. - :return: Path to the resized image. - """ - return os.path.join(self.base_dir, f"resized_{width}x{height}_{filename}") - - def resize_and_save(self, original_path: str, resized_path: str, width: int, height: int): - """ - Resize and save the image if it doesn't already exist. - - :param original_path: Path to the original image file. - :param resized_path: Path to save the resized image. - :param width: Desired width. - :param height: Desired height. - """ - if not os.path.exists(resized_path): - with Image.open(original_path) as img: - img_resized = img.resize((width, height)) - img_resized.save(resized_path, format="JPEG") - - def generate_image_tag(self, src: str, width: int, height: int, css_class: str = "", alt: str = "") -> str: - """ - Generate an HTML tag and ensure the image exists with the specified dimensions. - - :param src: Relative path to the original image. - :param width: Desired width of the image. - :param height: Desired height of the image. - :param css_class: Optional CSS class to add to the tag. - :param alt: Alternative text for the image. - :return: HTML tag. - """ - original_path = self.get_image_path(src) - if not os.path.isfile(original_path): - raise FileNotFoundError(f"Image not found: {src}") - - # Construct resized image path - resized_filename = f"resized_{width}x{height}_{os.path.basename(src)}" - resized_path = self.get_resized_image_path(src, width, height) - - # Resize and save the image if necessary - self.resize_and_save(original_path, resized_path, width, height) - - # Return the tag - class_attr = f' class="{css_class}"' if css_class else "" - alt_attr = f' alt="{alt}"' if alt else "" - return f'' diff --git a/app/services/image_service.py b/app/services/image_service.py new file mode 100644 index 0000000..ebf07f4 --- /dev/null +++ b/app/services/image_service.py @@ -0,0 +1,156 @@ +import os +from fastapi import HTTPException +from fastapi.responses import FileResponse +from fastapi import APIRouter, Request, FastAPI +from PIL import Image + + +class FileHandler: + + def __init__(self, category, image_type, filename): + self.filename = filename + self.category = category + self.image_type = image_type + + @property + def src_file(self) -> str: + src_path = "data/{category}/images/{filename}" + return src_path.format( category = self.category, filename = self.filename ) + + @property + def dest_file(self) -> str: + base_url = "/images/{category}/{filename}" + return base_url.format( category = self.category, filename = self.filename ) + + @property + def dest_filename(self) -> str: + base_url = "static/images/{category}/{image_type}/{filename}" + return base_url.format( category = self.category, image_type = self.image_type, filename = self.filename ) + + @property + def dest_path(self) -> str: + base_url = "static/images/{category}/{image_type}" + return base_url.format( category = self.category, image_type = self.image_type ) + + def __str__(self): + return ( + f"FileHandler(\n" + f" filename='{self.filename}',\n" + f" category='{self.category}',\n" + f" image_type='{self.image_type}',\n" + f" src_file='{self.src_file}',\n" + f" dest_file='{self.dest_file}',\n" + f" dest_filename='{self.dest_filename}'\n" + f")" + ) + + + +class ImageService: + + def __init__(self,app: FastAPI): + self.router = APIRouter() + self.app = app + self.IMAGE_SIZES = self.app.state.IMAGE_SIZES + #self._ensure_directories_exist() + self._add_routes() + + + + + def __str__(self): + """ + Provides a string representation of the class instance. + """ + base_paths_str = "\n".join( + [f"{key}: {value}" for key, value in self.base_paths.items()] + ) + image_sizes_str = "\n".join( + [ + f"{key}: width={value['width']}, height={value['height']}" + for key, value in self.image_sizes.items() + ] + ) + return f" dict: + """ + Retrieve the width and height for a given image type from the app state. + + Args: + request (Request): FastAPI request object. + image_type (str): The type of the image (e.g., 'thumbnails'). + + Returns: + dict: A dictionary with 'width' and 'height'. + """ + + image_sizes = self.app.state.IMAGE_SIZES + if image_type not in image_sizes: + raise ValueError( f"Invalid image type: {image_type}. Must be one of {list( image_sizes.keys() )}" ) + + return image_sizes[image_type] + + def _add_routes(self): + self.router.add_api_route( + "/image/{category}/{type}/{filename}", + self.get_image, + methods=["GET"], + response_class=FileResponse, + ) + + async def get_image(self, category: str, type: str, filename: str): + """ + Retrieve an image file from the specified category and type. + """ + file_path = self._resolve_path(category, type, filename) + return FileResponse(file_path) + + def validate_image(self, file_path:FileHandler=None, width:int=None, height:int=None, overwrite = True ) -> bool: + if not os.path.exists( file_path.dest_filename ): + with Image.open( file_path.src_file ) as img: + print(file_path.src_file) + self._resize_image( img, file_path, width, height ) + return True + + with Image.open( file_path.dest_filename ) as img: + if img.width != width or img.height != height: + if overwrite: + self._resize_image( img, file_path, width, height ) + return False + return True + + def _resize_image(self, img: Image.Image, file_path: FileHandler, width: int, height: int): + resized_img = img.resize( (width, height), Image.Resampling.LANCZOS ) + os.makedirs(file_path.dest_path,exist_ok = True) + resized_img.save( file_path.dest_filename ) + + + async def get_image(self, category: str, type: str, filename: str): + file_path = self._resolve_path( category, type, filename ) + return FileResponse( file_path ) + + def image_tag(self, category: str, image_type: str, filename: str, alt: str = "", width: int = None, + height: int = None) -> str: + """ + Generate an HTML tag with default sizes if dimensions are not provided. + """ + # Use default sizes if none are provided + default_size = self.get_image_size( image_type) + width = width or default_size.get( "width" ) + height = height or default_size.get( "height" ) + + + + #file_path = self._resolve_path( category, image_type, filename ) + file_path = FileHandler(category = category,image_type = image_type,filename = filename) + self.validate_image( file_path, width = width,height=height, overwrite = True ) + + tag = f'{alt} list: """ @@ -33,15 +34,21 @@ class MarkdownProcessor: Returns: list: A list of processed sections containing metadata and rendered content. """ + from pathlib import Path + sections = [] + + + for file in sorted(os.listdir(directory_path)): if file.endswith(".md"): file_path = os.path.join(directory_path, file) with open(file_path, "r", encoding="utf-8") as md_file: markdown_content = md_file.read() - + markdown_render = MarkdownRenderer(file_path=file_path,app=self.app) # Process Markdown and Jinja2 - rendered_content, metadata = render_markdown_with_jinja(markdown_content) + + rendered_content, metadata = markdown_render.render_markdown_with_jinja ( markdown_content ) # Append the section to the list sections.append({ diff --git a/app/services/markdown_render.py b/app/services/markdown_render.py index 495364a..8c6d491 100644 --- a/app/services/markdown_render.py +++ b/app/services/markdown_render.py @@ -1,123 +1,168 @@ +from pathlib import Path +import sys import markdown +from fastapi import FastAPI from jinja2 import Environment, DictLoader -from .image_controller import ImageHandler -# Define Jinja2 custom functions -def img_left_overlay(src): - """Render an image with overlay.""" - return f''' -
- Overlay Image -
Overlay Text
-
- ''' +from markupsafe import Markup +from .image_service import ImageService -def box(title, content): - """Render a box component.""" - return f''' -
- {title} -

{content}

-
- ''' - -def note(content): - """Render a note component.""" - return f''' -
-

{content}

-
- ''' -def link_to(title, url): - """Render a box component.""" - return f''' - {title} - ''' - -def warning(content): - """Render a warning component.""" - return f''' -
- ⚠️

{content}

-
- ''' +class MarkdownRenderer: + def __init__(self, file_path: str = None, app: FastAPI=None): + """ + Initialize the MarkdownRenderer with a Jinja2 environment and custom functions. + """ + self.app = app + self.image_service = ImageService(self.app) + self.jinja_env = self._create_jinja_environment() + self.file_path = file_path -def slider(options, images): - """Render a slider using the provided HTML structure.""" - import uuid - modal_id = uuid.uuid4().hex.upper()[0:6] # Lets create some uniq modals - width = options.get("width", 500) - height = options.get("height", 375) + def _create_jinja_environment(self) -> Environment: + """ + Create and configure the Jinja2 environment with custom functions. - html_content = [] - html_content.append('
') - for i, val in enumerate(images): - modal_id = f"{modal_id}_{i}" - modal_id_next = f"{modal_id}_{i+1}" - - if int(len(images))<=int(i+1): - modal_id_next = f"{modal_id}_0" - if i % 2 == 0: - html_content.append(f"""""".strip()) - else: - html_content.append(f"""""".strip()) - html_content.append(f"""""") + Returns: + Environment: A configured Jinja2 environment. + """ + env = Environment(loader=DictLoader({"base_template": "{{ content | safe }}"})) - html_content.append( '
' ) - html = '\n'.join( html_content ) + env.globals.update({ + "img_left_overlay": self.img_left_overlay, + "box": self.box, + "note": self.note, + "warning": self.warning, + "link_to": self.link_to, + "slider": self.slider, + "image": self.get_image, # Add image handler function + }) + return env - return html + def img_left_overlay(self, src: str) -> str: + """Render an image with overlay.""" + return f''' +
+ Overlay Image +
Overlay Text
+
+ ''' + + def box(self, title: str, content: str) -> str: + """Render a box component.""" + return f''' +
+ {title} +

{content}

+
+ ''' + + def note(self, content: str) -> str: + """Render a note component.""" + return f''' +
+

{content}

+
+ ''' + + def link_to(self, title: str, url: str) -> str: + """Render a link component.""" + return f''' + {title} + ''' + + def warning(self, content: str) -> str: + """Render a warning component.""" + return f''' +
+ ⚠️

{content}

+
+ ''' + + def slider(self, options: dict, images: list) -> str: + """Render a slider component.""" + import uuid + modal_id = uuid.uuid4().hex.upper()[0:6] -def create_jinja_environment(): - """Create and configure the Jinja2 environment.""" - env = Environment(loader=DictLoader({"base_template": "{{ content | safe }}"})) - image_handler = ImageHandler(base_dir="static/images") + html_content = [] + html_content.append('
') + for i, val in enumerate(images): + self.image_service = ImageService( self.app ) + print(val) + modal_id_current = f"{modal_id}_{i}" + modal_id_next = f"{modal_id}_{i + 1}" if i + 1 < len(images) else f"{modal_id}_0" - env.globals.update({ - "img_left_overlay": img_left_overlay, - "box": box, - "note": note, - "warning": warning, - "link_to": link_to, - "slider": slider, - "image": image_handler.generate_image_tag, # Add image handler function + html_content.append(f""" + + + """) + html_content.append('
') + return '\n'.join(html_content) - }) - return env + def _get_category(self): + if isinstance(self.file_path, str): + this_path = Path(self.file_path) + return this_path.parent.name -def render_markdown_with_jinja(markdown_content: str): - """ - Convert Markdown to HTML and apply Jinja2 rendering for custom tags. + return True - Args: - markdown_content (str): Raw Markdown content. - Returns: - tuple: Rendered HTML content and metadata as a dictionary. - """ - # Step 1: Convert Markdown to HTML and extract metadata - md = markdown.Markdown(extensions=["extra", "nl2br", "meta"]) - intermediate_html = md.convert(markdown_content) - metadata = {key: " ".join(value) for key, value in md.Meta.items()} if md.Meta else {} + def get_image(self, image_type: str, filename: str, alt: str = "", width: int = None, height: int = None) -> Markup: + """ + Generate a dynamic HTML tag for an image using ImageService's image_tag method. + """ + valid_types = ['thumbnails', 'large', 'small', 'original'] + if image_type not in valid_types: + sys.tracebacklimit = 0 + raise ValueError( f"Invalid image type: {image_type}. Must be one of {valid_types}" ) - # Step 2: Pass the resulting HTML with Jinja2 custom tags through Jinja2 - env = create_jinja_environment() + tag = self.image_service.image_tag( + category=self._get_category(), + image_type=image_type, + filename=filename, + alt=alt, + width=width, + height=height + ) + my_tag = Markup(tag) + print(my_tag) + return my_tag - template = env.get_template("base_template") - final_html = template.render(content=intermediate_html) - # Step 3: Re-render final_html in Jinja2 for embedded tags like {{ image(...) }} - final_output = env.from_string(final_html).render() - return final_output, metadata + + def render_markdown_with_jinja(self, markdown_content: str): + """ + Convert Markdown to HTML and apply Jinja2 rendering for custom tags. + + Args: + markdown_content (str): Raw Markdown content. + + Returns: + tuple: Rendered HTML content and metadata as a dictionary. + """ + + md = markdown.Markdown(extensions=["extra", "nl2br", "meta"]) + intermediate_html = md.convert(markdown_content) + metadata = {key: " ".join(value) for key, value in md.Meta.items()} if md.Meta else {} + + # Step 3: Pass the resulting HTML with Jinja2 custom tags through Jinja2 + template = self.jinja_env.get_template("base_template") + final_html = template.render(content=intermediate_html) + + # Step 4: Re-render final_html in Jinja2 for embedded tags like {{ image(...) }} + final_output = self.jinja_env.from_string(final_html).render() + + return final_output, metadata \ No newline at end of file diff --git a/app/services/metadata_processor.py b/app/services/metadata_processor.py index cfe923b..de8a0e0 100644 --- a/app/services/metadata_processor.py +++ b/app/services/metadata_processor.py @@ -3,6 +3,8 @@ import markdown import json from typing import List, Dict +from fastapi import FastAPI + class MetadataProcessor: """ @@ -10,7 +12,7 @@ class MetadataProcessor: and generate a structured JSON file. """ - def __init__(self, input_dir: str, output_file: str): + def __init__(self, input_dir: str, output_file: str,app:FastAPI=None): """ Initialize the MetadataProcessor. diff --git a/data.old/bolig/index.html b/data.old/bolig/index.html deleted file mode 100644 index 6298baa..0000000 --- a/data.old/bolig/index.html +++ /dev/null @@ -1,26 +0,0 @@ -
- -
-
-
-

Opsumering: Lidt omkring job situationen og hvordan det fungere

-
-
-

Dato:

-
-
-

Untitled

-
-

Bolig Bolig Bolig Bolig - Hvor skal sengen placeres

-

Nu bliver det spænde!

-

-

-

Dette er stadig en test side

-
-

-

{img-left-overlay: images/my-cat.png}

-
-
-
- -
diff --git a/data.old/bolig/lidt_omkring_boliger.md b/data.old/bolig/lidt_omkring_boliger.md deleted file mode 100644 index f7e66c8..0000000 --- a/data.old/bolig/lidt_omkring_boliger.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -name: Generalt -description: Hvem, hvad og hvor -author: Henrik Jess -date: ons 11 dec 22:16:13 CET 2024 -summary: Lidt omkring job situationen og hvordan det fungere -favorite: true -image: images/pic07.jpg ---- - -# Bolig Bolig Bolig Bolig - Hvor skal sengen placeres - -Nu bliver det spænde! - -{{ note("Dette er stadig en test side") }} - -{img-left-overlay: images/my-cat.png} diff --git a/data.old/job/det_ved_jeg_om_job.md b/data.old/job/det_ved_jeg_om_job.md deleted file mode 100644 index 5a09157..0000000 --- a/data.old/job/det_ved_jeg_om_job.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Job -description: Hvem, hvad og hvor -author: Henrik Jess -date: ons 11 dec 22:16:13 CET 2024 -summary: Lidt omkring job situationen og hvordan det fungere -favorite: true -image: images/pic04.jpg ---- - -# Lidt mere info om job - -Der skal langt mere tekst her - - - - - -{{ note("Husk alpha side") }} \ No newline at end of file diff --git a/data.old/job/index.html b/data.old/job/index.html deleted file mode 100644 index 9e7fd3c..0000000 --- a/data.old/job/index.html +++ /dev/null @@ -1,57 +0,0 @@ -
- -
-
-
-

Opsumering: Lidt omkring job situationen og hvordan det fungere

-
-
-

Dato:

-
-
-

Untitled

-
-

Lidt mere info om job

-

Der skal langt mere tekst her

-

-

-

Husk alpha side

-
-

-
-
-
- -
-
-
-

Opsumering: Lidt omkring job situationen og hvordan det fungere

-
-
-

Dato:

-
-
-

Untitled

-
-

Overskrift 1

-

Overskrift 2

-

Overskrift 3

-

Overskrift4

-

Here is a custom box:

-

-

- Important Title -

This is the content inside the box.

-
-

-

Here is a note:

-

-

-

This is a note for the readers.

-
-

-
-
-
- -
diff --git a/data.old/job/job1.md b/data.old/job/job1.md deleted file mode 100644 index 4a35e4d..0000000 --- a/data.old/job/job1.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: Job Job Job Job Job -description: Hvem, hvad og hvor -author: Henrik Jess -date: ons 11 dec 22:16:13 CET 2024 -summary: Lidt omkring job situationen og hvordan det fungere -favorite: true -image: images/pic04.jpg ---- - - -# Overskrift 1 -## Overskrift 2 -### Overskrift 3 -#### Overskrift4 -Here is a custom box: - -{{ box("Important Title", "This is the content inside the box.") }} - -Here is a note: - -{{ note("This is a note for the readers.") }} diff --git a/data.old/kontor/index.html b/data.old/kontor/index.html deleted file mode 100644 index 555e8e8..0000000 --- a/data.old/kontor/index.html +++ /dev/null @@ -1,25 +0,0 @@ -
- -
-
-
-

Opsumering: Lad os snakke kontor fælleskaber

-
-
-

Dato:

-
-
-

Untitled

-
-

Kontorfællesskab!

-

Der skal langt mere tekst her

-

-

-

Husk alpha side

-
-

-
-
-
- -
diff --git a/data.old/kontor/lidt_om_kontore.md b/data.old/kontor/lidt_om_kontore.md deleted file mode 100644 index 7b9695e..0000000 --- a/data.old/kontor/lidt_om_kontore.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: Kontor -description: Kontorfælleskaber osv -author: Henrik Jess -date: today -summary: Lad os snakke kontor fælleskaber -favorite: false -image: images/pic05.jpg ---- - -# Kontorfællesskab! - -Der skal langt mere tekst her - - -{{ note("Husk alpha side") }} \ No newline at end of file diff --git a/data.old/skat/index.html b/data.old/skat/index.html deleted file mode 100644 index 0db8b94..0000000 --- a/data.old/skat/index.html +++ /dev/null @@ -1,20 +0,0 @@ -
- -
-
-
-

Opsumering: Jeg er langt fra expert, men her er lidt hvad jeg har indsamlet omkring skat

-
-
-

Dato:

-
-
-

Untitled

-
-

Skat! - Det skal jo også være sjovt og leve

-

dette er mere tekst omkring skat

-
-
-
- -
diff --git a/data.old/skat/portugal_vs_dansk_skat.md b/data.old/skat/portugal_vs_dansk_skat.md deleted file mode 100644 index a6db716..0000000 --- a/data.old/skat/portugal_vs_dansk_skat.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: Skat -description: SKAT,SKAT, SKAT - Det skal betales den slags -author: Henrik Jess -date: today -summary: Jeg er langt fra expert, men her er lidt hvad jeg har indsamlet omkring skat -favorite: false -image: images/pic07.jpg ---- - -# Skat! - Det skal jo også være sjovt og leve - -dette er mere tekst omkring skat \ No newline at end of file diff --git a/data.old/skole/index.html b/data.old/skole/index.html deleted file mode 100644 index c5aa2c0..0000000 --- a/data.old/skole/index.html +++ /dev/null @@ -1,22 +0,0 @@ -
- -
-
-
-

Opsumering: Nørj det er lidt spændende..

-
-
-

Dato:

-
-
-

Untitled

-
-

Skole start!

-

dette er mere tekst omkring skole

-

Skole efter lidt tid

-

HA!

-
-
-
- -
diff --git a/data.old/skole/skole.md b/data.old/skole/skole.md deleted file mode 100644 index b56fb23..0000000 --- a/data.old/skole/skole.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -name: Skole -description: Skole, ny kultur og menesker -author: Erika Nielsen -date: today -summary: Nørj det er lidt spændende.. -favorite: false -image: images/pic07.jpg ---- - -# Skole start! - -dette er mere tekst omkring skole - -# Skole efter lidt tid - -HA! diff --git a/data/Kultur/0200_kultur_unikt.md b/data/Kultur/0200_kultur_unikt.md index 4a3d521..f19ce24 100644 --- a/data/Kultur/0200_kultur_unikt.md +++ b/data/Kultur/0200_kultur_unikt.md @@ -69,7 +69,6 @@ Lissabon føles på mange måder som København – med fokus på kultur, kvalit 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. -{{ image("pic11.jpg", 200, 150, "thumbnail", "Example Image") }} ### Lidt billeder diff --git a/data/_frontpage/frontpage.md b/data/_frontpage/frontpage.md index b23acef..00b38b8 100644 --- a/data/_frontpage/frontpage.md +++ b/data/_frontpage/frontpage.md @@ -1,7 +1,8 @@ # Min Drøm om Portugal ## En Frisk Start for Henrik og Erika -{{ image("pic09.jpg", 475, 100, "", "Example Image") }} + +{{ image('thumbnails', 'pic11.jpg', alt='Mit fantatiske billed') }} --- @@ -14,3 +15,4 @@ For Erika er det også en chance for at opleve en ny kultur, møde nye mennesker Denne hjemmeside er en samling af mine tanker, forberedelser og erfaringer på vejen mod at gøre drømmen til virkelighed. Måske overvejer du selv en lignende rejse, eller måske er du bare nysgerrig på, hvordan det er at tage springet. Her deler jeg min rejse – fra de første spæde idéer til de praktiske skridt mod et nyt liv i Portugal. For mig og for Erika. --- + diff --git a/depricated/convert_markdown_to_html.py b/depricated/convert_markdown_to_html.py deleted file mode 100644 index f05ea83..0000000 --- a/depricated/convert_markdown_to_html.py +++ /dev/null @@ -1,43 +0,0 @@ -import os -from app.services.markdown_render import render_markdown_with_jinja - -def process_markdown_files(input_dir: str, output_dir: str): - """ - Recursively process all Markdown files in the input directory, - render them to HTML, and save them to the output directory. - """ - for root, _, files in os.walk(input_dir): - for file in files: - if file.endswith(".md"): - input_file_path = os.path.join(root, file) - - # Determine output file path (convert .md to .html) - relative_path = os.path.relpath(input_file_path, input_dir) - output_file_path = os.path.join(output_dir, os.path.splitext(relative_path)[0] + ".html") - - # Ensure the output directory exists - os.makedirs(os.path.dirname(output_file_path), exist_ok=True) - - # Read Markdown content - with open(input_file_path, "r", encoding="utf-8") as md_file: - markdown_content = md_file.read() - - # Render Markdown with Jinja2 - print(f"Processing: {input_file_path} -> {output_file_path}") - rendered_html = render_markdown_with_jinja(markdown_content) - - # Write the rendered HTML to the output file - with open(output_file_path, "w", encoding="utf-8") as html_file: - html_file.write(rendered_html) - - print("Markdown processing complete!") - -if __name__ == "__main__": - # Input directory containing Markdown files - input_directory = "./data" - - # Output directory where HTML files will be stored - output_directory = "./data" - - # Start the processing - process_markdown_files(input_directory, output_directory) diff --git a/depricated/markdown_service.py b/depricated/markdown_service.py deleted file mode 100644 index b2f4fc9..0000000 --- a/depricated/markdown_service.py +++ /dev/null @@ -1,25 +0,0 @@ -import os -from app.services.markdown_render import render_markdown_with_jinja - -def process_markdown_files(input_dir: str, output_dir: str): - """ - Recursively process all Markdown files in the input directory, - render them to HTML, and save them in the output directory. - """ - for root, _, files in os.walk(input_dir): - for file in files: - if file.endswith(".md"): - input_file_path = os.path.join(root, file) - relative_path = os.path.relpath(input_file_path, input_dir) - output_file_path = os.path.join(output_dir, os.path.splitext(relative_path)[0] + ".html") - - os.makedirs(os.path.dirname(output_file_path), exist_ok=True) - - with open(input_file_path, "r", encoding="utf-8") as md_file: - markdown_content = md_file.read() - - print(f"Processing: {input_file_path} -> {output_file_path}") - rendered_html = render_markdown_with_jinja(markdown_content) - - with open(output_file_path, "w", encoding="utf-8") as html_file: - html_file.write(rendered_html) diff --git a/depricated/mock_data.json b/depricated/mock_data.json deleted file mode 100644 index 59881d5..0000000 --- a/depricated/mock_data.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "categories": [ - {"name": "SKAT", "path": "skat", "author": "Henrik"}, - {"name": "Skole", "path": "skole", "author": "Erika"}, - {"name": "Bolig", "path": "bolig", "author": "Henrik"}, - {"name": "Job", "path": "job", "author": "Henrik"} - ], - "favorites": [ - {"name": "SKAT", "image": "images/pic07.jpg", "description": "Favorit Kategori"}, - {"name": "Skole", "image": "images/pic08.jpg", "description": "Skole information"}, - {"name": "Bolig", "image": "images/pic09.jpg", "description": "Bolig detaljer"} - ] -} \ No newline at end of file diff --git a/depricated/test_markdown_render.py b/depricated/test_markdown_render.py deleted file mode 100644 index d71869a..0000000 --- a/depricated/test_markdown_render.py +++ /dev/null @@ -1,18 +0,0 @@ -from app.services.markdown_render import MarkdownRenderer - -# Initialize MarkdownRenderer -renderer = MarkdownRenderer() - -# Test Markdown input -markdown_content = """ -{img-left-overlay: src=my-cat.png} -{box: title=Test Box, content=This is a test.} -{note: content=This is a note.} -{warning: content=Be careful!} -""" - -# Render to HTML -print("Rendering Markdown...") -html_output = renderer.render(markdown_content) -print("Rendered HTML:") -print(html_output) \ No newline at end of file diff --git a/fonts/open-sans-v40-latin.zip b/fonts/open-sans-v40-latin.zip deleted file mode 100644 index eaa737f..0000000 Binary files a/fonts/open-sans-v40-latin.zip and /dev/null differ diff --git a/fonts/roboto-slab-v34-latin.zip b/fonts/roboto-slab-v34-latin.zip deleted file mode 100644 index 71f78b9..0000000 Binary files a/fonts/roboto-slab-v34-latin.zip and /dev/null differ diff --git a/templates/navigation.html b/templates/navigation.html index b37ef0f..f4f32a5 100644 --- a/templates/navigation.html +++ b/templates/navigation.html @@ -26,6 +26,7 @@ {% for favorite in data.favorites %}
+ {{ favorite.name }}

{{ favorite.path }}: {{ favorite.description }}