diff --git a/README.md b/README.md
index 1a12f874..8acfc2d3 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@
-
+
@@ -174,12 +174,23 @@
-
-
-
+
+
+
+
+_A small set of well-written output styles, specifically focused on debugging - root cause analysis, systematic, methodical debugging, encouraging a more careful approach to bug-squashing from Claude Code._
+
+
+
+_A high-performance Claude Code statusline tool written in Rust with Git integration, usage tracking, interactive TUI configuration, and Claude Code enhancement utilities._
+
+
+
+_Collection of best practices, tips, and techniques for Claude Code development workflows, enhanced with distributable plugins_
+
diff --git a/README_CLASSIC.md b/README_CLASSIC.md
index 1af30bad..6d6d9113 100644
--- a/README_CLASSIC.md
+++ b/README_CLASSIC.md
@@ -35,11 +35,33 @@ Claude Code is a cutting-edge CLI-based coding assistant and agent released by [
-## This Week's Additions ✨ [🔝](#awesome-claude-code)
+## Latest Additions ✨ [🔝](#awesome-claude-code)
-> Resources added in the past 7 days
-*No new resources added this week.*
+[`Claude Code Output Styles - Debugging`](https://github.com/JamieM0/claude-output-styles) by [Jamie Matthews](https://github.com/JamieM0) ⚖️ MIT
+A small set of well-written output styles, specifically focused on debugging - root cause analysis, systematic, methodical debugging, encouraging a more careful approach to bug-squashing from Claude Code.
+
+
+📊 GitHub Stats
+
+
+
+
+
+
+[`CCometixLine - Claude Code Statusline`](https://github.com/Haleclipse/CCometixLine) by [Haleclipse](https://github.com/Haleclipse)
+A high-performance Claude Code statusline tool written in Rust with Git integration, usage tracking, interactive TUI configuration, and Claude Code enhancement utilities.
+
+
+📊 GitHub Stats
+
+
+
+
+
+
+[`Claude Code Handbook`](https://nikiforovall.blog/claude-code-rules/) by [nikiforovall](https://github.com/nikiforovall) ⚖️ MIT
+Collection of best practices, tips, and techniques for Claude Code development workflows, enhanced with distributable plugins
## Contents [🔝](#awesome-claude-code)
diff --git a/assets/badge-claude-code-output-styles-debugging.svg b/assets/badge-claude-code-output-styles-debugging.svg
new file mode 100644
index 00000000..fbd335bc
--- /dev/null
+++ b/assets/badge-claude-code-output-styles-debugging.svg
@@ -0,0 +1,32 @@
+
\ No newline at end of file
diff --git a/assets/latest-additions-header-light.svg b/assets/latest-additions-header-light.svg
new file mode 100644
index 00000000..012a869a
--- /dev/null
+++ b/assets/latest-additions-header-light.svg
@@ -0,0 +1,47 @@
+
diff --git a/assets/latest-additions-header.svg b/assets/latest-additions-header.svg
new file mode 100644
index 00000000..4bf043b1
--- /dev/null
+++ b/assets/latest-additions-header.svg
@@ -0,0 +1,67 @@
+
diff --git a/scripts/create_resource_pr.py b/scripts/create_resource_pr.py
index 3385209c..614d8fd9 100755
--- a/scripts/create_resource_pr.py
+++ b/scripts/create_resource_pr.py
@@ -7,6 +7,7 @@
import argparse
import json
import os
+import re
import subprocess
import sys
from datetime import datetime
@@ -29,6 +30,16 @@ def create_unique_branch_name(base_name: str) -> str:
return f"{base_name}-{timestamp}"
+def get_badge_filename(display_name: str) -> str:
+ """Compute the badge filename for a resource.
+
+ Uses the same logic as save_resource_badge_svg in generate_readme.py.
+ """
+ safe_name = re.sub(r"[^a-zA-Z0-9]", "-", display_name.lower())
+ safe_name = re.sub(r"-+", "-", safe_name).strip("-")
+ return f"badge-{safe_name}.svg"
+
+
def main():
"""Main entry point."""
parser = argparse.ArgumentParser(description="Create PR from approved resource submission")
@@ -112,8 +123,28 @@ def main():
status_result = run_command(["git", "status", "--porcelain"])
print(f"Git status after README generation:\n{status_result.stdout}", file=sys.stderr)
+ # Compute badge path and check if it was generated
+ script_dir_abs = os.path.dirname(os.path.abspath(__file__))
+ repo_root = os.path.dirname(script_dir_abs)
+ badge_filename = get_badge_filename(resource_data["display_name"])
+ badge_path = os.path.join(repo_root, "assets", badge_filename)
+ badge_warning = ""
+
# Stage changes (includes both README.md and README_CLASSIC.md)
- run_command(["git", "add", "THE_RESOURCES_TABLE.csv", "README.md", "README_CLASSIC.md"])
+ files_to_stage = ["THE_RESOURCES_TABLE.csv", "README.md", "README_CLASSIC.md"]
+
+ if os.path.exists(badge_path):
+ # Stage the badge file relative to repo root
+ files_to_stage.append(f"assets/{badge_filename}")
+ print(f"Badge file found and will be staged: {badge_filename}", file=sys.stderr)
+ else:
+ print(f"Warning: Badge file not generated: {badge_path}", file=sys.stderr)
+ badge_warning = (
+ f"\n\n> **Warning**: Badge SVG (`assets/{badge_filename}`) was not generated. "
+ "Manual attention may be required."
+ )
+
+ run_command(["git", "add", *files_to_stage])
# Commit
commit_message = f"Add resource: {resource_data['display_name']}\n\n"
@@ -131,6 +162,7 @@ def main():
# Create PR
pr_title = f"Add resource: {resource_data['display_name']}"
pr_body = generate_pr_content(resource)
+ pr_body += badge_warning # Empty string if badge was generated successfully
pr_body += f"\n\n---\n\nResolves #{args.issue_number}"
# Use gh CLI to create PR
diff --git a/scripts/generate_readme.py b/scripts/generate_readme.py
index d4fd5dce..a8027e65 100644
--- a/scripts/generate_readme.py
+++ b/scripts/generate_readme.py
@@ -1597,26 +1597,98 @@ def parse_resource_date(date_string):
return None
-def generate_weekly_section(csv_data):
- """Generate the weekly resources section that appears above Contents."""
+def generate_weekly_section(csv_data, assets_dir=None):
+ """Generate the latest additions section that appears above Contents."""
lines = []
- # EXTREME MAKEOVER BANNER!
+ # Latest Additions header with light/dark mode support
lines.append('')
lines.append("
")
lines.append(
- ' '
+ ' '
)
lines.append(
- ' '
- )
- lines.append(
- '
'
+ ' '
)
+ lines.append('
')
lines.append(" ")
lines.append("
")
lines.append("")
+ # Get rows sorted by date added (newest first)
+ resources_sorted_by_date = []
+ for row in csv_data:
+ date_added = row.get("Date Added", "").strip()
+ if date_added:
+ parsed_date = parse_resource_date(date_added)
+ if parsed_date:
+ resources_sorted_by_date.append((parsed_date, row))
+ resources_sorted_by_date.sort(key=lambda x: x[0], reverse=True)
+
+ # Add all resources added in the past 7 days
+ latest_additions = []
+ cutoff_date = datetime.now() - timedelta(days=7)
+ for dated_resource in resources_sorted_by_date:
+ if dated_resource[0] >= cutoff_date or len(latest_additions) < 3:
+ latest_additions.append(dated_resource[1])
+ else:
+ break
+
+ for resource in latest_additions:
+ lines.append(
+ format_resource_entry(resource, assets_dir=assets_dir, include_separator=False)
+ )
+ lines.append("")
+
+ # # Get all resources with dates, sorted newest first
+ # cutoff_date = datetime.now() - timedelta(days=7)
+ # all_dated_resources = []
+
+ # for row in csv_data:
+ # date_added = row.get("Date Added", "").strip()
+ # if date_added:
+ # parsed_date = parse_resource_date(date_added)
+ # if parsed_date:
+ # all_dated_resources.append((parsed_date, row))
+
+ # # Sort by date (newest first)
+ # all_dated_resources.sort(key=lambda x: x[0], reverse=True)
+
+ # # Get resources from past 7 days
+ # recent_resources = [(d, r) for d, r in all_dated_resources if d >= cutoff_date]
+
+ # # Ensure at least 3 entries (fill with most recent if needed)
+ # min_entries = 3
+ # if len(recent_resources) < min_entries:
+ # # Add more recent entries to reach minimum
+ # for dated_resource in all_dated_resources:
+ # if dated_resource not in recent_resources:
+ # recent_resources.append(dated_resource)
+ # if len(recent_resources) >= min_entries:
+ # break
+ # # Re-sort after adding extras
+ # recent_resources.sort(key=lambda x: x[0], reverse=True)
+
+ # if recent_resources:
+ # lines.append("")
+ # lines.append("")
+ # lines.append("The latest resources added to the list")
+ # lines.append("")
+ # lines.append("
")
+ # lines.append("")
+ # for _, resource in recent_resources:
+ # lines.append(
+ # format_resource_entry(resource, assets_dir=assets_dir, include_separator=False)
+ # )
+ # lines.append("")
+ # else:
+ # lines.append("")
+ # lines.append("")
+ # lines.append("*No resources with dates found.*")
+ # lines.append("")
+ # lines.append("
")
+ # lines.append("")
+
return "\n".join(lines).rstrip() + "\n"
@@ -1905,7 +1977,7 @@ def generate_readme_from_templates(csv_path, template_dir, output_path):
toc_content = generate_toc_from_categories(csv_data, general_anchor_map)
# Generate weekly section
- weekly_section = generate_weekly_section(csv_data)
+ weekly_section = generate_weekly_section(csv_data, assets_dir=assets_dir)
# Generate body sections
body_sections = []
@@ -2105,8 +2177,8 @@ def generate_toc(self) -> str:
return generate_toc_from_categories(self.csv_data, self.general_anchor_map)
def generate_weekly_section(self) -> str:
- """Generate weekly section with banner SVG."""
- return generate_weekly_section(self.csv_data)
+ """Generate latest additions section with header SVG."""
+ return generate_weekly_section(self.csv_data, assets_dir=self.assets_dir)
def generate_section_content(self, category: dict, section_index: int) -> str:
"""Generate section with SVG headers and desc boxes."""
@@ -2255,32 +2327,32 @@ def generate_toc(self) -> str:
def generate_weekly_section(self) -> str:
"""Generate weekly section with plain markdown."""
lines = []
- lines.append("## This Week's Additions ✨ [🔝](#awesome-claude-code)")
+ lines.append("## Latest Additions ✨ [🔝](#awesome-claude-code)")
lines.append("")
- lines.append("> Resources added in the past 7 days")
-
- # Get recent resources
- cutoff_date = datetime.now() - timedelta(days=7)
- recent_resources = []
+ # Get rows sorted by date added (newest first)
+ resources_sorted_by_date = []
for row in self.csv_data:
date_added = row.get("Date Added", "").strip()
if date_added:
parsed_date = parse_resource_date(date_added)
- if parsed_date and parsed_date >= cutoff_date:
- recent_resources.append((parsed_date, row))
+ if parsed_date:
+ resources_sorted_by_date.append((parsed_date, row))
+ resources_sorted_by_date.sort(key=lambda x: x[0], reverse=True)
- # Sort by date (newest first)
- recent_resources.sort(key=lambda x: x[0], reverse=True)
+ # Add all resources added in the past 7 days
+ latest_additions: list[dict[str, str]] = []
+ cutoff_date = datetime.now() - timedelta(days=7)
+ for dated_resource in resources_sorted_by_date:
+ if dated_resource[0] >= cutoff_date or len(latest_additions) < 3:
+ latest_additions.append(dated_resource[1])
+ else:
+ break
- if recent_resources:
- lines.append("")
- for _, resource in recent_resources:
- lines.append(self.format_resource_entry(resource, include_separator=False))
- lines.append("")
- else:
+ lines.append("")
+ for resource in latest_additions:
+ lines.append(self.format_resource_entry(resource, include_separator=False))
lines.append("")
- lines.append("*No new resources added this week.*")
return "\n".join(lines).rstrip() + "\n"
diff --git a/scripts/generate_readme_bak_2.py b/scripts/generate_readme_bak_2.py
index 9093426c..74e384f1 100644
--- a/scripts/generate_readme_bak_2.py
+++ b/scripts/generate_readme_bak_2.py
@@ -9,7 +9,7 @@
import re
import shutil
import sys
-from datetime import datetime, timedelta
+from datetime import datetime
import yaml # type: ignore[import-untyped]
from validate_links import parse_github_url # type: ignore[import-not-found]
@@ -24,9 +24,9 @@ def load_template(template_path):
def create_h2_svg_file(text, filename, assets_dir):
"""Create an animated hero-centered H2 header SVG file."""
# Escape XML special characters
- text_escaped = text.replace('&', '&').replace('<', '<').replace('>', '>')
+ text_escaped = text.replace("&", "&").replace("<", "<").replace(">", ">")
- svg_content = f'''"""
# Write SVG file
filepath = os.path.join(assets_dir, filename)
- with open(filepath, 'w', encoding='utf-8') as f:
+ with open(filepath, "w", encoding="utf-8") as f:
f.write(svg_content)
return filename
@@ -134,13 +134,13 @@ def create_h2_svg_file(text, filename, assets_dir):
def create_h3_svg_file(text, filename, assets_dir):
"""Create an animated minimal-inline H3 header SVG file."""
# Escape XML special characters
- text_escaped = text.replace('&', '&').replace('<', '<').replace('>', '>')
+ text_escaped = text.replace("&", "&").replace("<", "<").replace(">", ">")
# Calculate approximate text width (rough estimate: 10px per character for 18px font)
text_width = len(text) * 10
total_width = text_width + 50 # Add padding for decorative elements
- svg_content = f'''
+ svg_content = f"""
@@ -175,11 +175,11 @@ def create_h3_svg_file(text, filename, assets_dir):
{text_escaped}
-'''
+"""
# Write SVG file
filepath = os.path.join(assets_dir, filename)
- with open(filepath, 'w', encoding='utf-8') as f:
+ with open(filepath, "w", encoding="utf-8") as f:
f.write(svg_content)
return filename
@@ -325,6 +325,7 @@ def get_anchor_suffix_for_icon(icon):
# SVG GENERATORS - Auto-generate assets for new categories/subcategories
# =============================================================================
+
def generate_category_header_light_svg(title, section_number="01"):
"""Generate a light-mode category header SVG in vintage technical manual style.
@@ -336,7 +337,7 @@ def generate_category_header_light_svg(title, section_number="01"):
title_width = len(title) * 14 # Approximate width per character
line_end_x = max(640, 220 + title_width + 50)
- return f'''
+ return f"""
-'''
+"""
def generate_section_divider_light_svg(variant=1):
@@ -390,7 +391,7 @@ def generate_section_divider_light_svg(variant=1):
"""
if variant == 1:
# Diagram/schematic style with nodes
- return '''
+ return """
@@ -443,11 +444,11 @@ def generate_section_divider_light_svg(variant=1):
-'''
+"""
elif variant == 2:
# Wave/organic style
- return '''
+ return """
@@ -477,11 +478,11 @@ def generate_section_divider_light_svg(variant=1):
-'''
+"""
else: # variant == 3
# Bracket style with layered drafts
- return '''
+ return """
@@ -523,7 +524,7 @@ def generate_section_divider_light_svg(variant=1):
-'''
+"""
def generate_desc_box_light_svg(position="top"):
@@ -533,7 +534,7 @@ def generate_desc_box_light_svg(position="top"):
position: "top" or "bottom"
"""
if position == "top":
- return '''
+ return """
@@ -591,9 +592,9 @@ def generate_desc_box_light_svg(position="top"):
-'''
+"""
else: # bottom
- return '''
+ return """
@@ -650,7 +651,7 @@ def generate_desc_box_light_svg(position="top"):
-'''
+"""
def generate_toc_row_svg(directory_name, description):
@@ -661,10 +662,10 @@ def generate_toc_row_svg(directory_name, description):
description: Short description for the comment
"""
# Escape XML entities
- desc_escaped = description.replace('&', '&').replace('<', '<').replace('>', '>')
- dir_escaped = directory_name.replace('&', '&').replace('<', '<').replace('>', '>')
+ desc_escaped = description.replace("&", "&").replace("<", "<").replace(">", ">")
+ dir_escaped = directory_name.replace("&", "&").replace("<", "<").replace(">", ">")
- return f'''
+ return f"""
@@ -707,7 +708,7 @@ def generate_toc_row_svg(directory_name, description):
# {desc_escaped}
-'''
+"""
def generate_toc_sub_svg(directory_name, description):
@@ -717,10 +718,10 @@ def generate_toc_sub_svg(directory_name, description):
directory_name: The subdirectory name (e.g., "general/")
description: Short description for the comment
"""
- desc_escaped = description.replace('&', '&').replace('<', '<').replace('>', '>')
- dir_escaped = directory_name.replace('&', '&').replace('<', '<').replace('>', '>')
+ desc_escaped = description.replace("&", "&").replace("<", "<").replace(">", ">")
+ dir_escaped = directory_name.replace("&", "&").replace("<", "<").replace(">", ">")
- return f'''
+ return f"""
@@ -757,20 +758,21 @@ def generate_toc_sub_svg(directory_name, description):
# {desc_escaped}
-'''
+"""
# =============================================================================
# ASSET SAVING HELPERS - Save generated assets to disk
# =============================================================================
+
def ensure_category_header_exists(category_id, title, section_number, assets_dir):
"""Ensure category header SVGs exist, generating them if needed.
Returns tuple of (dark_filename, light_filename).
"""
# Define filenames
- safe_name = category_id.replace('-', '_')
+ safe_name = category_id.replace("-", "_")
dark_filename = f"header_{safe_name}.svg"
light_filename = f"header_{safe_name}-light-v3.svg"
@@ -778,7 +780,7 @@ def ensure_category_header_exists(category_id, title, section_number, assets_dir
light_path = os.path.join(assets_dir, light_filename)
if not os.path.exists(light_path):
svg_content = generate_category_header_light_svg(title, section_number)
- with open(light_path, 'w', encoding='utf-8') as f:
+ with open(light_path, "w", encoding="utf-8") as f:
f.write(svg_content)
return (dark_filename, light_filename)
@@ -795,7 +797,7 @@ def ensure_section_divider_exists(variant, assets_dir):
light_path = os.path.join(assets_dir, light_filename)
if not os.path.exists(light_path):
svg_content = generate_section_divider_light_svg(variant)
- with open(light_path, 'w', encoding='utf-8') as f:
+ with open(light_path, "w", encoding="utf-8") as f:
f.write(svg_content)
return (dark_filename, light_filename)
@@ -812,7 +814,7 @@ def ensure_desc_box_exists(position, assets_dir):
if not os.path.exists(filepath):
svg_content = generate_desc_box_light_svg(position)
- with open(filepath, 'w', encoding='utf-8') as f:
+ with open(filepath, "w", encoding="utf-8") as f:
f.write(svg_content)
return filename
@@ -825,7 +827,7 @@ def ensure_toc_row_exists(category_id, directory_name, description, assets_dir):
if not os.path.exists(filepath):
svg_content = generate_toc_row_svg(directory_name, description)
- with open(filepath, 'w', encoding='utf-8') as f:
+ with open(filepath, "w", encoding="utf-8") as f:
f.write(svg_content)
return filename
@@ -838,7 +840,7 @@ def ensure_toc_sub_exists(subcat_id, directory_name, description, assets_dir):
if not os.path.exists(filepath):
svg_content = generate_toc_sub_svg(directory_name, description)
- with open(filepath, 'w', encoding='utf-8') as f:
+ with open(filepath, "w", encoding="utf-8") as f:
f.write(svg_content)
return filename
@@ -848,57 +850,69 @@ def ensure_toc_sub_exists(subcat_id, directory_name, description, assets_dir):
# MAPPING FUNCTIONS - Map IDs to filenames
# =============================================================================
+
def get_category_svg_filename(category_id):
"""Map category ID to SVG filename."""
svg_map = {
- 'skills': 'toc-row-skills.svg',
- 'workflows': 'toc-row-workflows.svg',
- 'tooling': 'toc-row-tooling.svg',
- 'statusline': 'toc-row-statusline.svg',
- 'hooks': 'toc-row-custom.svg',
- 'slash-commands': 'toc-row-commands.svg',
- 'claude-md-files': 'toc-row-config.svg',
- 'alternative-clients': 'toc-row-clients.svg',
- 'official-documentation': 'toc-row-docs.svg',
+ "skills": "toc-row-skills.svg",
+ "workflows": "toc-row-workflows.svg",
+ "tooling": "toc-row-tooling.svg",
+ "statusline": "toc-row-statusline.svg",
+ "hooks": "toc-row-custom.svg",
+ "slash-commands": "toc-row-commands.svg",
+ "claude-md-files": "toc-row-config.svg",
+ "alternative-clients": "toc-row-clients.svg",
+ "official-documentation": "toc-row-docs.svg",
}
- return svg_map.get(category_id, f'toc-row-{category_id}.svg')
+ return svg_map.get(category_id, f"toc-row-{category_id}.svg")
def get_subcategory_svg_filename(subcat_id):
"""Map subcategory ID to SVG filename."""
svg_map = {
- 'general': 'toc-sub-general.svg',
- 'ide-integrations': 'toc-sub-ide.svg',
- 'usage-monitors': 'toc-sub-monitors.svg',
- 'orchestrators': 'toc-sub-orchestrators.svg',
- 'version-control-git': 'toc-sub-git.svg',
- 'code-analysis-testing': 'toc-sub-code-analysis.svg',
- 'context-loading-priming': 'toc-sub-context.svg',
- 'documentation-changelogs': 'toc-sub-documentation.svg',
- 'ci-deployment': 'toc-sub-ci.svg',
- 'project-task-management': 'toc-sub-project-mgmt.svg',
- 'miscellaneous': 'toc-sub-misc.svg',
- 'language-specific': 'toc-sub-language.svg',
- 'domain-specific': 'toc-sub-domain.svg',
- 'project-scaffolding-mcp': 'toc-sub-scaffolding.svg',
+ "general": "toc-sub-general.svg",
+ "ide-integrations": "toc-sub-ide.svg",
+ "usage-monitors": "toc-sub-monitors.svg",
+ "orchestrators": "toc-sub-orchestrators.svg",
+ "version-control-git": "toc-sub-git.svg",
+ "code-analysis-testing": "toc-sub-code-analysis.svg",
+ "context-loading-priming": "toc-sub-context.svg",
+ "documentation-changelogs": "toc-sub-documentation.svg",
+ "ci-deployment": "toc-sub-ci.svg",
+ "project-task-management": "toc-sub-project-mgmt.svg",
+ "miscellaneous": "toc-sub-misc.svg",
+ "language-specific": "toc-sub-language.svg",
+ "domain-specific": "toc-sub-domain.svg",
+ "project-scaffolding-mcp": "toc-sub-scaffolding.svg",
}
- return svg_map.get(subcat_id, f'toc-sub-{subcat_id}.svg')
+ return svg_map.get(subcat_id, f"toc-sub-{subcat_id}.svg")
def get_category_header_svg(category_id):
"""Map category ID to pre-made header SVG filenames (dark and light variants)."""
header_map = {
- 'skills': ('header_agent_skills.svg', 'header_agent_skills-light-v3.svg'),
- 'workflows': ('header_workflows_knowledge_guides.svg', 'header_workflows_knowledge_guides-light-v3.svg'),
- 'tooling': ('header_tooling.svg', 'header_tooling-light-v3.svg'),
- 'statusline': ('header_status_lines.svg', 'header_status_lines-light-v3.svg'),
- 'hooks': ('header_hooks.svg', 'header_hooks-light-v3.svg'),
- 'slash-commands': ('header_slash_commands.svg', 'header_slash_commands-light-v3.svg'),
- 'claude-md-files': ('header_claudemd_files.svg', 'header_claudemd_files-light-v3.svg'),
- 'alternative-clients': ('header_alternative_clients.svg', 'header_alternative_clients-light-v3.svg'),
- 'official-documentation': ('header_official_documentation.svg', 'header_official_documentation-light-v3.svg'),
+ "skills": ("header_agent_skills.svg", "header_agent_skills-light-v3.svg"),
+ "workflows": (
+ "header_workflows_knowledge_guides.svg",
+ "header_workflows_knowledge_guides-light-v3.svg",
+ ),
+ "tooling": ("header_tooling.svg", "header_tooling-light-v3.svg"),
+ "statusline": ("header_status_lines.svg", "header_status_lines-light-v3.svg"),
+ "hooks": ("header_hooks.svg", "header_hooks-light-v3.svg"),
+ "slash-commands": ("header_slash_commands.svg", "header_slash_commands-light-v3.svg"),
+ "claude-md-files": ("header_claudemd_files.svg", "header_claudemd_files-light-v3.svg"),
+ "alternative-clients": (
+ "header_alternative_clients.svg",
+ "header_alternative_clients-light-v3.svg",
+ ),
+ "official-documentation": (
+ "header_official_documentation.svg",
+ "header_official_documentation-light-v3.svg",
+ ),
}
- return header_map.get(category_id, (f'header_{category_id}.svg', f'header_{category_id}-light-v3.svg'))
+ return header_map.get(
+ category_id, (f"header_{category_id}.svg", f"header_{category_id}-light-v3.svg")
+ )
# Global counter for cycling section dividers (light mode only)
@@ -914,7 +928,7 @@ def get_section_divider_svg():
global _section_divider_counter
variant = (_section_divider_counter % 3) + 1 # 1, 2, 3
_section_divider_counter += 1
- return ('section-divider-alt2.svg', f'section-divider-light-manual-v{variant}.svg')
+ return ("section-divider-alt2.svg", f"section-divider-light-manual-v{variant}.svg")
def sanitize_filename_from_anchor(anchor: str) -> str:
@@ -1003,14 +1017,18 @@ def generate_toc_from_categories(csv_data=None, general_map=None):
# Add main category row with theme-adaptive picture element
dark_svg = svg_filename
- light_svg = svg_filename.replace('.svg', '-light-anim-scanline.svg')
+ light_svg = svg_filename.replace(".svg", "-light-anim-scanline.svg")
toc_lines.append(f'')
- toc_lines.append(f' ')
- toc_lines.append(f' ')
- toc_lines.append(f' ')
+ toc_lines.append(" ")
+ toc_lines.append(
+ f' '
+ )
+ toc_lines.append(
+ f' '
+ )
toc_lines.append(f'
')
- toc_lines.append(f' ')
- toc_lines.append(f'')
+ toc_lines.append(" ")
+ toc_lines.append("")
toc_lines.append('
')
# Check if this category has subcategories
@@ -1061,14 +1079,18 @@ def generate_toc_from_categories(csv_data=None, general_map=None):
# Add subcategory row with theme-adaptive picture element
dark_svg = svg_filename
- light_svg = svg_filename.replace('.svg', '-light-anim-scanline.svg')
+ light_svg = svg_filename.replace(".svg", "-light-anim-scanline.svg")
toc_lines.append(f'')
- toc_lines.append(f' ')
- toc_lines.append(f' ')
- toc_lines.append(f' ')
+ toc_lines.append(" ")
+ toc_lines.append(
+ f' '
+ )
+ toc_lines.append(
+ f' '
+ )
toc_lines.append(f'
')
- toc_lines.append(f' ')
- toc_lines.append(f'')
+ toc_lines.append(" ")
+ toc_lines.append("")
toc_lines.append('
')
return "\n".join(toc_lines).strip()
@@ -1089,8 +1111,20 @@ def generate_resource_badge_svg(display_name, author_name=""):
initials = display_name[:2].upper()
# Escape XML special characters
- name_escaped = display_name.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"')
- author_escaped = author_name.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"') if author_name else ""
+ name_escaped = (
+ display_name.replace("&", "&")
+ .replace("<", "<")
+ .replace(">", ">")
+ .replace('"', """)
+ )
+ author_escaped = (
+ author_name.replace("&", "&")
+ .replace("<", "<")
+ .replace(">", ">")
+ .replace('"', """)
+ if author_name
+ else ""
+ )
# Calculate width based on text length (approximate) - larger fonts need more space
name_width = len(display_name) * 10
@@ -1104,10 +1138,10 @@ def generate_resource_badge_svg(display_name, author_name=""):
# Build author text element if author provided
author_element = ""
if author_name:
- author_element = f'''
- by {author_escaped}'''
+ author_element = f"""
+ by {author_escaped}"""
- svg = f'''
+ svg = f"""