From 73807869ff8a36cd31cd835cc6e2d8e281d74f55 Mon Sep 17 00:00:00 2001 From: x222 <113437965+rsnx222@users.noreply.github.com> Date: Wed, 26 Feb 2025 22:37:46 +0000 Subject: [PATCH 1/4] Fix path handling issues in MkDocs generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gen_pages.py: Ensured source_dir is always an absolute Path to prevent NoneType errors. name_conversion.py: Fixed an issue where channel['path'] could be None, ensuring valid path operations. rules.py: Prevented NoneType errors when formatting Discord channel links by defaulting to a safe path. page_generator.py: Fixed relative_to() path errors by resolving absolute paths and falling back if paths don’t match. --- gen_pages.py | 6 ++++-- site_builder/formatter/rules.py | 3 ++- site_builder/name_conversion.py | 6 ++++-- site_builder/page_generator.py | 13 ++++++++++++- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/gen_pages.py b/gen_pages.py index e8351d6a59..9ead2f8aeb 100644 --- a/gen_pages.py +++ b/gen_pages.py @@ -31,7 +31,9 @@ # 'afk/**/*.txt' # ]) -name_converter = NameConverter(settings.name_convert, settings.files.source_dir) +source_dir = Path(settings.files.source_dir).resolve() if settings.files.source_dir else Path("docs").resolve() + +name_converter = NameConverter(settings.name_convert, source_dir) +page_generator = PageGenerator(files, name_converter, source_dir) -page_generator = PageGenerator(files, name_converter, settings.files.source_dir) page_generator.generate_pages() diff --git a/site_builder/formatter/rules.py b/site_builder/formatter/rules.py index 7130310f5b..5843e7a517 100644 --- a/site_builder/formatter/rules.py +++ b/site_builder/formatter/rules.py @@ -169,7 +169,8 @@ def format_content(content): # path = f"{os.path.dirname(txt_path)}/{name}" # link = f"[#{name}](../../{path})" name = channel['name'] - txt_file = Path(channel['path']) + txt_file = Path(channel['path']) if channel.get('path') else Path("docs/unknown.txt") + # todo: work-around relative links, check if absolute links work relative_path = '../' * (len(DiscordChannelID.CUR_FILE.parts) - 1) + txt_file.with_suffix('').as_posix() link = f"[#{name}]({relative_path})" diff --git a/site_builder/name_conversion.py b/site_builder/name_conversion.py index 8047b2022b..193187ab20 100644 --- a/site_builder/name_conversion.py +++ b/site_builder/name_conversion.py @@ -31,8 +31,10 @@ def __init__(self, settings: NameConvertSettings, source_dir: Path): self.__category_settings = AliasStore('category', settings.category) self.__forum_alias = AliasStore('forum', settings.forum) self.__word_alias = AliasStore('word', settings.word) - self.__channel_alias = {source_dir / channel['path']: channel['name'] for channel in - DiscordChannelID.CHANNEL_LOOKUP.values()} + self.__channel_alias = { + source_dir / Path(channel['path']) if channel.get('path') else source_dir: channel['name'] + for channel in DiscordChannelID.CHANNEL_LOOKUP.values() + } self.__extra_channel_alias = AliasStore('extra-channel-alias', settings.extra_channel) def channel(self, source_file: Path): diff --git a/site_builder/page_generator.py b/site_builder/page_generator.py index eaef899457..bb1222af61 100644 --- a/site_builder/page_generator.py +++ b/site_builder/page_generator.py @@ -29,7 +29,18 @@ def generate_pages(self): output_file = source_file.with_suffix('.md') self.generate_page(source_file, output_file, channel_name) - self.__update_nav(source_file.relative_to(self.__source_output_dir).parent, output_file, channel_name) + + source_file_absolute = source_file.resolve() + source_output_absolute = self.__source_output_dir.resolve() + + try: + relative_source = source_file_absolute.relative_to(source_output_absolute) + except ValueError: + logger.warning(f"Cannot compute relative path for {source_file_absolute}. Using absolute path instead.") + relative_source = source_file_absolute # Fallback to absolute path + + self.__update_nav(relative_source.parent, output_file, channel_name) + self.__nav.update_mkdocs_nav() From 2a7eee96fddc68e6acc780a329bebf17e9213533 Mon Sep 17 00:00:00 2001 From: x222 <113437965+rsnx222@users.noreply.github.com> Date: Fri, 28 Feb 2025 11:11:59 +0000 Subject: [PATCH 2/4] 1/2 - Simplified nav and landing page guides Still needs "first child" logic when you click on category --- docs/pvme-guides.md | 55 ++++++++++++++++ docs/stylesheets/extra.css | 27 ++++++++ mkdocs.yml | 39 +++++++---- site_builder/navigation.py | 115 ++++++++++++++++++++++++++++----- site_builder/page_generator.py | 47 +++++++------- structure_settings.yml | 90 ++++++++++++-------------- 6 files changed, 276 insertions(+), 97 deletions(-) create mode 100644 docs/pvme-guides.md diff --git a/docs/pvme-guides.md b/docs/pvme-guides.md new file mode 100644 index 0000000000..1ef1052895 --- /dev/null +++ b/docs/pvme-guides.md @@ -0,0 +1,55 @@ +--- +hide: + - navigation + - toc + +hide_actions: true +--- +# PVM Guides + +
+ +
\ No newline at end of file diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index b9928dee2a..59ea7bb099 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -65,4 +65,31 @@ p { /* Hide navigation emojis when the category is opened */ .md-nav__link .nav-emoji { display: none; +} + +.md-typeset .grid { + grid-gap: 1rem; + grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); +} + +.md-typeset .grid.cards>ul>li { + padding: 0; +} + +.md-typeset .grid li > a { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + color: var(--md-primary-bg-color); + padding: 0.8rem; +} + +.md-typeset .grid li:hover > a { + color: var(--md-primary-fg-color); +} + + +.md-typeset .grid h2 { + margin: 0; } \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 5232726fa0..b56fe463bf 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -13,14 +13,14 @@ theme: custom_dir: overrides favicon: assets/logo.ico features: - - navigation.instant - navigation.tabs - navigation.tabs.sticky + - navigation.instant + - navigation.sections + - navigation.expand + - navigation.path - search.suggest - search.highlight - # - search.share - - navigation.top - # - navigation.indexes - announce.dismiss - content.action.edit palette: @@ -33,10 +33,8 @@ theme: icon: material/weather-sunny name: Switch to dark mode - plugins: - search -#- git-revision-date-localized - macros - gen-files: scripts: @@ -50,7 +48,8 @@ markdown_extensions: - pymdownx.emoji - admonition - footnotes -# - pymdownx.extra (markdown formatting in HTMl blocks) + - attr_list + - md_in_html extra_css: - stylesheets/extra.css @@ -61,9 +60,23 @@ extra_javascript: - javascripts/discordInvite.js nav: - - index.md - - About: - - Info: about/info.md - - Keyboard Shortcuts: about/shortcuts.md - - How The Site Works: about/workings.md - - Changelog: about/changelog.md \ No newline at end of file + - Home: index.md + - Getting Started: + - New to PvM: new-to-pvm + - New to Bossing: new-to-bossing + - Invention & Perks: invention-and-perks + - PVME Guides: + - Guides Home: pvme-guides.md + - Basic Guides: basic-guides + - RS3 Full Boss Guides: rs3-full-boss-guides + - AFK Methods: afk + - Combat Achievements: combat-achievements + - Slayer Guides: slayer + - One Tick Guides: one-tick-guides + - Strategy: + - DPM Advice: dpm-advice + - Upgrade Paths: upgrading-info + - Miscellaneous: + - PVME Mastery Roles: get-involved + - About PVME: about + - Editor Resources: editor-resources diff --git a/site_builder/navigation.py b/site_builder/navigation.py index be11b20334..6aadeb97b0 100644 --- a/site_builder/navigation.py +++ b/site_builder/navigation.py @@ -1,24 +1,109 @@ -from typing import List, Union, Tuple +import yaml +import logging +from typing import List +from pathlib import Path +from collections import defaultdict +logging.basicConfig(level=logging.DEBUG, format="%(levelname)s:%(name)s:%(message)s") +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) -class NavStructure(dict): - def __setitem__(self, keys: List[str], value: Union[Tuple[str, str], str]): - cur = self - for key in keys: - cur = cur.setdefault(key, {}) - cur[value[0]] = value[1] +# Load NAV structure from mkdocs.yml +def load_nav_from_mkdocs(): + mkdocs_path = Path("mkdocs.yml") + with mkdocs_path.open("r", encoding="utf-8") as file: + config = yaml.safe_load(file) + return config.get("nav", []) +HARDCODED_NAV = load_nav_from_mkdocs() class NavInterface: - def __init__(self, mkdocs_nav): + def __init__(self, mkdocs_nav, source_files, name_converter): + if mkdocs_nav is None: + raise ValueError("Error: MkDocs navigation is None. Ensure 'nav:' is properly initialized.") + self.__nav = mkdocs_nav - self.__structure = NavStructure() + self.__source_files = source_files + self.__name_converter = name_converter + self.__structure = defaultdict(lambda: defaultdict(list)) - def add_item(self, category_name, forum_name, channel_name, output_file): - keys = [category_name] + def add_item(self, category_name: str, forum_name: str, channel_name: str, output_file: str): + """Ensures Level 2 appears first, then nests Level 3 pages under it properly.""" if forum_name: - keys.append(forum_name) - self.__structure[keys] = channel_name, output_file + self.__structure[category_name][forum_name].append({channel_name: output_file}) + else: + self.__structure[category_name][channel_name] = output_file + + def find_first_guide(self, category_folder, mkdocs_files): + """Finds the first available markdown file inside a given category.""" + logger.debug(f"πŸ” Searching for guides in category: {category_folder}") + + # Normalize category path for comparison + expected_prefix = f"pvme-guides/{category_folder}/" + + # Retrieve and sort relevant markdown files + md_files = sorted( + [file.src_path for file in mkdocs_files if file.src_path.startswith(expected_prefix) and file.src_path.endswith(".md")] + ) + + logger.debug(f"πŸ“„ Found {len(md_files)} markdown files for {category_folder}: {md_files}") + + return md_files[0] if md_files else None # Return first guide if found + + def rebuild_nav(self, mkdocs_files): + """Ensures 'PVME Guides' appears with its subcategories and actual guides.""" + logger.debug("πŸ” Rebuilding MkDocs Navigation") + + nav = [] + + # Force all paths to use forward slashes to avoid Windows path issues + all_md_files = [file.src_path.replace("\\", "/") for file in mkdocs_files if file.src_path.endswith(".md")] + logger.debug(f"πŸ“„ ALL MkDocs Markdown Files: {all_md_files}") + + # Load PVME Guides categories from HARDCODED_NAV + pvme_guides_section = None + for section in HARDCODED_NAV: + if isinstance(section, dict) and "PVME Guides" in section: + category_entries = section["PVME Guides"] + logger.debug(f"πŸ“‚ Found PVME Guides Categories: {category_entries}") + + # Initialize PVME Guides with its landing page + pvme_guides_section = {"PVME Guides": []} + + for entry in category_entries: + if isinstance(entry, dict): + for category, folder in entry.items(): + # Find all markdown files within the category (recursive scan) + category_guides = sorted( + [file for file in all_md_files if file.startswith(f"pvme-guides/{folder}/")] + ) + + if category_guides: + # Append actual guides under each category + pvme_guides_section["PVME Guides"].append({category: category_guides}) + logger.debug(f"πŸ“Œ Added {len(category_guides)} guides under '{category}'.") + else: + # Ensure empty categories still exist as placeholders + pvme_guides_section["PVME Guides"].append({category: folder}) + logger.warning(f"⚠️ No guides found for '{category}', keeping as placeholder.") + + elif isinstance(entry, str): + # Ensure the landing page is added first + pvme_guides_section["PVME Guides"].insert(0, entry) + logger.debug(f"πŸ“Œ Added PVME Guides Landing Page: {entry}") + + break # We only need to process PVME Guides once + + if pvme_guides_section: + nav.append(pvme_guides_section) + else: + logger.warning("⚠️ PVME Guides structure not found, skipping.") + + # Preserve other sections + for section in HARDCODED_NAV: + if isinstance(section, dict) and "PVME Guides" not in section: + nav.append(section) - def update_mkdocs_nav(self): - self.__nav.extend([{key: value} for key, value in self.__structure.items()]) + self.__nav.clear() + self.__nav.extend(nav) + logger.debug(f"βœ… Final Navigation Structure:\n{self.__nav}") diff --git a/site_builder/page_generator.py b/site_builder/page_generator.py index bb1222af61..ad849a29bc 100644 --- a/site_builder/page_generator.py +++ b/site_builder/page_generator.py @@ -1,19 +1,15 @@ import logging from typing import List from pathlib import Path - import mkdocs_gen_files - from site_builder.navigation import NavInterface from site_builder.formatter.rules import DiscordChannelID from site_builder.raw_message_parser import get_raw_messages from site_builder.formatter.message_formatter import MessageFormatter from site_builder.name_conversion import NameConverter - logger = logging.getLogger(__name__) - class PageGenerator: def __init__(self, source_files: List[Path], name_converter: NameConverter, source_output_dir: Path): self.__source_output_dir = source_output_dir @@ -21,36 +17,37 @@ def __init__(self, source_files: List[Path], name_converter: NameConverter, sour self.__name_converter = name_converter mkdocs_process = mkdocs_gen_files.FilesEditor.current() - self.__nav = NavInterface(mkdocs_process.config.nav) + mkdocs_nav = getattr(mkdocs_process.config, "nav", None) + + if mkdocs_nav is None: + raise ValueError("Error: MkDocs navigation is not initialized. Ensure 'nav:' is defined in mkdocs.yml before running.") + + self.__nav = NavInterface(mkdocs_nav, self.__source_files, self.__name_converter) def generate_pages(self): + mkdocs_process = mkdocs_gen_files.FilesEditor.current() + mkdocs_files = mkdocs_process.files + for source_file in self.__source_files: channel_name = self.__name_converter.channel(source_file) output_file = source_file.with_suffix('.md') self.generate_page(source_file, output_file, channel_name) - source_file_absolute = source_file.resolve() - source_output_absolute = self.__source_output_dir.resolve() + self.__update_nav(source_file.parent, output_file, channel_name) - try: - relative_source = source_file_absolute.relative_to(source_output_absolute) - except ValueError: - logger.warning(f"Cannot compute relative path for {source_file_absolute}. Using absolute path instead.") - relative_source = source_file_absolute # Fallback to absolute path - - self.__update_nav(relative_source.parent, output_file, channel_name) - - - self.__nav.update_mkdocs_nav() + # Rebuild navigation after processing all pages + self.__nav.rebuild_nav(mkdocs_files) @staticmethod def generate_page(source_file: Path, output_file: Path, channel_name): - logger.debug(f"formatting: {output_file}") + logger.debug(f"πŸ“ Generating page: {output_file}") + + output_file.parent.mkdir(parents=True, exist_ok=True) - # todo: work-around relative links, check if absolute links work DiscordChannelID.CUR_FILE = output_file - formatted_channel = f"" + + formatted_channel = f"# {channel_name}\n\n" for raw_message in get_raw_messages(source_file.read_text('utf-8')): message_formatter = MessageFormatter(raw_message) message_formatter.format() @@ -60,8 +57,14 @@ def generate_page(source_file: Path, output_file: Path, channel_name): file.write(formatted_channel) def __update_nav(self, category_forum_path: Path, output_file, channel_name): + """Ensures correct Level 2 & 3 nesting in navigation.""" category, *forum = category_forum_path.parts category_name = self.__name_converter.category(category) - forum_name = self.__name_converter.forum(forum[0]) if len(forum) > 0 else None + forum_name = self.__name_converter.forum(forum[0]) if forum else None + + corrected_path = output_file.as_posix() + + if corrected_path.startswith("pvme-guides/pvme-guides"): + corrected_path = corrected_path.replace("pvme-guides/pvme-guides", "pvme-guides", 1) - self.__nav.add_item(category_name, forum_name, channel_name, output_file.as_posix()) \ No newline at end of file + self.__nav.add_item(category_name, forum_name, channel_name, corrected_path) diff --git a/structure_settings.yml b/structure_settings.yml index 3466662713..6922d95272 100644 --- a/structure_settings.yml +++ b/structure_settings.yml @@ -1,45 +1,29 @@ files: includes: - - getting-started/quick-start.txt - - getting-started/how-to-use-pvme.txt - - getting-started/interface-guide.txt - - getting-started/early-moneymaking-ideas.txt - - getting-started/noncombat-skilling-guides.txt - + # Getting Started + - getting-started/**/*.txt - new-to-pvm/**/*.txt - - new-to-bossing/**/*.txt + # Invention & Perks - invention-and-perks/**/*.txt - - - miscellaneous-information/**/*.txt - - - upgrading-info/upgrade-order/*.txt - - upgrading-info/**/*.txt - - dpm-advice/**/*.txt - - - afk/afk-overview.txt - - afk/**/*.txt - - - basic-guides/**/*.txt - - - rs3-full-boss-guides/**/*.txt + # Guides + - basic-guides/**/*.{txt,md} + - rs3-full-boss-guides/**/*.{txt,md} + - afk/**/*.{txt,md} + - combat-achievements/**/*.{txt,md} + - slayer/**/*.{txt,md} + - one-tick-guides/**/*.{txt,md} - - slayer/overview-of-slayer.txt - - slayer/block-prefer-list.txt - - slayer/ultimate-slayer.txt - - slayer/miscellaneous-slayer.txt - - slayer/**/*.txt + # Strategy + - dpm-advice/**/*.{txt,md} + - upgrading-info/**/*.{txt,md} - - get-involved/mastery-requirements.txt - - get-involved/feats-requirements.txt - - - editor-resources/intro-to-editing.txt - - editor-resources/intro-to-editing-continued.txt - - editor-resources/editor-tools/*.txt - - editor-resources/editor-references/*.txt - - editor-resources/github-tutorials/*.txt + # Miscellaneous + - get-involved/**/*.{txt,md} + - editor-resources/**/*.{txt,md} + - miscellaneous-information/**/*.{txt,md} excludes: - navigation/**/*.txt @@ -52,26 +36,38 @@ files: - get-involved/editor-entry.txt - .github/**/* -# uncategorized: -# - '**/*.txt' - name_convert: category: + getting-started: + alias: Getting Started + new-to-pvm: + alias: New to PvM + new-to-bossing: + alias: New to Bossing invention-and-perks: - alias: perks - emoji: "689509250946695292" - miscellaneous-information: - alias: miscellaneous - upgrading-info: - alias: upgrades - slayer: - emoji: "797896049548066857" + alias: Invention & Perks + basic-guides: + alias: Basic Guides rs3-full-boss-guides: - alias: full boss guides + alias: RS3 Full Boss Guides + afk: + alias: AFK Methods + combat-achievements: + alias: Combat Achievements + slayer: + alias: Slayer Guides + one-tick-guides: + alias: One Tick Guides + dpm-advice: + alias: Strategy + upgrading-info: + alias: Strategy get-involved: - alias: mastery + alias: PVME Mastery Roles editor-resources: - alias: editor info + alias: Editor Resources + miscellaneous-information: + alias: Miscellaneous extra_channel: AFK Commander Zilyana Hard Mode: afk commander zilyana hm From 24ad62b4efcd0fbf1dd39d65726ad6c2cf1ccfff Mon Sep 17 00:00:00 2001 From: x222 <113437965+rsnx222@users.noreply.github.com> Date: Fri, 28 Feb 2025 13:47:15 +0000 Subject: [PATCH 3/4] 1/2 continued renamed section to "boss guides" to avoid confusion with pvme-guides --- ...vme-guides.md => boss-guides-directory.md} | 3 +- mkdocs.yml | 10 +++--- site_builder/navigation.py | 34 +++++++++---------- site_builder/page_generator.py | 7 ++-- 4 files changed, 26 insertions(+), 28 deletions(-) rename docs/{pvme-guides.md => boss-guides-directory.md} (97%) diff --git a/docs/pvme-guides.md b/docs/boss-guides-directory.md similarity index 97% rename from docs/pvme-guides.md rename to docs/boss-guides-directory.md index 1ef1052895..1fe39e8048 100644 --- a/docs/pvme-guides.md +++ b/docs/boss-guides-directory.md @@ -1,11 +1,10 @@ --- hide: - - navigation - toc hide_actions: true --- -# PVM Guides +# Boss Guides - Directory