From f7f23565104a32b70e0f715800a0b2b8549250cf Mon Sep 17 00:00:00 2001 From: Djeex Date: Fri, 15 Aug 2025 13:36:48 +0000 Subject: [PATCH 1/3] Better comments --- src/py/css_generator.py | 3 +++ src/py/gallery_builder.py | 5 +++++ src/py/html_generator.py | 5 +++++ src/py/utils.py | 13 +++++++------ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/py/css_generator.py b/src/py/css_generator.py index 82737ca..c550954 100644 --- a/src/py/css_generator.py +++ b/src/py/css_generator.py @@ -3,6 +3,7 @@ from pathlib import Path from shutil import copyfile def generate_css_variables(colors_dict, output_path): + """Generate css variables for theme colors""" css_lines = [":root {"] for key, value in colors_dict.items(): css_lines.append(f" --color-{key.replace('_', '-')}: {value};") @@ -13,6 +14,7 @@ def generate_css_variables(colors_dict, output_path): logging.info(f"[✓] CSS variables written to {output_path}") def generate_fonts_css(fonts_dir, output_path, fonts_cfg=None): + """Generate css variables fonts""" font_files = list(fonts_dir.glob("*")) font_faces = {} preload_links = [] @@ -57,6 +59,7 @@ def generate_fonts_css(fonts_dir, output_path, fonts_cfg=None): return preload_links def generate_google_fonts_link(fonts): + """Generate src link for Google fonts""" if not fonts: return "" families = [] diff --git a/src/py/gallery_builder.py b/src/py/gallery_builder.py index eaff225..2666f8c 100644 --- a/src/py/gallery_builder.py +++ b/src/py/gallery_builder.py @@ -10,6 +10,7 @@ GALLERY_DIR = Path("config/photos/gallery") HERO_DIR = Path("config/photos/hero") def load_yaml(path): + """Load gallery config .yaml file""" print(f"[→] Loading {path}...") if not os.path.exists(path): print(f"[✗] File not found: {path}") @@ -21,11 +22,13 @@ def load_yaml(path): return data def save_yaml(data, path): + """Save modified gallery config .yaml file""" with open(path, "w", encoding="utf-8") as f: yaml.dump(data, f, sort_keys=False, allow_unicode=True) print(f"[✓] Saved updated YAML to {path}") def get_all_image_paths(directory): + """Get the path to record for builded site""" return sorted([ str(p.relative_to(directory.parent)).replace("\\", "/") for p in directory.rglob("*") @@ -33,6 +36,7 @@ def get_all_image_paths(directory): ]) def update_gallery(): + """Update the gallery photo list""" print("\n=== Updating gallery.yaml (gallery section) ===") gallery = load_yaml(GALLERY_YAML) @@ -71,6 +75,7 @@ def update_gallery(): print("[✓] No changes to gallery.yaml (gallery)") def update_hero(): + """Update the hero photo list""" print("\n=== Updating gallery.yaml (hero section) ===") gallery = load_yaml(GALLERY_YAML) diff --git a/src/py/html_generator.py b/src/py/html_generator.py index 2ac932e..9ee3872 100644 --- a/src/py/html_generator.py +++ b/src/py/html_generator.py @@ -3,6 +3,7 @@ import logging from pathlib import Path def render_template(template_path, context): + """Render html templates""" with open(template_path, encoding="utf-8") as f: content = f.read() for key, value in context.items(): @@ -11,6 +12,7 @@ def render_template(template_path, context): return content def render_gallery_images(images): + """Render the photo gallery""" html = "" for img in images: tags = " ".join(img.get("tags", [])) @@ -24,6 +26,7 @@ def render_gallery_images(images): return html def generate_gallery_json_from_images(images, output_dir): + """Generte the hero carrousel photo list""" try: img_list = [img["src"] for img in images] output_path = output_dir / "data" / "gallery.json" @@ -35,6 +38,7 @@ def generate_gallery_json_from_images(images, output_dir): logging.error(f"[✗] Error generating gallery JSON: {e}") def generate_robots_txt(canonical_url, allowed_paths, output_dir): + """Generate the robot.txt""" robots_lines = ["User-agent: *"] # Block everything by default @@ -62,6 +66,7 @@ def generate_robots_txt(canonical_url, allowed_paths, output_dir): logging.error(f"[✗] Failed to write robots.txt: {e}") def generate_sitemap_xml(canonical_url, allowed_paths, output_dir): + """Generate the sitemap""" urlset_start = '\n\n' urlset_end = '\n' urls = "" diff --git a/src/py/utils.py b/src/py/utils.py index abef78c..1e2e9c1 100644 --- a/src/py/utils.py +++ b/src/py/utils.py @@ -4,6 +4,7 @@ from pathlib import Path from shutil import copytree, rmtree, copyfile def load_yaml(path): + """Load gallery and site .yaml conf""" if not path.exists(): logging.warning(f"[!] YAML file not found: {path}") return {} @@ -11,6 +12,7 @@ def load_yaml(path): return yaml.safe_load(f) def load_theme_config(theme_name, themes_dir): + """Load theme.yaml""" theme_dir = themes_dir / theme_name theme_config_path = theme_dir / "theme.yaml" if not theme_config_path.exists(): @@ -20,26 +22,25 @@ def load_theme_config(theme_name, themes_dir): return theme_vars, theme_dir def clear_dir(path: Path): + """Clear the output dir""" if not path.exists(): path.mkdir(parents=True) return - - # Remove all files and subdirectories inside path, but not path itself for child in path.iterdir(): if child.is_file() or child.is_symlink(): - child.unlink() # delete file or symlink + child.unlink() elif child.is_dir(): - rmtree(child) # delete directory and contents - -# Then replace your ensure_dir with this: + rmtree(child) def ensure_dir(path: Path): + """Create the output dir if it does not exist""" if not path.exists(): path.mkdir(parents=True) else: clear_dir(path) def copy_assets(js_dir, style_dir, build_dir): + """Copy public assets to output dir""" for folder in [js_dir, style_dir]: if folder.exists(): dest = build_dir / folder.name From a02da47e73f8e71c8719b5c37444f7de58fc565e Mon Sep 17 00:00:00 2001 From: Djeex Date: Mon, 18 Aug 2025 10:24:08 +0000 Subject: [PATCH 2/3] fixed scroll to tup button --- docker/.sh/entrypoint.sh | 2 +- src/public/js/lumeex.js | 10 ++++++---- src/py/site_builder.py | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docker/.sh/entrypoint.sh b/docker/.sh/entrypoint.sh index 5db76c5..4cb60f2 100644 --- a/docker/.sh/entrypoint.sh +++ b/docker/.sh/entrypoint.sh @@ -52,7 +52,7 @@ start_server() { if [ $# -eq 0 ]; then echo -e "${CYAN}╭───────────────────────────────────────────╮${NC}" - echo -e "${CYAN}│${NC} Lum${CYAN}eex${NC} - Version 1.3.1${NC} ${CYAN}│${NC}" + echo -e "${CYAN}│${NC} Lum${CYAN}eex${NC} - Version 1.3.2${NC} ${CYAN}│${NC}" echo -e "${CYAN}├───────────────────────────────────────────┤${NC}" echo -e "${CYAN}│${NC} Source: https://git.djeex.fr/Djeex/lumeex ${CYAN}│${NC}" echo -e "${CYAN}│${NC} Mirror: https://github.com/Djeex/lumeex ${CYAN}│${NC}" diff --git a/src/public/js/lumeex.js b/src/public/js/lumeex.js index a07cce3..a9faf3e 100644 --- a/src/public/js/lumeex.js +++ b/src/public/js/lumeex.js @@ -143,10 +143,12 @@ const disableRightClickAndDrag = () => { // Scroll to top button const setupScrollToTopButton = () => { - const scrollToTopButton = document.querySelector('.scroll-to-top'); - if (!scrollToTopButton) return; - scrollToTopButton.addEventListener('click', () => { - window.scrollTo({ top: 0, behavior: 'smooth' }); + const scrollBtn = document.getElementById("scrollToTop"); + window.addEventListener("scroll", () => { + scrollBtn.style.display = window.scrollY > 300 ? "block" : "none"; + }); + scrollBtn.addEventListener("click", () => { + window.scrollTo({ top: 0, behavior: "smooth" }); }); }; diff --git a/src/py/site_builder.py b/src/py/site_builder.py index 10f38bf..f8996f1 100644 --- a/src/py/site_builder.py +++ b/src/py/site_builder.py @@ -23,7 +23,7 @@ SITE_FILE = SRC_DIR / "config/site.yaml" THEMES_DIR = SRC_DIR / "config/themes" def build(): - build_version = "v1.3.1" + build_version = "v1.3.2" logging.info("\n") logging.info("=" * 24) logging.info(f"🚀 Lumeex builder {build_version}") From 643a729f94e49bc1024be7970eb47b5766e0c1bf Mon Sep 17 00:00:00 2001 From: Djeex Date: Mon, 18 Aug 2025 13:01:51 +0200 Subject: [PATCH 3/3] Hotfix --- src/public/js/lumeex.js | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/public/js/lumeex.js b/src/public/js/lumeex.js index a9faf3e..998b9e1 100644 --- a/src/public/js/lumeex.js +++ b/src/public/js/lumeex.js @@ -69,7 +69,8 @@ const setupTagFilter = () => { const allSections = document.querySelectorAll('.section[data-tags]'); const allTags = document.querySelectorAll('.tag'); let activeTags = []; - let lastClickedTag = null; // mémorise le dernier tag cliqué + let lastClickedTag = null; // remembers the last clicked tag + let lastClickedSection = null; // remembers the last clicked section (photo) const applyFilter = () => { let filteredSections = []; @@ -81,30 +82,41 @@ const setupTagFilter = () => { section.style.display = hasAllTags ? '' : 'none'; if (hasAllTags) { - filteredSections.push(section); - if (lastClickedTag && sectionTags.includes(lastClickedTag) && !matchingSection) { + if (lastClickedSection === section) { matchingSection = section; + } else { + filteredSections.push(section); } } }); - // Réorganise : la photo correspondante au dernier tag cliqué en premier - if (matchingSection && galleryContainer.contains(matchingSection)) { - galleryContainer.prepend(matchingSection); + // Remove all filtered sections from DOM before reordering + if (galleryContainer) { + [matchingSection, ...filteredSections].forEach(section => { + if (section && galleryContainer.contains(section)) { + galleryContainer.removeChild(section); + } + }); + if (matchingSection) { + galleryContainer.prepend(matchingSection); + } + filteredSections.forEach(section => { + galleryContainer.appendChild(section); + }); } - // Met à jour le style des tags + // Update tag styles allTags.forEach((tagEl) => { const tagText = tagEl.textContent.replace('#', '').toLowerCase(); tagEl.classList.toggle('active', activeTags.includes(tagText)); }); - // Met à jour l'URL + // Update the URL const base = window.location.pathname; const query = activeTags.length > 0 ? `?tag=${activeTags.join(',')}` : ''; window.history.pushState({}, '', base + query); - // Scroll jusqu'à la galerie + // Scroll to the gallery if (galleryContainer) { galleryContainer.scrollIntoView({ behavior: 'smooth', block: 'start' }); } @@ -113,7 +125,8 @@ const setupTagFilter = () => { allTags.forEach((tagEl) => { tagEl.addEventListener('click', () => { const tagText = tagEl.textContent.replace('#', '').toLowerCase(); - lastClickedTag = tagText; // mémorise le dernier tag cliqué + lastClickedTag = tagText; // remembers the last clicked tag + lastClickedSection = tagEl.closest('.section'); // remembers the last clicked section if (activeTags.includes(tagText)) { activeTags = activeTags.filter((t) => t !== tagText); @@ -130,6 +143,7 @@ const setupTagFilter = () => { if (urlTags) { activeTags = urlTags.split(',').map((t) => t.toLowerCase()); lastClickedTag = activeTags[activeTags.length - 1] || null; + lastClickedSection = null; // No section selected from URL applyFilter(); } }); @@ -141,9 +155,9 @@ const disableRightClickAndDrag = () => { document.addEventListener('dragstart', (e) => e.preventDefault()); }; -// Scroll to top button +// Scroll-to-top button functionality const setupScrollToTopButton = () => { - const scrollBtn = document.getElementById("scrollToTop"); + const scrollBtn = document.getElementById("scrollToTop"); window.addEventListener("scroll", () => { scrollBtn.style.display = window.scrollY > 300 ? "block" : "none"; }); @@ -175,4 +189,4 @@ document.addEventListener("DOMContentLoaded", () => { fixNavSeparators(); }); -window.addEventListener('resize', fixNavSeparators); +window.addEventListener('resize', fixNavSeparators); \ No newline at end of file