33from mkdocs .plugins import BasePlugin , get_plugin_logger
44from mkdocs .config import config_options as c
55from mkdocs .structure .files import File
6- from mkdocs .structure .pages import Page
76
87
98log = get_plugin_logger (__name__ )
@@ -22,115 +21,103 @@ class AuthorsPlugin(BasePlugin):
2221
2322 def on_pre_build (self , config ):
2423 """
25- The 'on_pre_build' event is called once, before the documentation is built.
26- This is where we'll generate our authors page content.
24+ Generates the authors page content from the YAML file before the build.
2725 """
2826 authors_file_path = os .path .join (
2927 config ["docs_dir" ], ".." , self .config ["authors_file" ]
3028 )
31-
3229 authors_data = []
3330 page_parameters = {}
3431
35- if os .path .exists (authors_file_path ):
36- with open (authors_file_path , "r" , encoding = "utf-8" ) as f :
37- try :
38- raw_data = yaml .safe_load (f )
39-
40- if isinstance (raw_data , dict ):
41- if self .config ["page_params_key" ] in raw_data and isinstance (
42- raw_data [self .config ["page_params_key" ]], dict
43- ):
44- page_parameters = raw_data [self .config ["page_params_key" ]]
45-
46- if "authors" in raw_data and isinstance (
47- raw_data ["authors" ], dict
48- ):
49- for author_id , details in raw_data ["authors" ].items ():
50- details ["id" ] = author_id
51- authors_data .append (details )
52- else :
53- log .warning (
54- f"'{ self .config ['authors_file' ]} ' does not contain an 'authors' key at the top level, or it's not a dictionary. No authors will be listed."
55- )
56- authors_data = []
57- else :
58- log .warning (
59- f"'{ self .config ['authors_file' ]} ' should contain a dictionary at the top level. No authors or page parameters will be loaded."
60- )
61- authors_data = []
62- page_parameters = {}
63-
64- except yaml .YAMLError as e :
65- log .error (f"Error parsing '{ self .config ['authors_file' ]} ': { e } " )
66- authors_data = []
67- page_parameters = {}
68- else :
32+ if not os .path .exists (authors_file_path ):
6933 log .warning (
7034 f"Authors file not found at '{ authors_file_path } '. No authors page will be generated."
7135 )
7236 self .authors_markdown_content = "No authors file found. Please create a '.authors.yml' file in your project root."
7337 return
7438
75- page_title = page_parameters .get ("title" , "Our Amazing Authors" )
76- page_description = page_parameters .get ("description" )
39+ try :
40+ with open (authors_file_path , "r" , encoding = "utf-8" ) as f :
41+ raw_data = yaml .safe_load (f )
42+
43+ if isinstance (raw_data , dict ):
44+ potential_page_params = raw_data .get (self .config ["page_params_key" ])
45+ if isinstance (potential_page_params , dict ):
46+ page_parameters = potential_page_params
47+ else :
48+ log .warning (
49+ f"'{ self .config ['page_params_key' ]} ' in '{ self .config ['authors_file' ]} ' is not a dictionary. Page parameters will be ignored."
50+ )
51+ page_parameters = {}
52+
53+ authors_dict = raw_data .get ("authors" , {})
54+
55+ if isinstance (authors_dict , dict ):
56+ authors_data = [
57+ {"id" : aid , ** details } for aid , details in authors_dict .items ()
58+ ]
59+ else :
60+ log .warning (
61+ f"'{ self .config ['authors_file' ]} ' does not contain an 'authors' key as a dictionary. No authors will be listed."
62+ )
63+ else :
64+ log .warning (
65+ f"'{ self .config ['authors_file' ]} ' should contain a dictionary at the top level. No authors or page parameters will be loaded."
66+ )
67+ except yaml .YAMLError as e :
68+ log .error (f"Error parsing '{ self .config ['authors_file' ]} ': { e } " )
69+ except Exception as e :
70+ log .error (f"An unexpected error occurred while loading authors data: { e } " )
7771
78- # Get avatar styling from page_parameters, with defaults
72+ self ._generate_markdown_content (authors_data , page_parameters )
73+ log .info (f"Authors page content generated for '{ self .config ['output_page' ]} '." )
74+
75+ def _generate_markdown_content (self , authors_data , page_parameters ):
76+ """Helper to generate the markdown string."""
77+ page_title = page_parameters .get ("title" , "Our Amazing Authors" )
78+ page_description = page_parameters .get ("description" , "" )
7979 avatar_size = page_parameters .get ("avatar_size" , 100 )
8080 avatar_shape = page_parameters .get ("avatar_shape" , "square" )
81- avatar_align = page_parameters .get (
82- "avatar_align" , "center"
83- ) # Default to 'center'
81+ avatar_align = page_parameters .get ("avatar_align" , "center" )
8482
85- markdown_content = f"# { page_title } \n \n "
83+ markdown_parts = [ f"# { page_title } \n \n " ]
8684 if page_description :
87- markdown_content += f"{ page_description } \n \n "
85+ markdown_parts . append ( f"{ page_description } \n \n " )
8886
8987 if not authors_data :
90- markdown_content += "No authors found or an error occurred while loading the authors data.\n "
88+ markdown_parts .append (
89+ "No authors found or an error occurred while loading the authors data.\n "
90+ )
9191 else :
9292 for author in authors_data :
93- markdown_content += f"## { author .get ('name' , 'Unknown Author' )} \n "
94-
95- avatar_html = "" # Initialize avatar HTML for conditional placement
96- if author .get ("avatar" ):
97- avatar_url = author ["avatar" ]
98- author_name = author .get ("name" , "Avatar" )
99-
100- style_attributes = f"width: { avatar_size } px; height: { avatar_size } px; object-fit: cover;"
101- if avatar_shape == "circle" :
102- style_attributes += " border-radius: 50%;"
103- else : # Default or 'square'
104- style_attributes += " border-radius: 0;"
105-
106- if avatar_align == "left" :
107- style_attributes += (
108- " float: left; margin-right: 15px; margin-bottom: 10px;"
109- )
110- avatar_html = f'<img src="{ avatar_url } " alt="{ author_name } Avatar" style="{ style_attributes } ">'
111- elif avatar_align == "right" :
112- style_attributes += (
113- " float: right; margin-left: 15px; margin-bottom: 10px;"
93+ markdown_parts .append (f"## { author .get ('name' , 'Unknown Author' )} \n " )
94+
95+ avatar_html = self ._get_avatar_html (
96+ author , avatar_size , avatar_shape , avatar_align
97+ )
98+ if avatar_align not in [
99+ "left" ,
100+ "right" ,
101+ ]: # Center-aligned avatar needs to be handled as a block
102+ if avatar_html :
103+ markdown_parts .append (
104+ f'<p style="text-align: center;">{ avatar_html } </p>\n '
114105 )
115- avatar_html = f'<img src="{ avatar_url } " alt="{ author_name } Avatar" style="{ style_attributes } ">'
116- else : # 'center' or default
117- style_attributes += " display: block; margin: 0 auto 10px auto;" # Add bottom margin for spacing
118- # For center, wrap in a paragraph for block-level centering
119- avatar_html = f'<p style="text-align: center;"><img src="{ avatar_url } " alt="{ author_name } Avatar" style="{ style_attributes } "></p>'
106+ avatar_html = "" # Clear for other alignments
120107
121- # Insert avatar HTML
122- markdown_content += avatar_html
108+ # Add avatar for left/right float and then other details
109+ if avatar_html :
110+ markdown_parts .append (avatar_html )
123111
124- # Now add the textual details that might wrap around a floated image
125112 if author .get ("affiliation" ):
126- markdown_content += f"**Affiliation:** { author ['affiliation' ]} \n "
113+ markdown_parts . append ( f"**Affiliation:** { author ['affiliation' ]} \n " )
127114
128115 if author .get ("description" ):
129- markdown_content += f"\n { author ['description' ]} \n "
116+ markdown_parts . append ( f"\n { author ['description' ]} \n " )
130117
131118 if author .get ("email" ):
132- markdown_content += (
133- f"\n **Email:** [{ author ['email' ]} ](mailto:{ author ['email' ]} )\n "
119+ markdown_parts . append (
120+ f"\n **Email:** [{ author ['email' ]} ](mailto:{ author ['email' ]} )\n "
134121 )
135122
136123 social_links = []
@@ -148,26 +135,44 @@ def on_pre_build(self, config):
148135 )
149136
150137 if social_links :
151- markdown_content += (
138+ markdown_parts . append (
152139 "\n **Connect:** " + " | " .join (social_links ) + "\n "
153140 )
154141
155- # Clear float after each author block if avatar was floated
156142 if avatar_align in ["left" , "right" ]:
157- markdown_content += '<div style="clear: both;"></div>\n '
143+ markdown_parts . append ( '<div style="clear: both;"></div>\n ' )
158144
159- markdown_content += "\n ---\n \n "
145+ markdown_parts . append ( "\n ---\n \n " )
160146
161- self .authors_markdown_content = markdown_content
162- log .info (f"Authors page content generated for '{ self .config ['output_page' ]} '." )
147+ self .authors_markdown_content = "" .join (markdown_parts )
148+
149+ def _get_avatar_html (self , author , size , shape , align ):
150+ """Generates the HTML for the author's avatar."""
151+ if not author .get ("avatar" ):
152+ return ""
153+
154+ avatar_url = author ["avatar" ]
155+ author_name = author .get ("name" , "Avatar" )
156+
157+ style_attributes = f"width: { size } px; height: { size } px; object-fit: cover;"
158+ style_attributes += (
159+ " border-radius: 50%;" if shape == "circle" else " border-radius: 0;"
160+ )
161+
162+ if align == "left" :
163+ style_attributes += " float: left; margin-right: 15px; margin-bottom: 10px;"
164+ elif align == "right" :
165+ style_attributes += " float: right; margin-left: 15px; margin-bottom: 10px;"
166+ elif align == "center" :
167+ style_attributes += " display: block; margin: 0 auto 10px auto;"
168+
169+ return f'<img src="{ avatar_url } " alt="{ author_name } Avatar" style="{ style_attributes } ">'
163170
164171 def on_files (self , files , config ):
165172 """
166- The 'on_files' event is called after the files are gathered.
167- We need to ensure our generated authors.md file is included in the build.
173+ Ensures the generated authors.md file is included in the MkDocs build.
168174 """
169175 output_page_name = self .config ["output_page" ]
170-
171176 if not any (f .src_path == output_page_name for f in files ):
172177 generated_file = File (
173178 path = output_page_name ,
@@ -181,8 +186,7 @@ def on_files(self, files, config):
181186
182187 def on_page_read_source (self , page , config ):
183188 """
184- The 'on_page_read_source' event is called when MkDocs reads the source
185- for a page. We'll intercept our generated page and provide its content.
189+ Intercepts the generated page and provides its content.
186190 """
187191 output_page_name = self .config ["output_page" ]
188192 if page .file .src_path == output_page_name :
0 commit comments