@@ -148,31 +148,37 @@ def build_library_highlight_carousel(limit=3):
148148 """Per-slide content for the homepage 'Explore battle tested libraries'
149149 carousel.
150150
151- Shows the libraries an editor curated in HomepageSettings first (in random
152- order); when fewer than `limit` are curated, the remaining slots are filled
153- with random flagship/core libraries in the latest release. Returns a list
154- of dicts (name, category_tags, description, added_in_version, docs_url);
155- empty when no candidate library exists.
151+ Shows the libraries an editor curated in HomepageSettings; when fewer than
152+ `limit` are curated, the remaining slots are filled with random flagship/core
153+ libraries in the latest release (admins may curate more than `limit`). When
154+ admins curate libraries, their pinned order is preserved (fallback top-ups
155+ follow); with no pins, slides are ordered by description length for UI
156+ appearance. Returns a list of dicts (name, category_tags, description,
157+ added_in_version, docs_url); empty when no candidate library exists.
156158 """
157159 latest = Version .objects .most_recent ()
158- libraries = list (
159- HomepageSettings .load ()
160- .highlighted_libraries .prefetch_related ("categories" )
161- .order_by ("?" )
160+ highlighted_ids = list (
161+ HomepageSettings .load ().highlighted_libraries .values_list ("id" , flat = True )
162162 )
163+ library_ids = list (highlighted_ids )
163164
164- remaining_slots = limit - len (libraries )
165+ # Admins may curate more than `limit`; only top up when they curate fewer.
166+ remaining_slots = limit - len (highlighted_ids )
165167 if remaining_slots > 0 :
166- libraries += list (
168+ library_ids += list (
167169 Library .objects .filter (
168170 tier__in = FEATURED_LIBRARY_TIERS ,
169171 library_version__version = latest ,
170172 )
171- .exclude (id__in = [ lib . id for lib in libraries ] )
173+ .exclude (id__in = highlighted_ids )
172174 .distinct ()
173- .prefetch_related ( "categories " )
174- .order_by ( "?" )[:remaining_slots ]
175+ .order_by ( "? " )
176+ .values_list ( "id" , flat = True )[:remaining_slots ]
175177 )
178+
179+ libraries = Library .objects .filter (id__in = library_ids ).prefetch_related (
180+ "categories"
181+ )
176182 if not libraries :
177183 return []
178184
@@ -181,28 +187,45 @@ def build_library_highlight_carousel(limit=3):
181187 for lv in LibraryVersion .objects .filter (library__in = libraries , version = latest )
182188 }
183189
184- slides = []
190+ category_list_url = reverse (
191+ "libraries-list" ,
192+ kwargs = {"version_slug" : "latest" , "library_view_str" : "list" },
193+ )
194+
195+ slides_by_id = {}
185196 for library in libraries :
186197 lv = library_versions .get (library .id )
187198 first_version = library .first_boost_version
188- slides .append (
189- {
190- "name" : library .display_name_short ,
191- "category_tags" : library .category_tags ,
192- "description" : (
193- (lv .description if lv else None ) or library .description or ""
194- ),
195- "added_in_version" : (
196- first_version .display_name if first_version else ""
197- ),
198- "docs_url" : get_documentation_url (lv , latest = True ) if lv else "" ,
199- }
200- )
201- slides .sort (
199+ slides_by_id [library .id ] = {
200+ "name" : library .display_name_short ,
201+ "category_tags" : [
202+ (
203+ {
204+ ** tag ,
205+ "url" : f"{ category_list_url } ?category={ tag ['slug' ]} " ,
206+ "aria_label" : f"Browse { tag ['label' ]} libraries" ,
207+ }
208+ if tag ["slug" ]
209+ else tag
210+ )
211+ for tag in library .category_tags
212+ ],
213+ "description" : (
214+ (lv .description if lv else None ) or library .description or ""
215+ ),
216+ "added_in_version" : (first_version .display_name if first_version else "" ),
217+ "docs_url" : get_documentation_url (lv , latest = True ) if lv else "" ,
218+ }
219+
220+ if highlighted_ids :
221+ # Respect the admin's pinned order; fallback top-ups follow.
222+ return [slides_by_id [lib_id ] for lib_id in library_ids ]
223+ # No pins: order by description length, then category count, for looks.
224+ return sorted (
225+ slides_by_id .values (),
202226 key = lambda slide : (len (slide ["description" ]), len (slide ["category_tags" ])),
203227 reverse = True ,
204- ) # sort by description length, then category count, to improve UI appearance
205- return slides
228+ )
206229
207230
208231def build_library_intro ():
0 commit comments