From 5a8e68655ff0e0d201ad8fee86259ed35b441ae1 Mon Sep 17 00:00:00 2001 From: Dariusz L Date: Fri, 5 Jun 2026 05:53:39 +0200 Subject: [PATCH] refactor: rename Model Linker to Model Resolver Replace all link dialog terminology with resolver terminology throughout the codebase, including module names, CSS classes, IDs, JS variables, SVG gradient IDs, and log module names. Remove the old web/linker/ tree and introduce the new web/resolver/ tree with parallel structure. Also replace core/linker.py with core/resolver.py. --- README.md | 14 +- __init__.py | 126 +- core/__init__.py | 4 +- core/downloader.py | 32 +- core/log_system/config.py | 4 +- core/{linker.py => resolver.py} | 4 +- core/scanner.py | 6 +- core/sources/lora_manager_archive.py | 4 +- core/sources/model_list.py | 2 +- core/workflow_analyzer.py | 6 +- web/css/css-variables.css | 394 +-- .../{linker-main.css => resolver-main.css} | 3026 ++++++++--------- .../{linker-shell.css => resolver-shell.css} | 270 +- web/linker.js | 18 - web/log_system/config.js | 6 +- web/resolver.js | 18 + .../actions/queue_methods.js | 152 +- .../actions/resolve_download_methods.js | 126 +- .../actions/selection_methods.js | 10 +- web/{linker => resolver}/globals.js | 30 +- .../model_resolver.js} | 188 +- .../resolver_dialog.js} | 40 +- .../search/download_target_methods.js | 68 +- .../search/search_panel.js | 184 +- .../shell/dialog_shell_methods.js | 84 +- .../shell/lifecycle_graph_methods.js | 34 +- .../shell/workflow_state_methods.js | 10 +- .../shell/workflow_update_methods.js | 8 +- .../utils/render_format_methods.js | 36 +- .../views/missing_browser_methods.js | 190 +- .../views/model_info_methods.js | 198 +- .../views/options_methods.js | 450 +-- .../views/tabs_loaded_methods.js | 94 +- web/utils/css_loader.js | 6 +- web/utils/icon_utils.js | 6 +- 35 files changed, 2924 insertions(+), 2924 deletions(-) rename core/{linker.py => resolver.py} (99%) rename web/css/{linker-main.css => resolver-main.css} (50%) rename web/css/{linker-shell.css => resolver-shell.css} (65%) delete mode 100644 web/linker.js create mode 100644 web/resolver.js rename web/{linker => resolver}/actions/queue_methods.js (86%) rename web/{linker => resolver}/actions/resolve_download_methods.js (93%) rename web/{linker => resolver}/actions/selection_methods.js (96%) rename web/{linker => resolver}/globals.js (83%) rename web/{linker/model_linker.js => resolver/model_resolver.js} (77%) rename web/{linker/linker_dialog.js => resolver/resolver_dialog.js} (83%) rename web/{linker => resolver}/search/download_target_methods.js (87%) rename web/{linker => resolver}/search/search_panel.js (88%) rename web/{linker => resolver}/shell/dialog_shell_methods.js (88%) rename web/{linker => resolver}/shell/lifecycle_graph_methods.js (93%) rename web/{linker => resolver}/shell/workflow_state_methods.js (95%) rename web/{linker => resolver}/shell/workflow_update_methods.js (91%) rename web/{linker => resolver}/utils/render_format_methods.js (84%) rename web/{linker => resolver}/views/missing_browser_methods.js (86%) rename web/{linker => resolver}/views/model_info_methods.js (80%) rename web/{linker => resolver}/views/options_methods.js (65%) rename web/{linker => resolver}/views/tabs_loaded_methods.js (76%) diff --git a/README.md b/README.md index d3aae3e..d78cff4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -

ModelLinker – Relink missing models and download from HuggingFace/CivitAI

+

ModelResolver – Relink missing models and download from HuggingFace/CivitAI

-

ModelLinker is a powerful ComfyUI extension for automatically resolving missing models in loaded workflows. It features intelligent local fuzzy matching, direct cloud downloads, background download tracking, and automated in-place workflow updating.

+

ModelResolver is a powerful ComfyUI extension for automatically resolving missing models in loaded workflows. It features intelligent local fuzzy matching, direct cloud downloads, background download tracking, and automated in-place workflow updating.

> [!WARNING] > **WIP (Work in Progress) — Download and use at your own risk!** @@ -9,8 +9,8 @@

ComfyUI - - License + + License Python 3.10+ JavaScript @@ -51,7 +51,7 @@ ## 📂 Supported Nodes & Model Types -Model Linker supports standard ComfyUI mechanisms as well as custom implementations of popular loader nodes: +Model Resolver supports standard ComfyUI mechanisms as well as custom implementations of popular loader nodes: * **Standard loaders**: CheckpointLoader, LoraLoader, VAELoader, ControlNetLoader, UpscaleModelLoader, etc. * **Advanced loaders**: Nodes from the `LoraManager` suite (`LoraLoaderV2`, `Lora Loader`, `Lora Stacker`), `rgthree` (`Power Lora Loader`), and LTX-Video nodes. * **Subgraphs**: Full support for scanning and updating nodes inside nested group subgraphs. @@ -73,7 +73,7 @@ In the extension settings panel, you can configure API keys and authorization to ## ⚡ Installation ### Install via ComfyUI-Manager -1. Search `ComfyUI Model Linker` in ComfyUI-Manager and click the `Install` button. +1. Search `ComfyUI Model Resolver` in ComfyUI-Manager and click the `Install` button. 2. Restart ComfyUI. ### Manual Install @@ -83,7 +83,7 @@ In the extension settings panel, you can configure API keys and authorization to ``` 2. Clone this repository: ```bash - git clone https://github.com/Azornes/comfyui-model-linker.git + git clone https://github.com/Azornes/comfyui-model-resolver.git ``` 3. Start or restart ComfyUI. The extension will automatically install any missing dependencies (`requests`, `aiohttp`) and load the web interface. diff --git a/__init__.py b/__init__.py index 43187a4..35ee49b 100644 --- a/__init__.py +++ b/__init__.py @@ -1,9 +1,9 @@ -""" -@author: Model Linker Team -@title: ComfyUI Model Linker -@nickname: Model Linker +""" +@author: Model Resolver Team +@title: ComfyUI Model Resolver +@nickname: Model Resolver @version: 1.1.0 -@description: Extension for relinking missing models and downloading from HuggingFace/CivitAI +@description: Extension for resolving missing models and downloading from HuggingFace/CivitAI """ import asyncio @@ -24,8 +24,8 @@ NODE_CLASS_MAPPINGS = {} __all__ = ["WEB_DIRECTORY"] -class ModelLinkerExtension: - """Main extension class for Model Linker.""" +class ModelResolverExtension: + """Main extension class for Model Resolver.""" def __init__(self): self.routes_setup = False @@ -36,14 +36,14 @@ class ModelLinkerExtension: """Initialize the extension and set up API routes.""" try: self.setup_routes() - self.logger.info("Model Linker: Extension initialized successfully") + self.logger.info("Model Resolver: Extension initialized successfully") except Exception as e: self.logger.error( - f"Model Linker: Extension initialization failed: {e}", exc_info=True + f"Model Resolver: Extension initialization failed: {e}", exc_info=True ) def setup_routes(self): - """Register API routes for the Model Linker extension.""" + """Register API routes for the Model Resolver extension.""" if self.routes_setup: return # Already set up @@ -58,24 +58,24 @@ class ModelLinkerExtension: not hasattr(PromptServer, "instance") or PromptServer.instance is None ): - self.logger.debug("Model Linker: PromptServer not available yet") + self.logger.debug("Model Resolver: PromptServer not available yet") return False routes = PromptServer.instance.routes except (ImportError, AttributeError) as e: - self.logger.debug(f"Model Linker: Could not access PromptServer: {e}") + self.logger.debug(f"Model Resolver: Could not access PromptServer: {e}") return False - # Import linker modules + # Import resolver modules try: - from .core.linker import ( + from .core.resolver import ( analyze_and_find_matches, apply_resolution, search_local_matches, ) from .core.scanner import get_model_files except ImportError as e: - self.logger.error(f"Model Linker: Could not import core modules: {e}") + self.logger.error(f"Model Resolver: Could not import core modules: {e}") return False # Import download modules @@ -129,13 +129,13 @@ class ModelLinkerExtension: download_available = True except ImportError as e: self.logger.warning( - f"Model Linker: Download features not available: {e}" + f"Model Resolver: Download features not available: {e}" ) download_available = False # ==================== ANALYZE ROUTES ==================== - @routes.post("/model_linker/analyze") + @routes.post("/model_resolver/analyze") async def analyze_workflow(request): """Analyze workflow and return missing models with matches.""" try: @@ -310,7 +310,7 @@ class ModelLinkerExtension: continue # NOTE: Search for online sources (HuggingFace, CivitAI) is - # now done on-demand via /model_linker/search endpoint + # now done on-demand via /model_resolver/search endpoint # when user clicks "Search Online" button, not automatically if analysis_id: @@ -333,10 +333,10 @@ class ModelLinkerExtension: "current": 0, "total": 0, } - self.logger.error(f"Model Linker analyze error: {e}", exc_info=True) + self.logger.error(f"Model Resolver analyze error: {e}", exc_info=True) return web.json_response({"error": str(e)}, status=500) - @routes.get("/model_linker/analyze-progress/{analysis_id}") + @routes.get("/model_resolver/analyze-progress/{analysis_id}") async def get_analyze_progress(request): """Get workflow analysis progress.""" analysis_id = request.match_info.get("analysis_id", "").strip() @@ -359,7 +359,7 @@ class ModelLinkerExtension: return web.json_response(progress) - @routes.post("/model_linker/resolve") + @routes.post("/model_resolver/resolve") async def resolve_models(request): """Apply model resolution and return updated workflow.""" try: @@ -384,12 +384,12 @@ class ModelLinkerExtension: {"workflow": updated_workflow, "success": True} ) except Exception as e: - self.logger.error(f"Model Linker resolve error: {e}", exc_info=True) + self.logger.error(f"Model Resolver resolve error: {e}", exc_info=True) return web.json_response( {"error": str(e), "success": False}, status=500 ) - @routes.post("/model_linker/local-matches") + @routes.post("/model_resolver/local-matches") async def local_matches(request): """Search local model files by filename/path.""" try: @@ -411,11 +411,11 @@ class ModelLinkerExtension: return web.json_response({"matches": matches}) except Exception as e: self.logger.error( - f"Model Linker local-matches error: {e}", exc_info=True + f"Model Resolver local-matches error: {e}", exc_info=True ) return web.json_response({"error": str(e)}, status=500) - @routes.post("/model_linker/open-containing-folder") + @routes.post("/model_resolver/open-containing-folder") async def open_containing_folder(request): """Open Explorer at the folder containing the selected model.""" try: @@ -448,12 +448,12 @@ class ModelLinkerExtension: return web.json_response({"success": True}) except Exception as e: self.logger.error( - f"Model Linker open-containing-folder error: {e}", + f"Model Resolver open-containing-folder error: {e}", exc_info=True, ) return web.json_response({"error": str(e)}, status=500) - @routes.get("/model_linker/models") + @routes.get("/model_resolver/models") async def get_models(request): """Get list of all available models.""" try: @@ -461,11 +461,11 @@ class ModelLinkerExtension: return web.json_response(models) except Exception as e: self.logger.error( - f"Model Linker get_models error: {e}", exc_info=True + f"Model Resolver get_models error: {e}", exc_info=True ) return web.json_response({"error": str(e)}, status=500) - @routes.post("/model_linker/loaded") + @routes.post("/model_resolver/loaded") async def get_loaded_models(request): """Get all currently loaded models in the workflow.""" try: @@ -656,13 +656,13 @@ class ModelLinkerExtension: except Exception as e: self.logger.error( - f"Model Linker get_loaded_models error: {e}", exc_info=True + f"Model Resolver get_loaded_models error: {e}", exc_info=True ) return web.json_response({"error": str(e)}, status=500) # ==================== CIVITAI SEARCH ROUTE ==================== - @routes.post("/model_linker/civitai-search") + @routes.post("/model_resolver/civitai-search") async def civitai_search(request): """Search CivitAI for a model using file hash.""" try: @@ -786,7 +786,7 @@ class ModelLinkerExtension: except Exception as e: self.logger.error( - f"Model Linker civitai-search error: {e}", exc_info=True + f"Model Resolver civitai-search error: {e}", exc_info=True ) return web.json_response({"error": str(e)}, status=500) @@ -794,7 +794,7 @@ class ModelLinkerExtension: if download_available: - @routes.post("/model_linker/search") + @routes.post("/model_resolver/search") async def search_sources(request): """Search for model download sources.""" try: @@ -1257,10 +1257,10 @@ class ModelLinkerExtension: return web.json_response(results) except Exception as e: - log_exception(f"Model Linker search error: {e}") + log_exception(f"Model Resolver search error: {e}") return web.json_response({"error": str(e)}, status=500) - @routes.post("/model_linker/clear-search-cache") + @routes.post("/model_resolver/clear-search-cache") async def clear_search_cache_route(request): """Clear backend search caches after token/settings changes.""" try: @@ -1274,7 +1274,7 @@ class ModelLinkerExtension: log_exception(f"Clear search cache error: {e}") return web.json_response({"error": str(e)}, status=500) - @routes.post("/model_linker/civitai/session-token/check") + @routes.post("/model_resolver/civitai/session-token/check") async def civitai_session_token_check_route(request): """Check whether a CivitAI browser session token is valid.""" try: @@ -1288,7 +1288,7 @@ class ModelLinkerExtension: log_exception(f"CivitAI session token check error: {e}") return web.json_response({"error": str(e)}, status=500) - @routes.post("/model_linker/civitai/api-key/check") + @routes.post("/model_resolver/civitai/api-key/check") async def civitai_api_key_check_route(request): """Check whether a CivitAI API key is valid.""" try: @@ -1302,7 +1302,7 @@ class ModelLinkerExtension: log_exception(f"CivitAI API key check error: {e}") return web.json_response({"error": str(e)}, status=500) - @routes.post("/model_linker/huggingface/token/check") + @routes.post("/model_resolver/huggingface/token/check") async def huggingface_token_check_route(request): """Check whether a HuggingFace token is valid.""" try: @@ -1314,7 +1314,7 @@ class ModelLinkerExtension: log_exception(f"HuggingFace token check error: {e}") return web.json_response({"error": str(e)}, status=500) - @routes.post("/model_linker/brave/api-key/check") + @routes.post("/model_resolver/brave/api-key/check") async def brave_api_key_check_route(request): """Check whether a Brave Search API key is valid.""" try: @@ -1328,7 +1328,7 @@ class ModelLinkerExtension: log_exception(f"Brave Search API key check error: {e}") return web.json_response({"error": str(e)}, status=500) - @routes.get("/model_linker/huggingface/author-index/status") + @routes.get("/model_resolver/huggingface/author-index/status") async def huggingface_author_index_status_route(request): """Return local HuggingFace author fallback index status.""" try: @@ -1337,7 +1337,7 @@ class ModelLinkerExtension: log_exception(f"HuggingFace author index status error: {e}") return web.json_response({"error": str(e)}, status=500) - @routes.post("/model_linker/huggingface/author-index/refresh") + @routes.post("/model_resolver/huggingface/author-index/refresh") async def huggingface_author_index_refresh_route(request): """Refresh HuggingFace author fallback index.""" try: @@ -1352,7 +1352,7 @@ class ModelLinkerExtension: log_exception(f"HuggingFace author index refresh error: {e}") return web.json_response({"error": str(e)}, status=500) - @routes.get("/model_linker/model-list/status") + @routes.get("/model_resolver/model-list/status") async def model_list_status_route(request): """Return local model-list status and optionally compare with GitHub.""" try: @@ -1367,7 +1367,7 @@ class ModelLinkerExtension: log_exception(f"Model list status error: {e}") return web.json_response({"error": str(e)}, status=500) - @routes.post("/model_linker/model-list/update") + @routes.post("/model_resolver/model-list/update") async def model_list_update_route(request): """Download latest ComfyUI-Manager model-list.json.""" try: @@ -1381,7 +1381,7 @@ class ModelLinkerExtension: log_exception(f"Model list update error: {e}") return web.json_response({"error": str(e)}, status=500) - @routes.post("/model_linker/download") + @routes.post("/model_resolver/download") async def download_model(request): """Start downloading a model.""" try: @@ -1441,13 +1441,13 @@ class ModelLinkerExtension: except Exception as e: self.logger.error( - f"Model Linker download error: {e}", exc_info=True + f"Model Resolver download error: {e}", exc_info=True ) return web.json_response( {"error": str(e), "success": False}, status=500 ) - @routes.get("/model_linker/progress/{download_id}") + @routes.get("/model_resolver/progress/{download_id}") async def get_download_progress(request): """Get progress for a specific download.""" try: @@ -1462,11 +1462,11 @@ class ModelLinkerExtension: ) except Exception as e: self.logger.error( - f"Model Linker progress error: {e}", exc_info=True + f"Model Resolver progress error: {e}", exc_info=True ) return web.json_response({"error": str(e)}, status=500) - @routes.get("/model_linker/progress") + @routes.get("/model_resolver/progress") async def get_all_downloads_progress(request): """Get progress for all downloads.""" try: @@ -1474,11 +1474,11 @@ class ModelLinkerExtension: return web.json_response(progress) except Exception as e: self.logger.error( - f"Model Linker progress error: {e}", exc_info=True + f"Model Resolver progress error: {e}", exc_info=True ) return web.json_response({"error": str(e)}, status=500) - @routes.post("/model_linker/cancel/{download_id}") + @routes.post("/model_resolver/cancel/{download_id}") async def cancel_download_route(request): """Cancel a download in progress.""" try: @@ -1487,13 +1487,13 @@ class ModelLinkerExtension: return web.json_response({"success": True}) except Exception as e: self.logger.error( - f"Model Linker cancel error: {e}", exc_info=True + f"Model Resolver cancel error: {e}", exc_info=True ) return web.json_response( {"error": str(e), "success": False}, status=500 ) - @routes.get("/model_linker/directories") + @routes.get("/model_resolver/directories") async def get_directories(request): """Get available model directories.""" try: @@ -1521,11 +1521,11 @@ class ModelLinkerExtension: return web.json_response(directories) except Exception as e: self.logger.error( - f"Model Linker directories error: {e}", exc_info=True + f"Model Resolver directories error: {e}", exc_info=True ) return web.json_response({"error": str(e)}, status=500) - @routes.get("/model_linker/capabilities") + @routes.get("/model_resolver/capabilities") async def get_capabilities(request): """Get optional source capabilities available in this install.""" try: @@ -1539,11 +1539,11 @@ class ModelLinkerExtension: ) except Exception as e: self.logger.error( - f"Model Linker capabilities error: {e}", exc_info=True + f"Model Resolver capabilities error: {e}", exc_info=True ) return web.json_response({"error": str(e)}, status=500) - @routes.get("/model_linker/subfolders/{category}") + @routes.get("/model_resolver/subfolders/{category}") async def get_subfolders(request): """Get known subfolders for a category using ComfyUI folder_paths.""" try: @@ -1579,7 +1579,7 @@ class ModelLinkerExtension: known_categories = set(folder_paths.folder_names_and_paths.keys()) if category not in known_categories: self.logger.debug( - f"Model Linker: skipping subfolder lookup for unknown category '{raw_category}' -> '{category}'" + f"Model Resolver: skipping subfolder lookup for unknown category '{raw_category}' -> '{category}'" ) return web.json_response([]) @@ -1599,31 +1599,31 @@ class ModelLinkerExtension: return web.json_response(sorted(subfolders)) except Exception as e: self.logger.error( - f"Model Linker subfolders error: {e}", exc_info=True + f"Model Resolver subfolders error: {e}", exc_info=True ) return web.json_response({"error": str(e)}, status=500) self.routes_setup = True - self.logger.info("Model Linker: API routes registered successfully") + self.logger.info("Model Resolver: API routes registered successfully") return True except ImportError as e: self.logger.warning( - f"Model Linker: Could not register routes (missing dependency): {e}" + f"Model Resolver: Could not register routes (missing dependency): {e}" ) return False except Exception as e: self.logger.error( - f"Model Linker: Error setting up routes: {e}", exc_info=True + f"Model Resolver: Error setting up routes: {e}", exc_info=True ) return False # Initialize the extension try: - extension = ModelLinkerExtension() + extension = ModelResolverExtension() extension.initialize() except Exception as e: log_error( - f"ComfyUI Model Linker extension initialization failed: {e}", exc_info=True + f"ComfyUI Model Resolver extension initialization failed: {e}", exc_info=True ) diff --git a/core/__init__.py b/core/__init__.py index a27d8b6..9c66869 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,5 +1,5 @@ """ -Core modules for Model Linker extension. +Core modules for Model Resolver extension. Modules: - linker: Main API for analyzing and resolving missing models @@ -13,7 +13,7 @@ Modules: from .log_system.log_funcs import log_debug, log_info, log_warn, log_error, log_exception from .log_system.logger import logger -from .linker import analyze_and_find_matches, apply_resolution +from .resolver import analyze_and_find_matches, apply_resolution from .scanner import get_model_files from .matcher import find_matches diff --git a/core/downloader.py b/core/downloader.py index 381e5c7..bc4f168 100644 --- a/core/downloader.py +++ b/core/downloader.py @@ -1,4 +1,4 @@ -""" +""" Model Downloader Module Handles downloading models from various sources with progress tracking. @@ -213,9 +213,9 @@ def download_file( if "civitai.com" in url else "URL" ) - print(f"\n[Model Linker] Starting download: {filename}") - print(f"[Model Linker] Source: {source}") - print(f"[Model Linker] URL: {url}") + print(f"\n[Model Resolver] Starting download: {filename}") + print(f"[Model Resolver] Source: {source}") + print(f"[Model Resolver] URL: {url}") # Start download response = requests.get(url, headers=headers, stream=True, timeout=30) @@ -224,7 +224,7 @@ def download_file( # Get total size total_size = int(response.headers.get("content-length", 0)) total_size_str = format_bytes(total_size) if total_size > 0 else "unknown" - print(f"[Model Linker] Size: {total_size_str}") + print(f"[Model Resolver] Size: {total_size_str}") with download_lock: download_progress[download_id]["total_size"] = total_size @@ -292,7 +292,7 @@ def download_file( ) speed_str = format_bytes(int(smoothed_speed)) + "/s" print( - f"[Model Linker] Progress: {downloaded_str} / {total_str} ({progress_pct}%) - {speed_str}" + f"[Model Resolver] Progress: {downloaded_str} / {total_str} ({progress_pct}%) - {speed_str}" ) else: # Just update downloaded bytes without recalculating speed @@ -316,13 +316,13 @@ def download_file( if os.path.exists(dest_path): os.remove(dest_path) print( - f"[Model Linker] Cancelled: {filename} - incomplete file deleted" + f"[Model Resolver] Cancelled: {filename} - incomplete file deleted" ) else: - print(f"[Model Linker] Cancelled: {filename} - no file to delete") + print(f"[Model Resolver] Cancelled: {filename} - no file to delete") except Exception as e: print( - f"[Model Linker] Warning: Could not delete incomplete file {dest_path}: {e}" + f"[Model Resolver] Warning: Could not delete incomplete file {dest_path}: {e}" ) # Try harder on Windows - sometimes the file handle takes a moment to release try: @@ -330,7 +330,7 @@ def download_file( if os.path.exists(dest_path): os.remove(dest_path) print( - f"[Model Linker] Cancelled: {filename} - incomplete file deleted (delayed)" + f"[Model Resolver] Cancelled: {filename} - incomplete file deleted (delayed)" ) except Exception: pass @@ -350,9 +350,9 @@ def download_file( # CLI completion log elapsed = time.time() - start_time avg_speed = downloaded / elapsed if elapsed > 0 else 0 - print(f"[Model Linker] ✓ Download complete: {filename}") + print(f"[Model Resolver] ✓ Download complete: {filename}") print( - f"[Model Linker] Size: {format_bytes(downloaded)}, Time: {elapsed:.1f}s, Avg speed: {format_bytes(int(avg_speed))}/s" + f"[Model Resolver] Size: {format_bytes(downloaded)}, Time: {elapsed:.1f}s, Avg speed: {format_bytes(int(avg_speed))}/s" ) except requests.exceptions.RequestException as e: @@ -378,8 +378,8 @@ def download_file( result["error"] = error_msg # CLI error log - print(f"[Model Linker] ✗ Download failed: {os.path.basename(dest_path)}") - print(f"[Model Linker] Error: {error_msg}") + print(f"[Model Resolver] ✗ Download failed: {os.path.basename(dest_path)}") + print(f"[Model Resolver] Error: {error_msg}") # Clean up partial file try: @@ -396,8 +396,8 @@ def download_file( result["error"] = error_msg # CLI error log - print(f"[Model Linker] ✗ Download failed: {os.path.basename(dest_path)}") - print(f"[Model Linker] Error: {error_msg}") + print(f"[Model Resolver] ✗ Download failed: {os.path.basename(dest_path)}") + print(f"[Model Resolver] Error: {error_msg}") log_error(f"Download error: {e}", exc_info=True) return result diff --git a/core/log_system/config.py b/core/log_system/config.py index 5ebe6e2..9829c15 100644 --- a/core/log_system/config.py +++ b/core/log_system/config.py @@ -1,4 +1,4 @@ -""" +""" @author: Azornes @title: AzLogs @version: 1.5.2 @@ -9,7 +9,7 @@ LOG_LEVEL = "DEBUG" # Logger module name. Set to None to auto-detect from folder name. -LOG_MODULE_NAME = "MLinker" +LOG_MODULE_NAME = "MResolver" # Enable ANSI colors in console logs. USE_COLORS = True diff --git a/core/linker.py b/core/resolver.py similarity index 99% rename from core/linker.py rename to core/resolver.py index 4e7d7e5..dec97f4 100644 --- a/core/linker.py +++ b/core/resolver.py @@ -1,5 +1,5 @@ -""" -Core Linker Module +""" +Core Resolver Module Integrates all components to provide high-level API for model linking. """ diff --git a/core/scanner.py b/core/scanner.py index 5bdfcf9..8ec5493 100644 --- a/core/scanner.py +++ b/core/scanner.py @@ -1,4 +1,4 @@ -""" +""" Directory Scanner Module Scans configured model directories and finds available model files. @@ -21,7 +21,7 @@ try: import folder_paths except ImportError: folder_paths = None - log_warn("Model Linker: folder_paths not available yet - will retry later") + log_warn("Model Resolver: folder_paths not available yet - will retry later") # Model file extensions to look for # This matches folder_paths.supported_pt_extensions @@ -61,7 +61,7 @@ def get_model_directories() -> Dict[str, Tuple[List[str], set]]: folder_paths = fp except ImportError: - log_error("Model Linker: folder_paths still not available") + log_error("Model Resolver: folder_paths still not available") return {} return folder_paths.folder_names_and_paths.copy() diff --git a/core/sources/lora_manager_archive.py b/core/sources/lora_manager_archive.py index 55674c9..02ab831 100644 --- a/core/sources/lora_manager_archive.py +++ b/core/sources/lora_manager_archive.py @@ -1,4 +1,4 @@ -""" +""" LoRA Manager Archive Source Module Search archived CivitAI metadata stored by comfyui-lora-manager. @@ -56,7 +56,7 @@ def get_lora_manager_archive_db_path() -> Optional[str]: if _db_path_cache is not None: return _db_path_cache if os.path.exists(_db_path_cache) else None - env_path = os.environ.get("MODEL_LINKER_LORA_MANAGER_ARCHIVE_DB", "").strip() + env_path = os.environ.get("model_resolver_LORA_MANAGER_ARCHIVE_DB", "").strip() candidates: List[str] = [] if env_path: candidates.append(env_path) diff --git a/core/sources/model_list.py b/core/sources/model_list.py index c1c28cf..863c65d 100644 --- a/core/sources/model_list.py +++ b/core/sources/model_list.py @@ -49,7 +49,7 @@ def _fetch_json_url(url: str) -> Dict[str, Any]: url, headers={ "Accept": "application/json", - "User-Agent": "comfyui-model-linker", + "User-Agent": "comfyui-model-resolver", }, ) with urlopen(request, timeout=HTTP_TIMEOUT) as response: diff --git a/core/workflow_analyzer.py b/core/workflow_analyzer.py index a90c283..61f387a 100644 --- a/core/workflow_analyzer.py +++ b/core/workflow_analyzer.py @@ -1,4 +1,4 @@ -""" +""" Workflow Analyzer Module Extracts model references from workflow JSON and identifies missing models. @@ -21,7 +21,7 @@ try: import folder_paths except ImportError: folder_paths = None - log_warn("Model Linker: folder_paths not available yet - will retry later") + log_warn("Model Resolver: folder_paths not available yet - will retry later") # Common model file extensions @@ -196,7 +196,7 @@ def try_resolve_model_path( folder_paths = fp except ImportError: - log_error("Model Linker: folder_paths not available") + log_error("Model Resolver: folder_paths not available") return None # If categories not provided, try all categories diff --git a/web/css/css-variables.css b/web/css/css-variables.css index 7f3cd01..78a5f0b 100644 --- a/web/css/css-variables.css +++ b/web/css/css-variables.css @@ -1,199 +1,199 @@ -:root { - --ml-color-primary: #5af; - --ml-color-primary-light: #7cf; - --ml-color-primary-lighter: #7bf; - --ml-color-success: #5f5; - --ml-color-error: #f00; - --ml-color-error-light: #f55; - --ml-color-error-lighter: #f77; - --ml-color-warning: #fa0; - --ml-color-white: #fff; - --ml-color-black: #000; - --ml-color-gray-100: #ddd; - --ml-color-gray-200: #ccc; - --ml-color-gray-300: #aaa; - --ml-color-gray-400: #999; - --ml-color-gray-500: #888; - --ml-color-gray-600: #666; - --ml-color-gray-700: #555; - --ml-color-gray-800: #444; - --ml-color-gray-900: #333; - --ml-color-bg-dark-1: #2a2a2a; - --ml-color-bg-dark-2: #1e1e1e; - --ml-color-bg-dark-3: #1a1a1a; - --ml-color-bg-dark-4: #0d0d0d; - --ml-color-bg-hover: #3a3a3a; - --ml-overlay-dark-20: rgba(0, 0, 0, 0.2); - --ml-overlay-dark-50: rgba(0, 0, 0, 0.5); - --ml-overlay-dark-70: rgba(0, 0, 0, 0.7); - --ml-overlay-dark-80: rgba(0, 0, 0, 0.8); - --ml-overlay-light-05: rgba(255, 255, 255, 0.05); - --ml-overlay-light-08: rgba(255, 255, 255, 0.08); - --ml-overlay-light-10: rgba(255, 255, 255, 0.1); - --ml-overlay-light-15: rgba(255, 255, 255, 0.15); - --ml-overlay-light-20: rgba(255, 255, 255, 0.2); - --ml-bg-primary-10: rgba(90, 170, 255, 0.1); - --ml-bg-primary-20: rgba(90, 170, 255, 0.2); - --ml-bg-primary-30: rgba(90, 170, 255, 0.3); - --ml-bg-primary-40: rgba(90, 170, 255, 0.4); - --ml-bg-primary-50: rgba(90, 170, 255, 0.5); - --ml-bg-success-10: rgba(80, 255, 80, 0.1); - --ml-bg-success-50: rgba(80, 255, 80, 0.5); - --ml-bg-error-10: rgba(255, 0, 0, 0.1); - --ml-bg-error-20: rgba(255, 0, 0, 0.2); - --ml-bg-gray-30: rgba(100, 100, 100, 0.3); - --ml-bg-gray-40: rgba(120, 120, 120, 0.4); - --ml-line-height-tight: 1.3; - --ml-line-height-normal: 1.5; - --ml-line-height-relaxed: 1.6; - --ml-line-height-editor: 19.5px; - --ml-width-dropdown-min: 250px; - --ml-width-dropdown-max: 400px; - --ml-width-input-inline-sm: 120px; - --ml-width-input-inline-md: 200px; - --ml-width-dialog-sm: 320px; - --ml-width-dialog-md: 800px; - --ml-z-dropdown: 9998; - --ml-z-dialog: 9999; - --ml-z-rename-dialog: 10000; - --ml-z-json-editor: 10001; - --ml-z-floating-button: 10000; - --ml-z-notification: 100000; - --ml-z-context-menu: 100001; - --ml-z-tooltip: 100002; - --ml-spacing-1: 1px; - --ml-spacing-2: 2px; - --ml-spacing-3: 3px; - --ml-spacing-4: 4px; - --ml-spacing-5: 5px; - --ml-spacing-6: 6px; - --ml-spacing-7: 7px; - --ml-spacing-8: 8px; - --ml-spacing-10: 10px; - --ml-spacing-12: 12px; - --ml-spacing-15: 15px; - --ml-spacing-16: 16px; - --ml-spacing-20: 20px; - --ml-spacing-24: 24px; - --ml-spacing-32: 32px; - --ml-spacing-40: 40px; - --ml-spacing-48: 48px; - --ml-radius-sm: 2px; - --ml-radius-md: 4px; - --ml-radius-lg: 6px; - --ml-radius-xl: 8px; - --ml-radius-2xl: 12px; - --ml-radius-3xl: 16px; - --ml-font-xs: 10px; - --ml-font-sm: 11px; - --ml-font-md: 12px; - --ml-font-base: 13px; - --ml-font-lg: 14px; - --ml-font-xl: 16px; - --ml-font-2xl: 18px; - --ml-font-3xl: 20px; - --ml-font-4xl: 24px; - --ml-font-5xl: 48px; - --ml-transition-fast: 0.1s; - --ml-transition-normal: 0.2s; - --ml-transition-all-fast: all 0.1s; - --ml-transition-all: all 0.2s; - --ml-transition-bg-fast: background 0.1s; - --ml-transition-bg: background 0.2s; - --ml-transition-color: color 0.2s; - --ml-transition-border: border-color 0.2s; - --ml-transition-opacity: opacity 0.2s; - --ml-shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.8); - --ml-gradient-dark: linear-gradient(135deg, var(--ml-color-bg-dark-1) 0%, var(--ml-color-bg-dark-2) 100%); - --ml-drag-color-reorder: var(--ml-color-primary); - --ml-drag-color-move: var(--ml-color-warning); - --ml-drag-color-error: var(--ml-color-error); - --ml-drag-color-clone: var(--ml-color-success); +:root { + --mr-color-primary: #5af; + --mr-color-primary-light: #7cf; + --mr-color-primary-lighter: #7bf; + --mr-color-success: #5f5; + --mr-color-error: #f00; + --mr-color-error-light: #f55; + --mr-color-error-lighter: #f77; + --mr-color-warning: #fa0; + --mr-color-white: #fff; + --mr-color-black: #000; + --mr-color-gray-100: #ddd; + --mr-color-gray-200: #ccc; + --mr-color-gray-300: #aaa; + --mr-color-gray-400: #999; + --mr-color-gray-500: #888; + --mr-color-gray-600: #666; + --mr-color-gray-700: #555; + --mr-color-gray-800: #444; + --mr-color-gray-900: #333; + --mr-color-bg-dark-1: #2a2a2a; + --mr-color-bg-dark-2: #1e1e1e; + --mr-color-bg-dark-3: #1a1a1a; + --mr-color-bg-dark-4: #0d0d0d; + --mr-color-bg-hover: #3a3a3a; + --mr-overlay-dark-20: rgba(0, 0, 0, 0.2); + --mr-overlay-dark-50: rgba(0, 0, 0, 0.5); + --mr-overlay-dark-70: rgba(0, 0, 0, 0.7); + --mr-overlay-dark-80: rgba(0, 0, 0, 0.8); + --mr-overlay-light-05: rgba(255, 255, 255, 0.05); + --mr-overlay-light-08: rgba(255, 255, 255, 0.08); + --mr-overlay-light-10: rgba(255, 255, 255, 0.1); + --mr-overlay-light-15: rgba(255, 255, 255, 0.15); + --mr-overlay-light-20: rgba(255, 255, 255, 0.2); + --mr-bg-primary-10: rgba(90, 170, 255, 0.1); + --mr-bg-primary-20: rgba(90, 170, 255, 0.2); + --mr-bg-primary-30: rgba(90, 170, 255, 0.3); + --mr-bg-primary-40: rgba(90, 170, 255, 0.4); + --mr-bg-primary-50: rgba(90, 170, 255, 0.5); + --mr-bg-success-10: rgba(80, 255, 80, 0.1); + --mr-bg-success-50: rgba(80, 255, 80, 0.5); + --mr-bg-error-10: rgba(255, 0, 0, 0.1); + --mr-bg-error-20: rgba(255, 0, 0, 0.2); + --mr-bg-gray-30: rgba(100, 100, 100, 0.3); + --mr-bg-gray-40: rgba(120, 120, 120, 0.4); + --mr-line-height-tight: 1.3; + --mr-line-height-normal: 1.5; + --mr-line-height-relaxed: 1.6; + --mr-line-height-editor: 19.5px; + --mr-width-dropdown-min: 250px; + --mr-width-dropdown-max: 400px; + --mr-width-input-inline-sm: 120px; + --mr-width-input-inline-md: 200px; + --mr-width-dialog-sm: 320px; + --mr-width-dialog-md: 800px; + --mr-z-dropdown: 9998; + --mr-z-dialog: 9999; + --mr-z-rename-dialog: 10000; + --mr-z-json-editor: 10001; + --mr-z-floating-button: 10000; + --mr-z-notification: 100000; + --mr-z-context-menu: 100001; + --mr-z-tooltip: 100002; + --mr-spacing-1: 1px; + --mr-spacing-2: 2px; + --mr-spacing-3: 3px; + --mr-spacing-4: 4px; + --mr-spacing-5: 5px; + --mr-spacing-6: 6px; + --mr-spacing-7: 7px; + --mr-spacing-8: 8px; + --mr-spacing-10: 10px; + --mr-spacing-12: 12px; + --mr-spacing-15: 15px; + --mr-spacing-16: 16px; + --mr-spacing-20: 20px; + --mr-spacing-24: 24px; + --mr-spacing-32: 32px; + --mr-spacing-40: 40px; + --mr-spacing-48: 48px; + --mr-radius-sm: 2px; + --mr-radius-md: 4px; + --mr-radius-lg: 6px; + --mr-radius-xl: 8px; + --mr-radius-2xl: 12px; + --mr-radius-3xl: 16px; + --mr-font-xs: 10px; + --mr-font-sm: 11px; + --mr-font-md: 12px; + --mr-font-base: 13px; + --mr-font-lg: 14px; + --mr-font-xl: 16px; + --mr-font-2xl: 18px; + --mr-font-3xl: 20px; + --mr-font-4xl: 24px; + --mr-font-5xl: 48px; + --mr-transition-fast: 0.1s; + --mr-transition-normal: 0.2s; + --mr-transition-all-fast: all 0.1s; + --mr-transition-all: all 0.2s; + --mr-transition-bg-fast: background 0.1s; + --mr-transition-bg: background 0.2s; + --mr-transition-color: color 0.2s; + --mr-transition-border: border-color 0.2s; + --mr-transition-opacity: opacity 0.2s; + --mr-shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.8); + --mr-gradient-dark: linear-gradient(135deg, var(--mr-color-bg-dark-1) 0%, var(--mr-color-bg-dark-2) 100%); + --mr-drag-color-reorder: var(--mr-color-primary); + --mr-drag-color-move: var(--mr-color-warning); + --mr-drag-color-error: var(--mr-color-error); + --mr-drag-color-clone: var(--mr-color-success); - --ml-bg: #121212; - --ml-bg-soft: #171717; - --ml-surface-elevated: #232323; - --ml-card-bg: #1a1a1a; - --ml-card-bg-alt: #1d1d1d; - --ml-panel-bg: #202020; - --ml-panel-bg-strong: #262626; - --ml-border: rgba(255, 255, 255, 0.08); - --ml-border-strong: rgba(255, 255, 255, 0.14); - --ml-divider: rgba(255, 255, 255, 0.08); - --ml-text: #f3f3f3; - --ml-text-muted: #b1b1b1; - --ml-text-dim: #7b7b7b; - --ml-text-soft: #dfdfdf; - --ml-accent: #72d38a; - --ml-accent-hover: #88de9e; - --ml-accent-blue: #72d38a; - --ml-warning: #e1b24d; - --ml-confidence-high: #72d38a; - --ml-confidence-medium: #e1b24d; - --ml-confidence-low: #e06a6a; - --ml-link-color: #d8d8d8; - --ml-shadow-elevated: 0 18px 42px rgba(0, 0, 0, 0.28); - --ml-ui-radius-sm: var(--ml-radius-xl); - --ml-ui-radius-md: var(--ml-radius-2xl); - --ml-ui-radius-lg: var(--ml-radius-3xl); - --ml-missing-control-bg: rgba(255, 255, 255, 0.035); - --ml-missing-control-bg-hover: rgba(255, 255, 255, 0.06); - --ml-missing-control-border: rgba(255, 255, 255, 0.105); - --ml-missing-control-border-hover: rgba(255, 255, 255, 0.17); - --ml-missing-control-focus-border: rgba(114, 211, 138, 0.30); - --ml-missing-control-focus-ring: rgba(114, 211, 138, 0.08); - --ml-missing-control-radius: 7px; - --ml-missing-control-shadow: none; - --ml-missing-control-transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease; - --ml-missing-icon-button-size: 28px; - --ml-missing-icon-size: 13px; - --ml-missing-field-height: 38px; - --ml-missing-search-button-height: 34px; - --ml-missing-chip-bg: rgba(255, 255, 255, 0.045); - --ml-missing-chip-bg-hover: rgba(255, 255, 255, 0.06); - --ml-missing-chip-border: rgba(255, 255, 255, 0.08); - --ml-missing-chip-border-hover: rgba(255, 255, 255, 0.18); - --ml-missing-chip-radius: 999px; - --ml-missing-chip-height: 20px; - --ml-missing-chip-icon-size: var(--ml-spacing-12); - --ml-type-chip-bg-alpha-strong: 0.155; - --ml-type-chip-bg-alpha: 0.12; - --ml-type-chip-border-alpha: 0.26; - --ml-type-chip-glow-alpha: 0.045; - --ml-type-generic-rgb: 176, 176, 176; - --ml-type-generic-text: #d6d6d6; - --ml-type-model-rgb: 179, 157, 219; - --ml-type-model-text: #dbcfff; - --ml-type-lora-rgb: 194, 255, 174; - --ml-type-lora-text: #d7ffcb; - --ml-type-style-model-rgb: 194, 255, 174; - --ml-type-style-model-text: #d7ffcb; - --ml-type-clip-rgb: 255, 213, 0; - --ml-type-clip-text: #ffe678; - --ml-type-clip-vision-rgb: 168, 218, 220; - --ml-type-clip-vision-text: #c7eff0; - --ml-type-clip-vision-output-rgb: 173, 116, 82; - --ml-type-clip-vision-output-text: #e8b79a; - --ml-type-conditioning-rgb: 255, 169, 49; - --ml-type-conditioning-text: #ffd08c; - --ml-type-controlnet-rgb: 110, 231, 183; - --ml-type-controlnet-text: #b1f4db; - --ml-type-image-rgb: 100, 181, 246; - --ml-type-image-text: #b9dcff; - --ml-type-latent-rgb: 255, 156, 249; - --ml-type-latent-text: #ffc8fb; - --ml-type-mask-rgb: 129, 199, 132; - --ml-type-mask-text: #bdebc0; - --ml-type-vae-rgb: 255, 110, 110; - --ml-type-vae-text: #ffb8b8; - --ml-type-noise-rgb: 176, 176, 176; - --ml-type-noise-text: #d6d6d6; - --ml-type-sampler-rgb: 236, 180, 180; - --ml-type-sampler-text: #f2cccc; - --ml-type-sigmas-rgb: 205, 255, 205; - --ml-type-sigmas-text: #dcffdc; - --ml-type-guider-rgb: 102, 255, 255; - --ml-type-guider-text: #c7ffff; - --ml-type-taesd-rgb: 220, 194, 116; - --ml-type-taesd-text: #efd991; + --mr-bg: #121212; + --mr-bg-soft: #171717; + --mr-surface-elevated: #232323; + --mr-card-bg: #1a1a1a; + --mr-card-bg-alt: #1d1d1d; + --mr-panel-bg: #202020; + --mr-panel-bg-strong: #262626; + --mr-border: rgba(255, 255, 255, 0.08); + --mr-border-strong: rgba(255, 255, 255, 0.14); + --mr-divider: rgba(255, 255, 255, 0.08); + --mr-text: #f3f3f3; + --mr-text-muted: #b1b1b1; + --mr-text-dim: #7b7b7b; + --mr-text-soft: #dfdfdf; + --mr-accent: #72d38a; + --mr-accent-hover: #88de9e; + --mr-accent-blue: #72d38a; + --mr-warning: #e1b24d; + --mr-confidence-high: #72d38a; + --mr-confidence-medium: #e1b24d; + --mr-confidence-low: #e06a6a; + --mr-link-color: #d8d8d8; + --mr-shadow-elevated: 0 18px 42px rgba(0, 0, 0, 0.28); + --mr-ui-radius-sm: var(--mr-radius-xl); + --mr-ui-radius-md: var(--mr-radius-2xl); + --mr-ui-radius-lg: var(--mr-radius-3xl); + --mr-missing-control-bg: rgba(255, 255, 255, 0.035); + --mr-missing-control-bg-hover: rgba(255, 255, 255, 0.06); + --mr-missing-control-border: rgba(255, 255, 255, 0.105); + --mr-missing-control-border-hover: rgba(255, 255, 255, 0.17); + --mr-missing-control-focus-border: rgba(114, 211, 138, 0.30); + --mr-missing-control-focus-ring: rgba(114, 211, 138, 0.08); + --mr-missing-control-radius: 7px; + --mr-missing-control-shadow: none; + --mr-missing-control-transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease; + --mr-missing-icon-button-size: 28px; + --mr-missing-icon-size: 13px; + --mr-missing-field-height: 38px; + --mr-missing-search-button-height: 34px; + --mr-missing-chip-bg: rgba(255, 255, 255, 0.045); + --mr-missing-chip-bg-hover: rgba(255, 255, 255, 0.06); + --mr-missing-chip-border: rgba(255, 255, 255, 0.08); + --mr-missing-chip-border-hover: rgba(255, 255, 255, 0.18); + --mr-missing-chip-radius: 999px; + --mr-missing-chip-height: 20px; + --mr-missing-chip-icon-size: var(--mr-spacing-12); + --mr-type-chip-bg-alpha-strong: 0.155; + --mr-type-chip-bg-alpha: 0.12; + --mr-type-chip-border-alpha: 0.26; + --mr-type-chip-glow-alpha: 0.045; + --mr-type-generic-rgb: 176, 176, 176; + --mr-type-generic-text: #d6d6d6; + --mr-type-model-rgb: 179, 157, 219; + --mr-type-model-text: #dbcfff; + --mr-type-lora-rgb: 194, 255, 174; + --mr-type-lora-text: #d7ffcb; + --mr-type-style-model-rgb: 194, 255, 174; + --mr-type-style-model-text: #d7ffcb; + --mr-type-clip-rgb: 255, 213, 0; + --mr-type-clip-text: #ffe678; + --mr-type-clip-vision-rgb: 168, 218, 220; + --mr-type-clip-vision-text: #c7eff0; + --mr-type-clip-vision-output-rgb: 173, 116, 82; + --mr-type-clip-vision-output-text: #e8b79a; + --mr-type-conditioning-rgb: 255, 169, 49; + --mr-type-conditioning-text: #ffd08c; + --mr-type-controlnet-rgb: 110, 231, 183; + --mr-type-controlnet-text: #b1f4db; + --mr-type-image-rgb: 100, 181, 246; + --mr-type-image-text: #b9dcff; + --mr-type-latent-rgb: 255, 156, 249; + --mr-type-latent-text: #ffc8fb; + --mr-type-mask-rgb: 129, 199, 132; + --mr-type-mask-text: #bdebc0; + --mr-type-vae-rgb: 255, 110, 110; + --mr-type-vae-text: #ffb8b8; + --mr-type-noise-rgb: 176, 176, 176; + --mr-type-noise-text: #d6d6d6; + --mr-type-sampler-rgb: 236, 180, 180; + --mr-type-sampler-text: #f2cccc; + --mr-type-sigmas-rgb: 205, 255, 205; + --mr-type-sigmas-text: #dcffdc; + --mr-type-guider-rgb: 102, 255, 255; + --mr-type-guider-text: #c7ffff; + --mr-type-taesd-rgb: 220, 194, 116; + --mr-type-taesd-text: #efd991; } diff --git a/web/css/linker-main.css b/web/css/resolver-main.css similarity index 50% rename from web/css/linker-main.css rename to web/css/resolver-main.css index efb0ff9..c5adef8 100644 --- a/web/css/linker-main.css +++ b/web/css/resolver-main.css @@ -1,363 +1,363 @@ -#model-linker-modal, -#model-linker-modal button, -#model-linker-modal input, -#model-linker-modal select { +#model-resolver-modal, +#model-resolver-modal button, +#model-resolver-modal input, +#model-resolver-modal select { font-family: "Segoe UI Variable", "Segoe UI", system-ui, -apple-system, BlinkMacSystemFont, sans-serif; } -#model-linker-modal button { - font-size: var(--ml-spacing-15); +#model-resolver-modal button { + font-size: var(--mr-spacing-15); } -.ml-hidden-initial { +.mr-hidden-initial { display: none; } -.ml-hidden { +.mr-hidden { display: none !important; } -.ml-is-hidden { +.mr-is-hidden { display: none !important; } -.ml-is-visible { +.mr-is-visible { display: block !important; } -.ml-is-inline-flex { +.mr-is-inline-flex { display: inline-flex !important; } -.ml-is-muted { - color: var(--ml-text-muted) !important; +.mr-is-muted { + color: var(--mr-text-muted) !important; } -.ml-is-error { - color: var(--ml-color-error-light, #f44336) !important; +.mr-is-error { + color: var(--mr-color-error-light, #f44336) !important; } -.ml-is-active-text { - color: var(--ml-text) !important; +.mr-is-active-text { + color: var(--mr-text) !important; } -.ml-is-success-action { - background: var(--ml-accent, #4CAF50) !important; - border-color: var(--ml-accent, #4CAF50) !important; +.mr-is-success-action { + background: var(--mr-accent, #4CAF50) !important; + border-color: var(--mr-accent, #4CAF50) !important; color: #101010 !important; box-shadow: none !important; } -.ml-icon-img { +.mr-icon-img { vertical-align: middle; } -.ml-meta-line { - margin-top: var(--ml-spacing-4); - font-size: var(--ml-font-md); +.mr-meta-line { + margin-top: var(--mr-spacing-4); + font-size: var(--mr-font-md); } -.ml-meta-secondary { - color: var(--ml-text-muted); +.mr-meta-secondary { + color: var(--mr-text-muted); } -.ml-stack-md { +.mr-stack-md { display: flex; flex-direction: column; - gap: var(--ml-spacing-10); + gap: var(--mr-spacing-10); } -.ml-stack-sm { +.mr-stack-sm { display: flex; flex-direction: column; - gap: var(--ml-spacing-4); - margin-top: var(--ml-spacing-8); + gap: var(--mr-spacing-4); + margin-top: var(--mr-spacing-8); } -.ml-loaded-filters { +.mr-loaded-filters { padding: 0; } -.ml-loaded-filter-row { +.mr-loaded-filter-row { display: flex; - gap: var(--ml-spacing-8); + gap: var(--mr-spacing-8); flex-wrap: wrap; justify-content: flex-end; margin-bottom: 0; } -.ml-btn-filter, -.ml-copy-mode, -.ml-btn-copy-compact, -.ml-copy-main-btn, -#model-linker-modal .ml-btn-filter, -#model-linker-modal .ml-copy-mode, -#model-linker-modal .ml-btn-copy-compact, -#model-linker-modal .ml-copy-main-btn { +.mr-btn-filter, +.mr-copy-mode, +.mr-btn-copy-compact, +.mr-copy-main-btn, +#model-resolver-modal .mr-btn-filter, +#model-resolver-modal .mr-copy-mode, +#model-resolver-modal .mr-btn-copy-compact, +#model-resolver-modal .mr-copy-main-btn { display: inline-flex; align-items: center; justify-content: center; - gap: var(--ml-spacing-5); + gap: var(--mr-spacing-5); min-height: 30px; height: 30px; padding: 0 12px; - color: var(--ml-text); - background: var(--ml-missing-control-bg, rgba(255,255,255,0.035)); - border: 1px solid var(--ml-missing-control-border, rgba(255,255,255,0.105)); - border-radius: var(--ml-missing-control-radius, 7px); - box-shadow: var(--ml-missing-control-shadow, none); + color: var(--mr-text); + background: var(--mr-missing-control-bg, rgba(255,255,255,0.035)); + border: 1px solid var(--mr-missing-control-border, rgba(255,255,255,0.105)); + border-radius: var(--mr-missing-control-radius, 7px); + box-shadow: var(--mr-missing-control-shadow, none); box-sizing: border-box; cursor: pointer; font-size: 12px; font-weight: 700; line-height: 1; text-decoration: none; - transition: var(--ml-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); + transition: var(--mr-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); white-space: nowrap; } -.ml-btn-filter:hover:not(:disabled), -.ml-copy-mode:hover:not(:disabled), -.ml-btn-copy-compact:hover:not(:disabled), -.ml-copy-main-btn:hover:not(:disabled), -#model-linker-modal .ml-btn-filter:hover:not(:disabled), -#model-linker-modal .ml-copy-mode:hover:not(:disabled), -#model-linker-modal .ml-btn-copy-compact:hover:not(:disabled), -#model-linker-modal .ml-copy-main-btn:hover:not(:disabled) { - color: var(--ml-text); - background: var(--ml-missing-control-bg-hover, rgba(255,255,255,0.06)); - border-color: var(--ml-missing-control-border-hover, rgba(255,255,255,0.17)); +.mr-btn-filter:hover:not(:disabled), +.mr-copy-mode:hover:not(:disabled), +.mr-btn-copy-compact:hover:not(:disabled), +.mr-copy-main-btn:hover:not(:disabled), +#model-resolver-modal .mr-btn-filter:hover:not(:disabled), +#model-resolver-modal .mr-copy-mode:hover:not(:disabled), +#model-resolver-modal .mr-btn-copy-compact:hover:not(:disabled), +#model-resolver-modal .mr-copy-main-btn:hover:not(:disabled) { + color: var(--mr-text); + background: var(--mr-missing-control-bg-hover, rgba(255,255,255,0.06)); + border-color: var(--mr-missing-control-border-hover, rgba(255,255,255,0.17)); transform: none; } -.ml-btn-filter:focus-visible, -.ml-copy-mode:focus-visible, -.ml-btn-copy-compact:focus-visible, -.ml-copy-main-btn:focus-visible, -#model-linker-modal .ml-btn-filter:focus-visible, -#model-linker-modal .ml-copy-mode:focus-visible, -#model-linker-modal .ml-btn-copy-compact:focus-visible, -#model-linker-modal .ml-copy-main-btn:focus-visible { +.mr-btn-filter:focus-visible, +.mr-copy-mode:focus-visible, +.mr-btn-copy-compact:focus-visible, +.mr-copy-main-btn:focus-visible, +#model-resolver-modal .mr-btn-filter:focus-visible, +#model-resolver-modal .mr-copy-mode:focus-visible, +#model-resolver-modal .mr-btn-copy-compact:focus-visible, +#model-resolver-modal .mr-copy-main-btn:focus-visible { outline: none; - border-color: var(--ml-missing-control-focus-border, rgba(114,211,138,0.30)); - box-shadow: 0 0 0 2px var(--ml-missing-control-focus-ring, rgba(114,211,138,0.08)); + border-color: var(--mr-missing-control-focus-border, rgba(114,211,138,0.30)); + box-shadow: 0 0 0 2px var(--mr-missing-control-focus-ring, rgba(114,211,138,0.08)); } -.ml-btn-filter.active, -.ml-copy-mode.active, -#model-linker-modal .ml-btn-filter.active, -#model-linker-modal .ml-copy-mode.active { +.mr-btn-filter.active, +.mr-copy-mode.active, +#model-resolver-modal .mr-btn-filter.active, +#model-resolver-modal .mr-copy-mode.active { color: #dffbe5; background: rgba(114,211,138,0.13); border-color: rgba(114,211,138,0.32); } -.ml-btn-filter.active:hover:not(:disabled), -.ml-copy-mode.active:hover:not(:disabled), -#model-linker-modal .ml-btn-filter.active:hover:not(:disabled), -#model-linker-modal .ml-copy-mode.active:hover:not(:disabled) { +.mr-btn-filter.active:hover:not(:disabled), +.mr-copy-mode.active:hover:not(:disabled), +#model-resolver-modal .mr-btn-filter.active:hover:not(:disabled), +#model-resolver-modal .mr-copy-mode.active:hover:not(:disabled) { background: rgba(114,211,138,0.17); border-color: rgba(114,211,138,0.42); } -.ml-models-list-pad { - padding: 0 var(--ml-spacing-12); +.mr-models-list-pad { + padding: 0 var(--mr-spacing-12); } -.ml-model-section { - margin-bottom: var(--ml-spacing-8); - padding: var(--ml-spacing-10); - background: var(--ml-card-bg-alt, #252525); +.mr-model-section { + margin-bottom: var(--mr-spacing-8); + padding: var(--mr-spacing-10); + background: var(--mr-card-bg-alt, #252525); border: 1px solid rgba(255, 255, 255, 0.055); - border-radius: var(--ml-ui-radius-sm); + border-radius: var(--mr-ui-radius-sm); } -.ml-model-section-header { +.mr-model-section-header { display: flex; align-items: center; justify-content: space-between; - gap: var(--ml-spacing-10); - margin-bottom: var(--ml-spacing-6); - padding-bottom: var(--ml-spacing-5); - border-bottom: 1px solid var(--ml-color-gray-900); + gap: var(--mr-spacing-10); + margin-bottom: var(--mr-spacing-6); + padding-bottom: var(--mr-spacing-5); + border-bottom: 1px solid var(--mr-color-gray-900); } -.ml-model-section-heading { +.mr-model-section-heading { display: flex; align-items: baseline; - gap: var(--ml-spacing-8); + gap: var(--mr-spacing-8); min-width: 0; } -.ml-model-section-title { - color: var(--ml-text); - font-size: var(--ml-font-lg); +.mr-model-section-title { + color: var(--mr-text); + font-size: var(--mr-font-lg); font-weight: 600; } -.ml-model-section-total { - color: var(--ml-text-dim); - font-size: var(--ml-font-xs); +.mr-model-section-total { + color: var(--mr-text-dim); + font-size: var(--mr-font-xs); font-weight: 600; white-space: nowrap; } -.ml-model-section-counts { +.mr-model-section-counts { display: flex; align-items: center; - gap: var(--ml-spacing-5); + gap: var(--mr-spacing-5); flex-wrap: wrap; justify-content: flex-end; } -.ml-model-count-pill { +.mr-model-count-pill { display: inline-flex; align-items: center; min-height: 18px; - padding: 0 var(--ml-spacing-7); + padding: 0 var(--mr-spacing-7); border-radius: 999px; border: 1px solid rgba(255, 255, 255, 0.09); - color: var(--ml-text-muted); + color: var(--mr-text-muted); background: rgba(255, 255, 255, 0.035); - font-size: var(--ml-font-xs); + font-size: var(--mr-font-xs); font-weight: 700; white-space: nowrap; } -.ml-model-count-pill.is-active { +.mr-model-count-pill.is-active { color: #c9f6d0; border-color: rgba(114, 211, 138, 0.25); background: rgba(114, 211, 138, 0.09); } -.ml-model-count-pill.is-inactive { - color: var(--ml-text-dim); +.mr-model-count-pill.is-inactive { + color: var(--mr-text-dim); } -.ml-model-group { - margin-bottom: var(--ml-spacing-6); +.mr-model-group { + margin-bottom: var(--mr-spacing-6); } -.ml-model-group-head { +.mr-model-group-head { display: flex; justify-content: space-between; align-items: center; - gap: var(--ml-spacing-8); - margin-bottom: var(--ml-spacing-5); + gap: var(--mr-spacing-8); + margin-bottom: var(--mr-spacing-5); } -.ml-model-group-label { +.mr-model-group-label { display: inline-flex; align-items: center; - gap: var(--ml-spacing-5); - font-size: var(--ml-font-sm); + gap: var(--mr-spacing-5); + font-size: var(--mr-font-sm); font-weight: 600; } -.ml-model-group-dot { +.mr-model-group-dot { width: 6px; height: 6px; border-radius: 999px; background: currentColor; } -.ml-model-group-count { - color: var(--ml-text-dim); - font-size: var(--ml-font-xs); +.mr-model-group-count { + color: var(--mr-text-dim); + font-size: var(--mr-font-xs); font-weight: 700; } -.ml-model-group-label-active { +.mr-model-group-label-active { color: #4caf50; } -.ml-model-group-label-inactive { - color: var(--ml-color-gray-500); +.mr-model-group-label-inactive { + color: var(--mr-color-gray-500); } -.ml-btn-copy-compact { +.mr-btn-copy-compact { font-size: 12px; } -.ml-copy-btn-icon { +.mr-copy-btn-icon { width: 13px; height: 13px; } -.ml-btn-copy-compact.is-muted { +.mr-btn-copy-compact.is-muted { opacity: 1; } -.ml-model-chip-list { +.mr-model-chip-list { display: flex; flex-wrap: wrap; - gap: var(--ml-spacing-5); + gap: var(--mr-spacing-5); } -.ml-model-chip-list-inactive { +.mr-model-chip-list-inactive { opacity: 0.5; } -.ml-copy-section { +.mr-copy-section { position: sticky; bottom: 0; z-index: 2; - padding: var(--ml-spacing-10) var(--ml-spacing-12) var(--ml-spacing-12); - background: var(--ml-bg); - border-top: 1px solid var(--ml-border); + padding: var(--mr-spacing-10) var(--mr-spacing-12) var(--mr-spacing-12); + background: var(--mr-bg); + border-top: 1px solid var(--mr-border); } -.ml-copy-label { +.mr-copy-label { margin: 0; - font-size: var(--ml-font-md); + font-size: var(--mr-font-md); font-weight: 700; - color: var(--ml-text); + color: var(--mr-text); } -.ml-copy-meta { - margin-top: var(--ml-spacing-2); - font-size: var(--ml-font-xs); - color: var(--ml-text-muted); +.mr-copy-meta { + margin-top: var(--mr-spacing-2); + font-size: var(--mr-font-xs); + color: var(--mr-text-muted); } -.ml-copy-toolbar { +.mr-copy-toolbar { display: flex; align-items: center; justify-content: space-between; - gap: var(--ml-spacing-10); - margin-bottom: var(--ml-spacing-8); + gap: var(--mr-spacing-10); + margin-bottom: var(--mr-spacing-8); } -.ml-copy-heading { +.mr-copy-heading { min-width: 0; } -.ml-copy-actions { +.mr-copy-actions { display: flex; align-items: center; - gap: var(--ml-spacing-6); + gap: var(--mr-spacing-6); flex-wrap: wrap; justify-content: flex-end; } -.ml-copy-mode { +.mr-copy-mode { font-size: 12px; } -.ml-copy-main-btn { +.mr-copy-main-btn { font-size: 12px; } -.ml-copy-code { +.mr-copy-code { display: block; width: 100%; max-height: 92px; box-sizing: border-box; - padding: var(--ml-spacing-8) var(--ml-spacing-12); - background: var(--ml-card-bg); - border-radius: var(--ml-radius-md); + padding: var(--mr-spacing-8) var(--mr-spacing-12); + background: var(--mr-card-bg); + border-radius: var(--mr-radius-md); font-family: "SF Mono", "Consolas", monospace; - font-size: var(--ml-font-sm); + font-size: var(--mr-font-sm); line-height: 1.45; color: #90caf9; overflow: auto; @@ -366,44 +366,44 @@ } @media (max-width: 720px) { - .ml-loaded-models-header, - .ml-copy-toolbar, - .ml-model-section-header { + .mr-loaded-models-header, + .mr-copy-toolbar, + .mr-model-section-header { align-items: stretch; flex-direction: column; } - .ml-loaded-filter-row, - .ml-copy-actions, - .ml-model-section-counts { + .mr-loaded-filter-row, + .mr-copy-actions, + .mr-model-section-counts { justify-content: flex-start; } } -.ml-error-text { +.mr-error-text { color: red; } -.ml-info-accent-text { +.mr-info-accent-text { color: #2196f3; } -.ml-progress-row { +.mr-progress-row { display: flex; align-items: center; - gap: var(--ml-spacing-8); + gap: var(--mr-spacing-8); } -.ml-progress-bar-grow { +.mr-progress-bar-grow { flex: 1; } -.ml-download-progress-slot { - margin-top: var(--ml-spacing-8); +.mr-download-progress-slot { + margin-top: var(--mr-spacing-8); display: none; } -.ml-civitai-open-btn { +.mr-civitai-open-btn { background: transparent; color: #ff9800; border: 1px solid #ff9800; @@ -411,71 +411,71 @@ cursor: pointer; } -.ml-civitai-download-btn { +.mr-civitai-download-btn { background: #ff9800; } -.ml-missing-summary { +.mr-missing-summary { display: flex; justify-content: space-between; align-items: center; - gap: var(--ml-spacing-12); - margin-bottom: var(--ml-spacing-10); - padding: var(--ml-spacing-10) var(--ml-spacing-12); - border-radius: var(--ml-ui-radius-lg); + gap: var(--mr-spacing-12); + margin-bottom: var(--mr-spacing-10); + padding: var(--mr-spacing-10) var(--mr-spacing-12); + border-radius: var(--mr-ui-radius-lg); background: linear-gradient(135deg, rgba(255,255,255,0.04) 0%, rgba(255,255,255,0.02) 100%); - border: 1px solid var(--ml-border-strong); - box-shadow: var(--ml-shadow-elevated); + border: 1px solid var(--mr-border-strong); + box-shadow: var(--mr-shadow-elevated); } -.ml-missing-summary-title { +.mr-missing-summary-title { display: flex; align-items: baseline; - gap: var(--ml-spacing-10); + gap: var(--mr-spacing-10); flex-wrap: wrap; } -.ml-missing-summary-count { - font-size: var(--ml-spacing-15); +.mr-missing-summary-count { + font-size: var(--mr-spacing-15); font-weight: 700; - color: var(--ml-text); + color: var(--mr-text); letter-spacing: -0.02em; } -.ml-missing-summary-meta { - font-size: var(--ml-font-sm); - color: var(--ml-text-muted); +.mr-missing-summary-meta { + font-size: var(--mr-font-sm); + color: var(--mr-text-muted); } -.ml-missing-browser { - --ml-missing-bg: #111; - --ml-missing-surface: rgba(255,255,255,0.03); - --ml-missing-surface-raised: rgba(255,255,255,0.052); - --ml-missing-surface-muted: rgba(255,255,255,0.02); - --ml-missing-line: rgba(255,255,255,0.075); - --ml-missing-line-strong: rgba(255,255,255,0.13); - --ml-missing-radius: 6px; +.mr-missing-browser { + --mr-missing-bg: #111; + --mr-missing-surface: rgba(255,255,255,0.03); + --mr-missing-surface-raised: rgba(255,255,255,0.052); + --mr-missing-surface-muted: rgba(255,255,255,0.02); + --mr-missing-line: rgba(255,255,255,0.075); + --mr-missing-line-strong: rgba(255,255,255,0.13); + --mr-missing-radius: 6px; display: flex; gap: 0; height: 100%; min-height: 0; overflow: hidden; - border: 1px solid var(--ml-missing-line); - background: var(--ml-missing-bg); + border: 1px solid var(--mr-missing-line); + background: var(--mr-missing-bg); } -.ml-missing-list-pane, -.ml-missing-detail-pane { +.mr-missing-list-pane, +.mr-missing-detail-pane { min-width: 0; min-height: 0; overflow: hidden; contain: layout paint style; - background: var(--ml-missing-bg); + background: var(--mr-missing-bg); } -.ml-missing-list-pane { +.mr-missing-list-pane { flex: 1 1 auto; display: grid; grid-template-rows: auto auto minmax(0, 1fr); border-right: 0; - background: var(--ml-missing-bg); + background: var(--mr-missing-bg); } -.ml-missing-browser-splitter { +.mr-missing-browser-splitter { position: relative; flex: 0 0 10px; min-width: 10px; @@ -483,12 +483,12 @@ cursor: col-resize; user-select: none; touch-action: none; - background: var(--ml-missing-bg); - border-left: 1px solid var(--ml-missing-line); - border-right: 1px solid var(--ml-missing-line); + background: var(--mr-missing-bg); + border-left: 1px solid var(--mr-missing-line); + border-right: 1px solid var(--mr-missing-line); outline: none; } -.ml-missing-browser-splitter::before { +.mr-missing-browser-splitter::before { content: ""; position: absolute; top: 16px; @@ -500,84 +500,84 @@ transform: translateX(-50%); transition: background 0.15s ease, box-shadow 0.15s ease; } -.ml-missing-browser-splitter:hover::before, -.ml-missing-browser-splitter:focus-visible::before, -.ml-missing-browser.is-resizing .ml-missing-browser-splitter::before { +.mr-missing-browser-splitter:hover::before, +.mr-missing-browser-splitter:focus-visible::before, +.mr-missing-browser.is-resizing .mr-missing-browser-splitter::before { background: rgba(114,211,138,0.78); box-shadow: 0 0 0 3px rgba(114,211,138,0.12); } -.ml-missing-browser.is-resizing .ml-missing-list-pane, -.ml-missing-browser.is-resizing .ml-missing-detail-pane { +.mr-missing-browser.is-resizing .mr-missing-list-pane, +.mr-missing-browser.is-resizing .mr-missing-detail-pane { pointer-events: none; user-select: none; } -.ml-missing-list-toolbar { +.mr-missing-list-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; - border-bottom: 1px solid var(--ml-missing-line); - background: var(--ml-missing-surface); + border-bottom: 1px solid var(--mr-missing-line); + background: var(--mr-missing-surface); } -.ml-missing-list-title { +.mr-missing-list-title { font-size: 15px; font-weight: 750; - color: var(--ml-text); + color: var(--mr-text); } -.ml-missing-list-meta { +.mr-missing-list-meta { margin-top: 3px; font-size: 11px; - color: var(--ml-text-muted); + color: var(--mr-text-muted); } -.ml-missing-list-stats { +.mr-missing-list-stats { display: flex; align-items: center; justify-content: flex-end; gap: 6px; flex-wrap: wrap; } -.ml-missing-stat { +.mr-missing-stat { display: inline-flex; align-items: center; min-height: 20px; padding: 2px 7px; border-radius: 999px; - background: var(--ml-missing-surface-raised); - border: 1px solid var(--ml-missing-line); - color: var(--ml-text-muted); + background: var(--mr-missing-surface-raised); + border: 1px solid var(--mr-missing-line); + color: var(--mr-text-muted); font-size: 10px; font-weight: 700; white-space: nowrap; } -.ml-missing-stat-exact { +.mr-missing-stat-exact { color: #72d38a; } -.ml-missing-stat-partial { +.mr-missing-stat-partial { color: #f1cf64; } -.ml-missing-list-head, -#model-linker-modal .ml-missing-list-row { +.mr-missing-list-head, +#model-resolver-modal .mr-missing-list-row { display: grid; - grid-template-columns: 38px 22px minmax(170px, var(--ml-missing-model-col, 280px)) minmax(66px, var(--ml-missing-type-col, 112px)) minmax(150px, 1fr) 58px 106px; + grid-template-columns: 38px 22px minmax(170px, var(--mr-missing-model-col, 280px)) minmax(66px, var(--mr-missing-type-col, 112px)) minmax(150px, 1fr) 58px 106px; align-items: center; gap: 8px; } -.ml-missing-list-head { +.mr-missing-list-head { padding: 10px 12px 10px 8px; - border-bottom: 1px solid var(--ml-missing-line); - background: var(--ml-missing-surface); - color: var(--ml-text-muted); + border-bottom: 1px solid var(--mr-missing-line); + background: var(--mr-missing-surface); + color: var(--mr-text-muted); font-size: 11px; font-weight: 700; } -.ml-missing-list { +.mr-missing-list { min-height: 0; overflow-y: auto; scrollbar-width: auto; - background: var(--ml-missing-bg); + background: var(--mr-missing-bg); } -#model-linker-modal .ml-missing-list-row { +#model-resolver-modal .mr-missing-list-row { width: 100%; min-height: 64px; padding: 9px 12px 9px 8px; @@ -585,49 +585,49 @@ border-bottom: 1px solid rgba(255,255,255,0.052); border-radius: 0; background: transparent; - color: var(--ml-text); + color: var(--mr-text); cursor: pointer; font-family: inherit; font-size: 11px; text-align: left; transition: background 0.14s ease, box-shadow 0.14s ease, border-color 0.14s ease; } -#model-linker-modal .ml-missing-list-row:hover { +#model-resolver-modal .mr-missing-list-row:hover { background: rgba(255,255,255,0.032); } -#model-linker-modal .ml-missing-list-row:focus-visible { +#model-resolver-modal .mr-missing-list-row:focus-visible { outline: none; box-shadow: inset 3px 0 0 rgba(114,211,138,0.72), inset 0 0 0 1px rgba(114,211,138,0.16); } -#model-linker-modal .ml-missing-list-row.is-selected { +#model-resolver-modal .mr-missing-list-row.is-selected { background: linear-gradient(90deg, rgba(114,211,138,0.12) 0%, rgba(114,211,138,0.055) 42%, rgba(114,211,138,0.018) 100%); box-shadow: inset 3px 0 0 rgba(114,211,138,0.92), inset 0 0 0 1px rgba(114,211,138,0.12); } -.ml-missing-list-row.is-batch-selected { +.mr-missing-list-row.is-batch-selected { background: rgba(78,161,255,0.055); } -.ml-missing-list-row.is-selected.is-batch-selected { +.mr-missing-list-row.is-selected.is-batch-selected { background: linear-gradient(90deg, rgba(114,211,138,0.13) 0%, rgba(78,161,255,0.065) 58%, rgba(78,161,255,0.025) 100%); } -.ml-missing-row-select { +.mr-missing-row-select { display: flex; justify-content: center; align-items: center; } -.ml-missing-head-select { +.mr-missing-head-select { display: flex; justify-content: center; align-items: center; } -.ml-missing-select-all-check, -.ml-missing-row-check { +.mr-missing-select-all-check, +.mr-missing-row-check { width: 14px; height: 14px; margin: 0; accent-color: #72d38a; cursor: pointer; } -.ml-missing-row-index { +.mr-missing-row-index { display: block; width: 100%; color: rgba(255,255,255,0.55); @@ -636,42 +636,42 @@ text-align: center; justify-self: stretch; } -.ml-missing-row-model, -.ml-missing-row-best, -.ml-missing-row-match { +.mr-missing-row-model, +.mr-missing-row-best, +.mr-missing-row-match { min-width: 0; display: grid; gap: 2px; } -.ml-missing-row-model { +.mr-missing-row-model { grid-template-columns: minmax(0, 1fr); align-items: center; } -.ml-missing-row-name, -.ml-missing-row-node, -.ml-missing-row-best { +.mr-missing-row-name, +.mr-missing-row-node, +.mr-missing-row-best { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.ml-missing-row-name { - color: var(--ml-text); +.mr-missing-row-name { + color: var(--mr-text); font-size: 13px; font-weight: 700; } -.ml-missing-row-node { +.mr-missing-row-node { grid-column: 1; - color: var(--ml-text-muted); + color: var(--mr-text-muted); font-size: 10px; } -.ml-missing-row-node-label { +.mr-missing-row-node-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.ml-missing-row-type { +.mr-missing-row-type { justify-self: start; max-width: 100%; min-width: 0; @@ -680,54 +680,54 @@ text-overflow: ellipsis; white-space: nowrap; border-radius: 999px; - background: var(--ml-missing-surface-raised); + background: var(--mr-missing-surface-raised); color: #d4d4d4; font-size: 9px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.02em; } -.ml-missing-row-match { +.mr-missing-row-match { justify-self: start; display: inline-flex; align-items: center; - color: var(--ml-text-muted); + color: var(--mr-text-muted); } -.ml-missing-row-match strong { +.mr-missing-row-match strong { display: inline-flex; align-items: center; min-height: 18px; padding: 2px 6px; border-radius: 999px; - background: var(--ml-missing-surface-raised); + background: var(--mr-missing-surface-raised); font-size: 10px; font-weight: 800; line-height: 1; white-space: nowrap; } -.ml-missing-row-best { - color: var(--ml-text-muted); +.mr-missing-row-best { + color: var(--mr-text-muted); font-size: 11px; line-height: 1.25; white-space: normal; overflow-wrap: anywhere; word-break: normal; } -.ml-missing-row-none { - color: var(--ml-text-dim); +.mr-missing-row-none { + color: var(--mr-text-dim); } -.ml-missing-row-match-exact strong { +.mr-missing-row-match-exact strong { color: #72d38a; background: rgba(114,211,138,0.12); } -.ml-missing-row-match-partial strong { +.mr-missing-row-match-partial strong { color: #f1cf64; background: rgba(241,207,100,0.13); } -.ml-missing-row-match-none strong { +.mr-missing-row-match-none strong { color: rgba(255,255,255,0.42); } -.ml-missing-row-sources { +.mr-missing-row-sources { position: relative; display: block; justify-self: center; @@ -735,12 +735,12 @@ width: 104px; height: 50px; } -.ml-missing-source-dot { - --ml-source-rgb: 168,174,181; - --ml-source-fill-alpha: 0.08; - --ml-source-border-hi-alpha: 0.52; - --ml-source-border-alpha: 0.34; - --ml-source-glow-alpha: 0.08; +.mr-missing-source-dot { + --mr-source-rgb: 168,174,181; + --mr-source-fill-alpha: 0.08; + --mr-source-border-hi-alpha: 0.52; + --mr-source-border-alpha: 0.34; + --mr-source-glow-alpha: 0.08; position: absolute; display: inline-flex; align-items: center; @@ -750,69 +750,69 @@ border: 0; border-radius: 0; background: transparent; - color: rgb(var(--ml-source-rgb)); + color: rgb(var(--mr-source-rgb)); font-size: 9px; font-weight: 800; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.44)) - drop-shadow(0 0 4px rgba(var(--ml-source-rgb), var(--ml-source-glow-alpha))); + drop-shadow(0 0 4px rgba(var(--mr-source-rgb), var(--mr-source-glow-alpha))); isolation: isolate; z-index: 1; } -.ml-missing-source-dot::before, -.ml-missing-source-dot::after { +.mr-missing-source-dot::before, +.mr-missing-source-dot::after { content: ""; position: absolute; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 114'%3E%3Cpath fill='black' d='M50 1 Q53 1 56 3 L94 25 Q99 28 99 34 L99 80 Q99 86 94 89 L56 111 Q50 114 44 111 L6 89 Q1 86 1 80 L1 34 Q1 28 6 25 L44 3 Q47 1 50 1 Z'/%3E%3C/svg%3E") center / 100% 100% no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 114'%3E%3Cpath fill='black' d='M50 1 Q53 1 56 3 L94 25 Q99 28 99 34 L99 80 Q99 86 94 89 L56 111 Q50 114 44 111 L6 89 Q1 86 1 80 L1 34 Q1 28 6 25 L44 3 Q47 1 50 1 Z'/%3E%3C/svg%3E") center / 100% 100% no-repeat; pointer-events: none; } -.ml-missing-source-dot::before { +.mr-missing-source-dot::before { inset: 0; background: linear-gradient(145deg, - rgba(var(--ml-source-rgb), var(--ml-source-border-hi-alpha)), - rgba(var(--ml-source-rgb), var(--ml-source-border-alpha)) 42%, + rgba(var(--mr-source-rgb), var(--mr-source-border-hi-alpha)), + rgba(var(--mr-source-rgb), var(--mr-source-border-alpha)) 42%, rgba(255,255,255,0.08) ); } -.ml-missing-source-dot::after { +.mr-missing-source-dot::after { inset: 1.5px; background: - radial-gradient(circle at 35% 22%, rgba(var(--ml-source-rgb), 0.18), transparent 48%), + radial-gradient(circle at 35% 22%, rgba(var(--mr-source-rgb), 0.18), transparent 48%), linear-gradient(145deg, - rgba(var(--ml-source-rgb), var(--ml-source-fill-alpha)), + rgba(var(--mr-source-rgb), var(--mr-source-fill-alpha)), rgba(25,27,30,0.94) 54%, rgba(13,14,16,0.97) ); } -.ml-missing-row-sources .ml-missing-source-dot:nth-child(1) { +.mr-missing-row-sources .mr-missing-source-dot:nth-child(1) { left: 22px; top: -7px; } -.ml-missing-row-sources .ml-missing-source-dot:nth-child(2) { +.mr-missing-row-sources .mr-missing-source-dot:nth-child(2) { left: 52px; top: -7px; } -.ml-missing-row-sources .ml-missing-source-dot:nth-child(3) { +.mr-missing-row-sources .mr-missing-source-dot:nth-child(3) { left: 7px; top: 18px; z-index: 2; } -.ml-missing-row-sources .ml-missing-source-dot:nth-child(4) { +.mr-missing-row-sources .mr-missing-source-dot:nth-child(4) { left: 37px; top: 18px; z-index: 2; } -.ml-missing-row-sources .ml-missing-source-dot:nth-child(5) { +.mr-missing-row-sources .mr-missing-source-dot:nth-child(5) { left: 67px; top: 18px; z-index: 2; } -.ml-missing-row-sources .ml-missing-source-dot:nth-child(3):last-child { +.mr-missing-row-sources .mr-missing-source-dot:nth-child(3):last-child { left: 37px; } -.ml-missing-source-icon { +.mr-missing-source-icon { position: relative; z-index: 1; display: block; @@ -820,228 +820,228 @@ height: 15px; flex: 0 0 15px; } -.ml-missing-source-found, -.ml-missing-source-exact { - --ml-source-rgb: 114,211,138; - --ml-source-fill-alpha: 0.16; - --ml-source-border-hi-alpha: 0.76; - --ml-source-border-alpha: 0.58; - --ml-source-glow-alpha: 0.20; +.mr-missing-source-found, +.mr-missing-source-exact { + --mr-source-rgb: 114,211,138; + --mr-source-fill-alpha: 0.16; + --mr-source-border-hi-alpha: 0.76; + --mr-source-border-alpha: 0.58; + --mr-source-glow-alpha: 0.20; } -.ml-missing-source-partial { - --ml-source-rgb: 241,207,100; - --ml-source-fill-alpha: 0.18; - --ml-source-border-hi-alpha: 0.82; - --ml-source-border-alpha: 0.62; - --ml-source-glow-alpha: 0.24; +.mr-missing-source-partial { + --mr-source-rgb: 241,207,100; + --mr-source-fill-alpha: 0.18; + --mr-source-border-hi-alpha: 0.82; + --mr-source-border-alpha: 0.62; + --mr-source-glow-alpha: 0.24; } -.ml-missing-source-none { - --ml-source-rgb: 150,155,162; - --ml-source-fill-alpha: 0.05; - --ml-source-border-hi-alpha: 0.32; - --ml-source-border-alpha: 0.22; - --ml-source-glow-alpha: 0.02; +.mr-missing-source-none { + --mr-source-rgb: 150,155,162; + --mr-source-fill-alpha: 0.05; + --mr-source-border-hi-alpha: 0.32; + --mr-source-border-alpha: 0.22; + --mr-source-glow-alpha: 0.02; } -.ml-missing-source-running, -.ml-missing-source-pending { - --ml-source-rgb: 96,190,255; - --ml-source-fill-alpha: 0.16; - --ml-source-border-hi-alpha: 0.78; - --ml-source-border-alpha: 0.6; - --ml-source-glow-alpha: 0.24; +.mr-missing-source-running, +.mr-missing-source-pending { + --mr-source-rgb: 96,190,255; + --mr-source-fill-alpha: 0.16; + --mr-source-border-hi-alpha: 0.78; + --mr-source-border-alpha: 0.6; + --mr-source-glow-alpha: 0.24; } -.ml-missing-source-error { - --ml-source-rgb: 255,138,128; - --ml-source-fill-alpha: 0.16; - --ml-source-border-hi-alpha: 0.82; - --ml-source-border-alpha: 0.62; - --ml-source-glow-alpha: 0.22; +.mr-missing-source-error { + --mr-source-rgb: 255,138,128; + --mr-source-fill-alpha: 0.16; + --mr-source-border-hi-alpha: 0.82; + --mr-source-border-alpha: 0.62; + --mr-source-glow-alpha: 0.22; } -.ml-missing-detail-pane { - flex: 0 0 var(--ml-missing-detail-track, 42%); +.mr-missing-detail-pane { + flex: 0 0 var(--mr-missing-detail-track, 42%); overflow-y: auto; - background: var(--ml-missing-bg); + background: var(--mr-missing-bg); } -.ml-missing-detail-pane .ml-card { +.mr-missing-detail-pane .mr-card { margin: 0; padding: 18px; background: transparent; box-shadow: none; } -.ml-missing-detail-pane .ml-card:hover { +.mr-missing-detail-pane .mr-card:hover { box-shadow: none; } -.ml-missing-detail-pane .ml-card-header { +.mr-missing-detail-pane .mr-card-header { margin-bottom: 10px; } -.ml-missing-detail-pane .ml-card-title { +.mr-missing-detail-pane .mr-card-title { font-size: 16px; letter-spacing: 0; } -.ml-missing-detail-pane .ml-card-subtitle { +.mr-missing-detail-pane .mr-card-subtitle { margin-top: 1px; } -.ml-missing-detail-pane .ml-columns { +.mr-missing-detail-pane .mr-columns { grid-template-columns: minmax(0, 1fr); gap: 10px; } -.ml-missing-detail-pane .ml-column { +.mr-missing-detail-pane .mr-column { padding: 12px; background: linear-gradient(180deg, rgba(255,255,255,0.028) 0%, rgba(255,255,255,0.014) 100%); - border: 1px solid var(--ml-missing-line); - border-radius: var(--ml-missing-radius); + border: 1px solid var(--mr-missing-line); + border-radius: var(--mr-missing-radius); box-shadow: none; } @media (max-width: 980px) { - .ml-missing-browser { + .mr-missing-browser { flex-direction: column; overflow-y: auto; } - .ml-missing-browser-splitter { + .mr-missing-browser-splitter { display: none; } - .ml-missing-list-pane { + .mr-missing-list-pane { max-height: 46vh; border-right: 0; border-bottom: 1px solid rgba(255,255,255,0.08); } - .ml-missing-detail-pane { + .mr-missing-detail-pane { flex: 0 0 auto; overflow: visible; } } @media (max-width: 760px) { - .ml-missing-list-head { + .mr-missing-list-head { display: none; } - #model-linker-modal .ml-missing-list-row { + #model-resolver-modal .mr-missing-list-row { grid-template-columns: 24px 18px minmax(0, 1fr); gap: 7px; } - .ml-missing-row-select { + .mr-missing-row-select { grid-row: 1 / span 4; align-self: start; margin-top: 1px; } - .ml-missing-row-index { + .mr-missing-row-index { grid-row: 1 / span 4; align-self: start; margin-top: 1px; text-align: center; } - .ml-missing-row-model, - .ml-missing-row-type, - .ml-missing-row-best, - .ml-missing-row-match, - .ml-missing-row-sources { + .mr-missing-row-model, + .mr-missing-row-type, + .mr-missing-row-best, + .mr-missing-row-match, + .mr-missing-row-sources { grid-column: 3; } } /* Card Styles */ -.ml-card { - background: var(--ml-card-bg); +.mr-card { + background: var(--mr-card-bg); border: 1px solid transparent; border-radius: 0; - padding: var(--ml-spacing-10) var(--ml-spacing-12); - margin-bottom: var(--ml-spacing-4); + padding: var(--mr-spacing-10) var(--mr-spacing-12); + margin-bottom: var(--mr-spacing-4); transition: background 0.18s ease, box-shadow 0.18s ease; box-shadow: inset 0 0 0 1px rgba(255,255,255,0.018); font-family: "Segoe UI Variable", "Segoe UI", sans-serif; } -.ml-card:nth-child(even) { - background: var(--ml-card-bg-alt); +.mr-card:nth-child(even) { + background: var(--mr-card-bg-alt); } -.ml-card:hover { +.mr-card:hover { box-shadow: inset 0 0 0 1px rgba(255,255,255,0.05), 0 10px 24px rgba(0,0,0,0.14); } /* Card Header */ -.ml-card-header { +.mr-card-header { display: flex; align-items: flex-start; justify-content: space-between; - gap: var(--ml-spacing-10); - margin-bottom: var(--ml-spacing-6); + gap: var(--mr-spacing-10); + margin-bottom: var(--mr-spacing-6); } -.ml-card-title-wrap { +.mr-card-title-wrap { min-width: 0; flex: 1; display: grid; - gap: var(--ml-spacing-4); + gap: var(--mr-spacing-4); } -.ml-card-title-meta { +.mr-card-title-meta { display: grid; - gap: var(--ml-spacing-2); + gap: var(--mr-spacing-2); } -.ml-card-title { - font-size: var(--ml-spacing-15); +.mr-card-title { + font-size: var(--mr-spacing-15); line-height: 1.24; font-weight: 700; - color: var(--ml-text); + color: var(--mr-text); margin: 0; word-break: break-word; letter-spacing: -0.01em; } -.ml-card-title-eyebrow { +.mr-card-title-eyebrow { display: block; font-family: 'SF Mono', 'Consolas', 'Monaco', monospace; - font-size: var(--ml-font-xs); + font-size: var(--mr-font-xs); line-height: 1.35; - color: var(--ml-text-dim); + color: var(--mr-text-dim); word-break: break-all; } -.ml-card-title-primary { +.mr-card-title-primary { display: block; - color: var(--ml-text-soft); + color: var(--mr-text-soft); } -.ml-card-title-secondary { +.mr-card-title-secondary { display: block; - font-size: var(--ml-font-md); + font-size: var(--mr-font-md); line-height: 1.4; - color: var(--ml-text-muted); + color: var(--mr-text-muted); word-break: break-word; } -.ml-card-subtitle { +.mr-card-subtitle { margin-top: 0; display: flex; align-items: center; - gap: var(--ml-spacing-4); + gap: var(--mr-spacing-4); flex-wrap: wrap; } -.ml-node-chip { +.mr-node-chip { display: inline-flex; align-items: center; - gap: var(--ml-spacing-4); - padding: var(--ml-spacing-2) var(--ml-spacing-7); + gap: var(--mr-spacing-4); + padding: var(--mr-spacing-2) var(--mr-spacing-7); background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.06); border-radius: 999px; - font-size: var(--ml-font-xs); + font-size: var(--mr-font-xs); color: #c8c8c8; white-space: nowrap; flex-shrink: 0; } -.ml-missing-browser .ml-node-chip, -.ml-missing-browser .ml-category-chip:not(.ml-type-chip), -.ml-missing-browser .ml-search-source-pill { - background: var(--ml-missing-chip-bg, var(--ml-missing-surface-raised, rgba(255,255,255,0.04))); - border-color: var(--ml-missing-chip-border, var(--ml-missing-line, rgba(255,255,255,0.075))); +.mr-missing-browser .mr-node-chip, +.mr-missing-browser .mr-category-chip:not(.mr-type-chip), +.mr-missing-browser .mr-search-source-pill { + background: var(--mr-missing-chip-bg, var(--mr-missing-surface-raised, rgba(255,255,255,0.04))); + border-color: var(--mr-missing-chip-border, var(--mr-missing-line, rgba(255,255,255,0.075))); box-shadow: none; } -.ml-missing-browser .ml-badge { +.mr-missing-browser .mr-badge { border-radius: 999px; box-shadow: none; } -.ml-missing-browser .ml-badge-neutral { - background: var(--ml-missing-surface-raised, rgba(255,255,255,0.04)); - border-color: var(--ml-missing-line, rgba(255,255,255,0.075)); +.mr-missing-browser .mr-badge-neutral { + background: var(--mr-missing-surface-raised, rgba(255,255,255,0.04)); + border-color: var(--mr-missing-line, rgba(255,255,255,0.075)); } -.ml-node-chip.is-locatable { +.mr-node-chip.is-locatable { cursor: pointer; padding-right: 9px; color: #f1f1f1; @@ -1049,36 +1049,36 @@ border-color: rgba(255,255,255,0.12); transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.15s ease; } -.ml-missing-browser .ml-node-chip.is-locatable { - background: var(--ml-missing-chip-bg, var(--ml-missing-surface-raised, rgba(255,255,255,0.04))); - border-color: var(--ml-missing-chip-border, var(--ml-missing-line-strong, rgba(255,255,255,0.12))); +.mr-missing-browser .mr-node-chip.is-locatable { + background: var(--mr-missing-chip-bg, var(--mr-missing-surface-raised, rgba(255,255,255,0.04))); + border-color: var(--mr-missing-chip-border, var(--mr-missing-line-strong, rgba(255,255,255,0.12))); transform: none; } -.ml-node-chip.is-locatable:hover { +.mr-node-chip.is-locatable:hover { background: rgba(255,255,255,0.12); border-color: rgba(255,255,255,0.18); color: #ffffff; transform: translateY(-1px); } -.ml-missing-browser .ml-node-chip.is-locatable:hover { - background: var(--ml-missing-chip-bg-hover, rgba(255,255,255,0.06)); - border-color: var(--ml-missing-chip-border-hover, rgba(255,255,255,0.18)); +.mr-missing-browser .mr-node-chip.is-locatable:hover { + background: var(--mr-missing-chip-bg-hover, rgba(255,255,255,0.06)); + border-color: var(--mr-missing-chip-border-hover, rgba(255,255,255,0.18)); transform: none; } -.ml-node-chip-icon { +.mr-node-chip-icon { display: inline-flex; align-items: center; justify-content: center; - width: var(--ml-missing-chip-icon-size, var(--ml-spacing-12)); - height: var(--ml-missing-chip-icon-size, var(--ml-spacing-12)); + width: var(--mr-missing-chip-icon-size, var(--mr-spacing-12)); + height: var(--mr-missing-chip-icon-size, var(--mr-spacing-12)); opacity: 0.95; } -.ml-node-chip-icon svg { - width: var(--ml-missing-chip-icon-size, var(--ml-spacing-12)); - height: var(--ml-missing-chip-icon-size, var(--ml-spacing-12)); +.mr-node-chip-icon svg { + width: var(--mr-missing-chip-icon-size, var(--mr-spacing-12)); + height: var(--mr-missing-chip-icon-size, var(--mr-spacing-12)); display: block; } -#model-linker-modal .ml-missing-row-locate { +#model-resolver-modal .mr-missing-row-locate { all: unset; display: inline-flex; align-items: center; @@ -1087,13 +1087,13 @@ justify-self: start; max-width: 100%; min-width: 0; - min-height: var(--ml-missing-chip-height, 20px); + min-height: var(--mr-missing-chip-height, 20px); margin: 0; padding: 2px 8px; - gap: var(--ml-spacing-4); - background: var(--ml-missing-chip-bg, rgba(255,255,255,0.045)); - border: 1px solid var(--ml-missing-chip-border, rgba(255,255,255,0.08)); - border-radius: var(--ml-missing-chip-radius, 999px); + gap: var(--mr-spacing-4); + background: var(--mr-missing-chip-bg, rgba(255,255,255,0.045)); + border: 1px solid var(--mr-missing-chip-border, rgba(255,255,255,0.08)); + border-radius: var(--mr-missing-chip-radius, 999px); box-shadow: none; color: #f1f1f1; font-family: inherit; @@ -1105,27 +1105,27 @@ flex-shrink: 1; overflow: hidden; vertical-align: middle; - transition: var(--ml-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease), transform 0.15s ease; + transition: var(--mr-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease), transform 0.15s ease; } -#model-linker-modal .ml-missing-row-locate:hover { - background: var(--ml-missing-chip-bg-hover, rgba(255,255,255,0.06)); - border-color: var(--ml-missing-chip-border-hover, rgba(255,255,255,0.18)); +#model-resolver-modal .mr-missing-row-locate:hover { + background: var(--mr-missing-chip-bg-hover, rgba(255,255,255,0.06)); + border-color: var(--mr-missing-chip-border-hover, rgba(255,255,255,0.18)); color: #ffffff; transform: none; } -#model-linker-modal .ml-missing-row-locate:focus-visible { +#model-resolver-modal .mr-missing-row-locate:focus-visible { outline: none; - border-color: var(--ml-missing-control-focus-border, rgba(114,211,138,0.24)); - box-shadow: 0 0 0 1px var(--ml-missing-control-focus-ring, rgba(114,211,138,0.10)); + border-color: var(--mr-missing-control-focus-border, rgba(114,211,138,0.24)); + box-shadow: 0 0 0 1px var(--mr-missing-control-focus-ring, rgba(114,211,138,0.10)); } -#model-linker-modal .ml-missing-row-locate .ml-node-chip-icon, -#model-linker-modal .ml-missing-row-locate .ml-node-chip-icon svg { - width: var(--ml-missing-chip-icon-size, var(--ml-spacing-12)); - height: var(--ml-missing-chip-icon-size, var(--ml-spacing-12)); +#model-resolver-modal .mr-missing-row-locate .mr-node-chip-icon, +#model-resolver-modal .mr-missing-row-locate .mr-node-chip-icon svg { + width: var(--mr-missing-chip-icon-size, var(--mr-spacing-12)); + height: var(--mr-missing-chip-icon-size, var(--mr-spacing-12)); } -.ml-category-chip { +.mr-category-chip { display: inline-flex; - padding: var(--ml-spacing-2) var(--ml-spacing-7); + padding: var(--mr-spacing-2) var(--mr-spacing-7); background: rgba(255,255,255,0.045); border: 1px solid rgba(255,255,255,0.07); border-radius: 999px; @@ -1136,282 +1136,282 @@ font-weight: 700; } /* ComfyUI node_slot-inspired type chips. */ -.ml-type-chip, -.ml-info-tag.ml-type-chip, -.ml-category-chip.ml-type-chip, -.ml-missing-row-type { - --ml-type-rgb: var(--ml-type-generic-rgb, 176, 176, 176); - --ml-type-text: var(--ml-type-generic-text, #d6d6d6); - --ml-type-bg-alpha-strong: var(--ml-type-chip-bg-alpha-strong, 0.155); - --ml-type-bg-alpha: var(--ml-type-chip-bg-alpha, 0.12); - --ml-type-border-alpha: var(--ml-type-chip-border-alpha, 0.26); - --ml-type-glow-alpha: var(--ml-type-chip-glow-alpha, 0.045); +.mr-type-chip, +.mr-info-tag.mr-type-chip, +.mr-category-chip.mr-type-chip, +.mr-missing-row-type { + --mr-type-rgb: var(--mr-type-generic-rgb, 176, 176, 176); + --mr-type-text: var(--mr-type-generic-text, #d6d6d6); + --mr-type-bg-alpha-strong: var(--mr-type-chip-bg-alpha-strong, 0.155); + --mr-type-bg-alpha: var(--mr-type-chip-bg-alpha, 0.12); + --mr-type-border-alpha: var(--mr-type-chip-border-alpha, 0.26); + --mr-type-glow-alpha: var(--mr-type-chip-glow-alpha, 0.045); background: linear-gradient(180deg, - rgba(var(--ml-type-rgb), var(--ml-type-bg-alpha-strong)) 0%, - rgba(var(--ml-type-rgb), var(--ml-type-bg-alpha)) 100%); - border: 1px solid rgba(var(--ml-type-rgb), var(--ml-type-border-alpha)); - color: var(--ml-type-text); + rgba(var(--mr-type-rgb), var(--mr-type-bg-alpha-strong)) 0%, + rgba(var(--mr-type-rgb), var(--mr-type-bg-alpha)) 100%); + border: 1px solid rgba(var(--mr-type-rgb), var(--mr-type-border-alpha)); + color: var(--mr-type-text); box-shadow: inset 0 0 0 1px rgba(255,255,255,0.026), - 0 0 12px rgba(var(--ml-type-rgb), var(--ml-type-glow-alpha)); + 0 0 12px rgba(var(--mr-type-rgb), var(--mr-type-glow-alpha)); } -.ml-type-chip.ml-type-chip--model { - --ml-type-rgb: var(--ml-type-model-rgb, 179, 157, 219); - --ml-type-text: var(--ml-type-model-text, #dbcfff); +.mr-type-chip.mr-type-chip--model { + --mr-type-rgb: var(--mr-type-model-rgb, 179, 157, 219); + --mr-type-text: var(--mr-type-model-text, #dbcfff); } -.ml-type-chip.ml-type-chip--lora { - --ml-type-rgb: var(--ml-type-lora-rgb, 194, 255, 174); - --ml-type-text: var(--ml-type-lora-text, #d7ffcb); +.mr-type-chip.mr-type-chip--lora { + --mr-type-rgb: var(--mr-type-lora-rgb, 194, 255, 174); + --mr-type-text: var(--mr-type-lora-text, #d7ffcb); } -.ml-type-chip.ml-type-chip--style-model { - --ml-type-rgb: var(--ml-type-style-model-rgb, 194, 255, 174); - --ml-type-text: var(--ml-type-style-model-text, #d7ffcb); +.mr-type-chip.mr-type-chip--style-model { + --mr-type-rgb: var(--mr-type-style-model-rgb, 194, 255, 174); + --mr-type-text: var(--mr-type-style-model-text, #d7ffcb); } -.ml-type-chip.ml-type-chip--clip { - --ml-type-rgb: var(--ml-type-clip-rgb, 255, 213, 0); - --ml-type-text: var(--ml-type-clip-text, #ffe678); +.mr-type-chip.mr-type-chip--clip { + --mr-type-rgb: var(--mr-type-clip-rgb, 255, 213, 0); + --mr-type-text: var(--mr-type-clip-text, #ffe678); } -.ml-type-chip.ml-type-chip--clip-vision { - --ml-type-rgb: var(--ml-type-clip-vision-rgb, 168, 218, 220); - --ml-type-text: var(--ml-type-clip-vision-text, #c7eff0); +.mr-type-chip.mr-type-chip--clip-vision { + --mr-type-rgb: var(--mr-type-clip-vision-rgb, 168, 218, 220); + --mr-type-text: var(--mr-type-clip-vision-text, #c7eff0); } -.ml-type-chip.ml-type-chip--clip-vision-output { - --ml-type-rgb: var(--ml-type-clip-vision-output-rgb, 173, 116, 82); - --ml-type-text: var(--ml-type-clip-vision-output-text, #e8b79a); +.mr-type-chip.mr-type-chip--clip-vision-output { + --mr-type-rgb: var(--mr-type-clip-vision-output-rgb, 173, 116, 82); + --mr-type-text: var(--mr-type-clip-vision-output-text, #e8b79a); } -.ml-type-chip.ml-type-chip--conditioning { - --ml-type-rgb: var(--ml-type-conditioning-rgb, 255, 169, 49); - --ml-type-text: var(--ml-type-conditioning-text, #ffd08c); +.mr-type-chip.mr-type-chip--conditioning { + --mr-type-rgb: var(--mr-type-conditioning-rgb, 255, 169, 49); + --mr-type-text: var(--mr-type-conditioning-text, #ffd08c); } -.ml-type-chip.ml-type-chip--controlnet { - --ml-type-rgb: var(--ml-type-controlnet-rgb, 110, 231, 183); - --ml-type-text: var(--ml-type-controlnet-text, #b1f4db); +.mr-type-chip.mr-type-chip--controlnet { + --mr-type-rgb: var(--mr-type-controlnet-rgb, 110, 231, 183); + --mr-type-text: var(--mr-type-controlnet-text, #b1f4db); } -.ml-type-chip.ml-type-chip--image { - --ml-type-rgb: var(--ml-type-image-rgb, 100, 181, 246); - --ml-type-text: var(--ml-type-image-text, #b9dcff); +.mr-type-chip.mr-type-chip--image { + --mr-type-rgb: var(--mr-type-image-rgb, 100, 181, 246); + --mr-type-text: var(--mr-type-image-text, #b9dcff); } -.ml-type-chip.ml-type-chip--latent { - --ml-type-rgb: var(--ml-type-latent-rgb, 255, 156, 249); - --ml-type-text: var(--ml-type-latent-text, #ffc8fb); +.mr-type-chip.mr-type-chip--latent { + --mr-type-rgb: var(--mr-type-latent-rgb, 255, 156, 249); + --mr-type-text: var(--mr-type-latent-text, #ffc8fb); } -.ml-type-chip.ml-type-chip--mask { - --ml-type-rgb: var(--ml-type-mask-rgb, 129, 199, 132); - --ml-type-text: var(--ml-type-mask-text, #bdebc0); +.mr-type-chip.mr-type-chip--mask { + --mr-type-rgb: var(--mr-type-mask-rgb, 129, 199, 132); + --mr-type-text: var(--mr-type-mask-text, #bdebc0); } -.ml-type-chip.ml-type-chip--vae { - --ml-type-rgb: var(--ml-type-vae-rgb, 255, 110, 110); - --ml-type-text: var(--ml-type-vae-text, #ffb8b8); +.mr-type-chip.mr-type-chip--vae { + --mr-type-rgb: var(--mr-type-vae-rgb, 255, 110, 110); + --mr-type-text: var(--mr-type-vae-text, #ffb8b8); } -.ml-type-chip.ml-type-chip--noise { - --ml-type-rgb: var(--ml-type-noise-rgb, 176, 176, 176); - --ml-type-text: var(--ml-type-noise-text, #d6d6d6); +.mr-type-chip.mr-type-chip--noise { + --mr-type-rgb: var(--mr-type-noise-rgb, 176, 176, 176); + --mr-type-text: var(--mr-type-noise-text, #d6d6d6); } -.ml-type-chip.ml-type-chip--sampler { - --ml-type-rgb: var(--ml-type-sampler-rgb, 236, 180, 180); - --ml-type-text: var(--ml-type-sampler-text, #f2cccc); +.mr-type-chip.mr-type-chip--sampler { + --mr-type-rgb: var(--mr-type-sampler-rgb, 236, 180, 180); + --mr-type-text: var(--mr-type-sampler-text, #f2cccc); } -.ml-type-chip.ml-type-chip--sigmas { - --ml-type-rgb: var(--ml-type-sigmas-rgb, 205, 255, 205); - --ml-type-text: var(--ml-type-sigmas-text, #dcffdc); +.mr-type-chip.mr-type-chip--sigmas { + --mr-type-rgb: var(--mr-type-sigmas-rgb, 205, 255, 205); + --mr-type-text: var(--mr-type-sigmas-text, #dcffdc); } -.ml-type-chip.ml-type-chip--guider { - --ml-type-rgb: var(--ml-type-guider-rgb, 102, 255, 255); - --ml-type-text: var(--ml-type-guider-text, #c7ffff); +.mr-type-chip.mr-type-chip--guider { + --mr-type-rgb: var(--mr-type-guider-rgb, 102, 255, 255); + --mr-type-text: var(--mr-type-guider-text, #c7ffff); } -.ml-type-chip.ml-type-chip--taesd { - --ml-type-rgb: var(--ml-type-taesd-rgb, 220, 194, 116); - --ml-type-text: var(--ml-type-taesd-text, #efd991); +.mr-type-chip.mr-type-chip--taesd { + --mr-type-rgb: var(--mr-type-taesd-rgb, 220, 194, 116); + --mr-type-text: var(--mr-type-taesd-text, #efd991); } -.ml-card-actions { +.mr-card-actions { display: flex; align-items: center; justify-content: flex-end; - gap: var(--ml-spacing-6); + gap: var(--mr-spacing-6); flex-wrap: wrap; flex-shrink: 0; } -.ml-inline-civitai-link { - color: var(--ml-text-soft); - font-size: var(--ml-font-lg); +.mr-inline-civitai-link { + color: var(--mr-text-soft); + font-size: var(--mr-font-lg); font-weight: 700; text-decoration: none; letter-spacing: -0.01em; } -.ml-inline-civitai-link:hover { +.mr-inline-civitai-link:hover { color: #ffffff; text-decoration: none; } /* Two-Column Layout */ -.ml-columns { +.mr-columns { display: grid; grid-template-columns: 1fr 1fr; - gap: var(--ml-spacing-8); + gap: var(--mr-spacing-8); } @media (max-width: 700px) { - .ml-missing-summary { + .mr-missing-summary { flex-direction: column; align-items: flex-start; } - .ml-columns { + .mr-columns { grid-template-columns: 1fr; } - .ml-card-header { + .mr-card-header { flex-direction: column; } - .ml-card-actions { + .mr-card-actions { justify-content: flex-start; } } -.ml-column { +.mr-column { min-width: 0; - background: var(--ml-panel-bg); + background: var(--mr-panel-bg); border: 1px solid transparent; border-radius: 0; - padding: var(--ml-spacing-10); + padding: var(--mr-spacing-10); box-shadow: inset 0 0 0 1px rgba(148,163,184,0.06); } -.ml-column-header { - font-size: var(--ml-font-xs); +.mr-column-header { + font-size: var(--mr-font-xs); font-weight: 700; - color: var(--ml-text-muted); + color: var(--mr-text-muted); text-transform: uppercase; letter-spacing: 0.1em; - margin-bottom: var(--ml-spacing-8); - padding-bottom: var(--ml-spacing-6); - border-bottom: 1px solid var(--ml-divider); + margin-bottom: var(--mr-spacing-8); + padding-bottom: var(--mr-spacing-6); + border-bottom: 1px solid var(--mr-divider); } -.ml-muted-note, -.ml-no-matches { - padding: var(--ml-spacing-8) var(--ml-spacing-10); - border-radius: var(--ml-ui-radius-sm); +.mr-muted-note, +.mr-no-matches { + padding: var(--mr-spacing-8) var(--mr-spacing-10); + border-radius: var(--mr-ui-radius-sm); background: rgba(255,255,255,0.018); border: 1px solid transparent; - color: var(--ml-text-muted); - font-size: var(--ml-font-sm); + color: var(--mr-text-muted); + font-size: var(--mr-font-sm); } -.ml-missing-browser .ml-column-header { +.mr-missing-browser .mr-column-header { margin-bottom: 9px; padding-bottom: 8px; - border-bottom: 1px solid var(--ml-missing-line, var(--ml-divider)); + border-bottom: 1px solid var(--mr-missing-line, var(--mr-divider)); color: #bdbdbd; font-size: 10px; letter-spacing: 0.08em; } -.ml-missing-browser .ml-muted-note, -.ml-missing-browser .ml-no-matches { +.mr-missing-browser .mr-muted-note, +.mr-missing-browser .mr-no-matches { padding: 9px 10px; - background: var(--ml-missing-surface-muted, rgba(255,255,255,0.018)); + background: var(--mr-missing-surface-muted, rgba(255,255,255,0.018)); border: 1px solid transparent; - border-radius: var(--ml-missing-control-radius, var(--ml-ui-radius-sm)); + border-radius: var(--mr-missing-control-radius, var(--mr-ui-radius-sm)); } -.ml-inline-note-action { +.mr-inline-note-action { transition: color 0.15s ease, background 0.15s ease; } -.ml-inline-note-action:hover { - color: var(--ml-text); +.mr-inline-note-action:hover { + color: var(--mr-text); background: rgba(255,255,255,0.05); } /* Filename Chips */ -.ml-chip { +.mr-chip { display: inline-flex; align-items: center; - padding: var(--ml-spacing-5) var(--ml-spacing-10); + padding: var(--mr-spacing-5) var(--mr-spacing-10); background: rgba(255,255,255,0.07); border: 1px solid rgba(255,255,255,0.08); border-radius: 999px; font-family: 'SF Mono', 'Consolas', 'Monaco', monospace; - font-size: var(--ml-font-md); - color: var(--ml-text); + font-size: var(--mr-font-md); + color: var(--mr-text); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.ml-chip:hover { +.mr-chip:hover { background: #444; } /* Confidence Badges */ -.ml-badge { +.mr-badge { display: inline-flex; align-items: center; justify-content: center; - padding: var(--ml-spacing-1) var(--ml-spacing-7); + padding: var(--mr-spacing-1) var(--mr-spacing-7); border-radius: 999px; - font-size: var(--ml-font-xs); + font-size: var(--mr-font-xs); font-weight: 600; min-width: 36px; text-align: center; border: 1px solid transparent; } -.ml-badge-high { +.mr-badge-high { background: rgba(114,211,138,0.14); color: #a7e6b6; border-color: rgba(114,211,138,0.22); } -.ml-badge-medium { +.mr-badge-medium { background: rgba(225,178,77,0.15); color: #efd391; border-color: rgba(225,178,77,0.2); } -.ml-badge-low { +.mr-badge-low { background: rgba(224,106,106,0.14); color: #efb1b1; border-color: rgba(224,106,106,0.2); } -.ml-badge-neutral { +.mr-badge-neutral { background: rgba(255,255,255,0.06); color: #d4d4d4; border-color: rgba(255,255,255,0.1); } /* Match Row */ -.ml-match-row { +.mr-match-row { display: flex; align-items: center; - gap: var(--ml-spacing-8); - padding: var(--ml-spacing-6) var(--ml-spacing-8); - border-radius: var(--ml-ui-radius-sm); - margin-bottom: var(--ml-spacing-4); + gap: var(--mr-spacing-8); + padding: var(--mr-spacing-6) var(--mr-spacing-8); + border-radius: var(--mr-ui-radius-sm); + margin-bottom: var(--mr-spacing-4); background: rgba(255,255,255,0.016); border: 1px solid transparent; transition: background 0.15s ease, box-shadow 0.15s ease; } -.ml-missing-browser .ml-match-row { +.mr-missing-browser .mr-match-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; align-items: center; min-height: 44px; margin-bottom: 7px; padding: 9px 10px; - background: var(--ml-missing-surface-muted, rgba(255,255,255,0.016)); - border: 1px solid var(--ml-missing-line, transparent); - border-radius: var(--ml-missing-control-radius, var(--ml-ui-radius-sm)); + background: var(--mr-missing-surface-muted, rgba(255,255,255,0.016)); + border: 1px solid var(--mr-missing-line, transparent); + border-radius: var(--mr-missing-control-radius, var(--mr-ui-radius-sm)); box-shadow: none; } -.ml-match-row:hover { +.mr-match-row:hover { background: rgba(255,255,255,0.032); box-shadow: inset 0 0 0 1px rgba(255,255,255,0.08); } -.ml-missing-browser .ml-match-row:hover { +.mr-missing-browser .mr-match-row:hover { background: rgba(255,255,255,0.032); - border-color: var(--ml-missing-line-strong, rgba(255,255,255,0.12)); + border-color: var(--mr-missing-line-strong, rgba(255,255,255,0.12)); box-shadow: none; } -.ml-match-row.ml-best-match { +.mr-match-row.mr-best-match { background: rgba(114,211,138,0.08); box-shadow: inset 0 0 0 1px rgba(114,211,138,0.16); } -.ml-missing-browser .ml-match-row.ml-best-match { +.mr-missing-browser .mr-match-row.mr-best-match { background: rgba(114,211,138,0.085); border-color: rgba(114,211,138,0.24); box-shadow: none; } -.ml-match-filename { +.mr-match-filename { flex: 1; min-width: 0; overflow: hidden; @@ -1419,32 +1419,32 @@ white-space: nowrap; font-family: 'SF Mono', 'Consolas', 'Monaco', monospace; font-size: 11.5px; - color: var(--ml-text-soft); + color: var(--mr-text-soft); } -.ml-missing-browser .ml-match-filename { - color: var(--ml-text-soft); +.mr-missing-browser .mr-match-filename { + color: var(--mr-text-soft); } -.ml-match-status { +.mr-match-status { display: inline-flex; align-items: center; justify-content: center; min-height: 20px; padding: 2px 7px; - border-radius: var(--ml-missing-control-radius, var(--ml-ui-radius-sm)); + border-radius: var(--mr-missing-control-radius, var(--mr-ui-radius-sm)); font-size: 10px; font-weight: 700; line-height: 1; white-space: nowrap; } -.ml-match-status-exact { +.mr-match-status-exact { color: #72d38a; background: rgba(114,211,138,0.10); } -.ml-match-status-partial { +.mr-match-status-partial { color: #f1cf64; background: rgba(241,207,100,0.10); } -.ml-local-alternatives-toggle { +.mr-local-alternatives-toggle { display: flex; align-items: center; width: 100%; @@ -1452,10 +1452,10 @@ margin: 6px 0 7px; padding: 0 8px; gap: 8px; - color: var(--ml-text-muted); + color: var(--mr-text-muted); background: rgba(255,255,255,0.022); border: 1px solid rgba(255,255,255,0.045); - border-radius: var(--ml-missing-control-radius, var(--ml-ui-radius-sm)); + border-radius: var(--mr-missing-control-radius, var(--mr-ui-radius-sm)); font-family: inherit; font-size: 11px; cursor: pointer; @@ -1463,29 +1463,29 @@ box-sizing: border-box; transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease; } -.ml-local-alternatives-toggle:hover { - color: var(--ml-text-soft); +.mr-local-alternatives-toggle:hover { + color: var(--mr-text-soft); background: rgba(255,255,255,0.032); border-color: rgba(255,255,255,0.06); } -.ml-local-alternatives-toggle:focus-visible { +.mr-local-alternatives-toggle:focus-visible { background: rgba(255,255,255,0.032); box-shadow: none; } -.ml-local-alternatives-label { - color: var(--ml-text-muted); +.mr-local-alternatives-label { + color: var(--mr-text-muted); font-weight: 650; font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase; } -.ml-local-alternatives-state { +.mr-local-alternatives-state { margin-left: auto; - color: var(--ml-text-dim); + color: var(--mr-text-dim); font-size: 10px; font-weight: 650; } -.ml-local-alternatives-chevron { +.mr-local-alternatives-chevron { width: 7px; height: 7px; border-right: 1px solid currentColor; @@ -1493,25 +1493,25 @@ transform: rotate(45deg) translateY(-1px); transition: transform 0.15s ease; } -.ml-local-alternatives-toggle[aria-expanded="true"] .ml-local-alternatives-chevron { +.mr-local-alternatives-toggle[aria-expanded="true"] .mr-local-alternatives-chevron { transform: rotate(225deg) translateY(-1px); } /* Buttons */ -.ml-btn, -#model-linker-modal .ml-btn { +.mr-btn, +#model-resolver-modal .mr-btn { display: inline-flex; align-items: center; justify-content: center; - gap: var(--ml-spacing-5); - min-height: var(--ml-missing-search-button-height, 34px); - height: var(--ml-missing-search-button-height, 34px); + gap: var(--mr-spacing-5); + min-height: var(--mr-missing-search-button-height, 34px); + height: var(--mr-missing-search-button-height, 34px); padding: 0 12px; - color: var(--ml-text); - background: var(--ml-missing-control-bg, rgba(255,255,255,0.035)); - border: 1px solid var(--ml-missing-control-border, rgba(255,255,255,0.105)); - border-radius: var(--ml-missing-control-radius, 7px); - box-shadow: var(--ml-missing-control-shadow, none); + color: var(--mr-text); + background: var(--mr-missing-control-bg, rgba(255,255,255,0.035)); + border: 1px solid var(--mr-missing-control-border, rgba(255,255,255,0.105)); + border-radius: var(--mr-missing-control-radius, 7px); + box-shadow: var(--mr-missing-control-shadow, none); box-sizing: border-box; font-size: 12px; font-weight: 700; @@ -1519,139 +1519,139 @@ cursor: pointer; appearance: none; -webkit-appearance: none; - transition: var(--ml-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); + transition: var(--mr-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); white-space: nowrap; text-decoration: none; } -.ml-btn:hover:not(:disabled), -#model-linker-modal .ml-btn:hover:not(:disabled) { - color: var(--ml-text); - background: var(--ml-missing-control-bg-hover, rgba(255,255,255,0.06)); - border-color: var(--ml-missing-control-border-hover, rgba(255,255,255,0.17)); +.mr-btn:hover:not(:disabled), +#model-resolver-modal .mr-btn:hover:not(:disabled) { + color: var(--mr-text); + background: var(--mr-missing-control-bg-hover, rgba(255,255,255,0.06)); + border-color: var(--mr-missing-control-border-hover, rgba(255,255,255,0.17)); transform: none; } -.ml-missing-browser .ml-btn, -#model-linker-modal .ml-missing-browser .ml-btn { - border-radius: var(--ml-missing-control-radius, var(--ml-ui-radius-sm)); - box-shadow: var(--ml-missing-control-shadow, none); +.mr-missing-browser .mr-btn, +#model-resolver-modal .mr-missing-browser .mr-btn { + border-radius: var(--mr-missing-control-radius, var(--mr-ui-radius-sm)); + box-shadow: var(--mr-missing-control-shadow, none); } -.ml-missing-browser .ml-btn:hover:not(:disabled), -#model-linker-modal .ml-missing-browser .ml-btn:hover:not(:disabled) { +.mr-missing-browser .mr-btn:hover:not(:disabled), +#model-resolver-modal .mr-missing-browser .mr-btn:hover:not(:disabled) { transform: none; } -.ml-btn:disabled, -#model-linker-modal .ml-btn:disabled { +.mr-btn:disabled, +#model-resolver-modal .mr-btn:disabled { opacity: 0.5; cursor: not-allowed; } -.ml-btn:focus-visible, -#model-linker-modal .ml-btn:focus-visible { +.mr-btn:focus-visible, +#model-resolver-modal .mr-btn:focus-visible { outline: none; - border-color: var(--ml-missing-control-focus-border, rgba(114,211,138,0.30)); - box-shadow: 0 0 0 2px var(--ml-missing-control-focus-ring, rgba(114,211,138,0.08)); + border-color: var(--mr-missing-control-focus-border, rgba(114,211,138,0.30)); + box-shadow: 0 0 0 2px var(--mr-missing-control-focus-ring, rgba(114,211,138,0.08)); } -.ml-btn-primary, -#model-linker-modal .ml-btn-primary { - background: var(--ml-accent); +.mr-btn-primary, +#model-resolver-modal .mr-btn-primary { + background: var(--mr-accent); border-color: rgba(114,211,138,0.42); color: white; } -.ml-btn-primary:hover:not(:disabled), -#model-linker-modal .ml-btn-primary:hover:not(:disabled) { - background: var(--ml-accent-hover); +.mr-btn-primary:hover:not(:disabled), +#model-resolver-modal .mr-btn-primary:hover:not(:disabled) { + background: var(--mr-accent-hover); border-color: rgba(114,211,138,0.55); color: white; } -.ml-btn-secondary, -.ml-btn-link, -#model-linker-modal .ml-btn-secondary, -#model-linker-modal .ml-btn-link { - background: var(--ml-missing-control-bg, rgba(255,255,255,0.035)); - color: var(--ml-text); - border-color: var(--ml-missing-control-border, rgba(255,255,255,0.105)); - box-shadow: var(--ml-missing-control-shadow, none); +.mr-btn-secondary, +.mr-btn-link, +#model-resolver-modal .mr-btn-secondary, +#model-resolver-modal .mr-btn-link { + background: var(--mr-missing-control-bg, rgba(255,255,255,0.035)); + color: var(--mr-text); + border-color: var(--mr-missing-control-border, rgba(255,255,255,0.105)); + box-shadow: var(--mr-missing-control-shadow, none); } -.ml-missing-browser .ml-btn-secondary, -#model-linker-modal .ml-missing-browser .ml-btn-secondary { - background: var(--ml-missing-control-bg, rgba(255,255,255,0.035)); - border-color: var(--ml-missing-control-border, var(--ml-missing-line-strong, rgba(255,255,255,0.12))); +.mr-missing-browser .mr-btn-secondary, +#model-resolver-modal .mr-missing-browser .mr-btn-secondary { + background: var(--mr-missing-control-bg, rgba(255,255,255,0.035)); + border-color: var(--mr-missing-control-border, var(--mr-missing-line-strong, rgba(255,255,255,0.12))); } -.ml-btn-secondary:hover:not(:disabled), -.ml-btn-link:hover:not(:disabled), -#model-linker-modal .ml-btn-secondary:hover:not(:disabled), -#model-linker-modal .ml-btn-link:hover:not(:disabled) { - background: var(--ml-missing-control-bg-hover, rgba(255,255,255,0.06)); - color: var(--ml-text); - border-color: var(--ml-missing-control-border-hover, rgba(255,255,255,0.17)); +.mr-btn-secondary:hover:not(:disabled), +.mr-btn-link:hover:not(:disabled), +#model-resolver-modal .mr-btn-secondary:hover:not(:disabled), +#model-resolver-modal .mr-btn-link:hover:not(:disabled) { + background: var(--mr-missing-control-bg-hover, rgba(255,255,255,0.06)); + color: var(--mr-text); + border-color: var(--mr-missing-control-border-hover, rgba(255,255,255,0.17)); transform: none; } -.ml-missing-browser .ml-btn-secondary:hover:not(:disabled), -#model-linker-modal .ml-missing-browser .ml-btn-secondary:hover:not(:disabled) { - background: var(--ml-missing-control-bg-hover, rgba(255,255,255,0.055)); - border-color: var(--ml-missing-control-border-hover, rgba(255,255,255,0.18)); +.mr-missing-browser .mr-btn-secondary:hover:not(:disabled), +#model-resolver-modal .mr-missing-browser .mr-btn-secondary:hover:not(:disabled) { + background: var(--mr-missing-control-bg-hover, rgba(255,255,255,0.055)); + border-color: var(--mr-missing-control-border-hover, rgba(255,255,255,0.18)); transform: none; } -.ml-btn-download, -#model-linker-modal .ml-btn-download { - background: var(--ml-accent); +.mr-btn-download, +#model-resolver-modal .mr-btn-download { + background: var(--mr-accent); border-color: rgba(114,211,138,0.42); color: #101010; box-shadow: 0 8px 18px rgba(114,211,138,0.18); } -.ml-btn-download:hover:not(:disabled), -#model-linker-modal .ml-btn-download:hover:not(:disabled) { - background: var(--ml-accent-hover); +.mr-btn-download:hover:not(:disabled), +#model-resolver-modal .mr-btn-download:hover:not(:disabled) { + background: var(--mr-accent-hover); border-color: rgba(114,211,138,0.55); color: #101010; transform: none; } -.ml-btn-danger, -#model-linker-modal .ml-btn-danger { +.mr-btn-danger, +#model-resolver-modal .mr-btn-danger { background: #f44336; border-color: rgba(244,67,54,0.52); color: white; } -.ml-btn-danger:hover:not(:disabled), -#model-linker-modal .ml-btn-danger:hover:not(:disabled) { +.mr-btn-danger:hover:not(:disabled), +#model-resolver-modal .mr-btn-danger:hover:not(:disabled) { background: #d32f2f; border-color: rgba(211,47,47,0.62); color: white; } -.ml-btn-sm, -#model-linker-modal .ml-btn-sm { - min-height: var(--ml-missing-search-button-height, 34px); - height: var(--ml-missing-search-button-height, 34px); +.mr-btn-sm, +#model-resolver-modal .mr-btn-sm { + min-height: var(--mr-missing-search-button-height, 34px); + height: var(--mr-missing-search-button-height, 34px); padding: 0 12px; - border-radius: var(--ml-missing-control-radius, 7px); + border-radius: var(--mr-missing-control-radius, 7px); font-size: 12px; font-weight: 700; line-height: 1; } -.ml-btn-ghost { +.mr-btn-ghost { background: rgba(255,255,255,0.018); - color: var(--ml-text-muted); + color: var(--mr-text-muted); border-color: rgba(255,255,255,0.08); box-shadow: none; } -.ml-btn-ghost:hover:not(:disabled) { +.mr-btn-ghost:hover:not(:disabled) { background: rgba(255,255,255,0.04); - color: var(--ml-text); + color: var(--mr-text); border-color: rgba(255,255,255,0.14); } -.ml-btn-utility { +.mr-btn-utility { padding-inline: 6px; font-weight: 600; letter-spacing: 0.01em; - color: var(--ml-text-soft); + color: var(--mr-text-soft); } -.ml-btn-link-compact { +.mr-btn-link-compact { min-width: 58px; - gap: var(--ml-spacing-4); + gap: var(--mr-spacing-4); padding-inline: 5px; font-size: 8.75px; } -.ml-missing-browser .ml-local-link-btn, -.ml-missing-browser .ml-btn-link-compact { +.mr-missing-browser .mr-local-link-btn, +.mr-missing-browser .mr-btn-link-compact { position: relative; flex: 0 0 46px; width: 46px; @@ -1661,14 +1661,14 @@ padding: 0 9px; overflow: hidden; gap: 0; - color: var(--ml-text-muted); + color: var(--mr-text-muted); font-size: 0; font-weight: 650; - background: var(--ml-missing-control-bg, rgba(255,255,255,0.035)); - border-color: var(--ml-missing-control-border, rgba(255,255,255,0.09)); + background: var(--mr-missing-control-bg, rgba(255,255,255,0.035)); + border-color: var(--mr-missing-control-border, rgba(255,255,255,0.09)); } -.ml-missing-browser .ml-local-link-btn::before, -.ml-missing-browser .ml-btn-link-compact::before { +.mr-missing-browser .mr-local-link-btn::before, +.mr-missing-browser .mr-btn-link-compact::before { content: "Link"; display: block; width: auto; @@ -1677,17 +1677,17 @@ font-size: 10px; line-height: 1; } -.ml-missing-browser .ml-local-link-btn > *, -.ml-missing-browser .ml-btn-link-compact > * { +.mr-missing-browser .mr-local-link-btn > *, +.mr-missing-browser .mr-btn-link-compact > * { display: none; } -.ml-missing-browser .ml-local-link-btn:hover:not(:disabled), -.ml-missing-browser .ml-btn-link-compact:hover:not(:disabled) { - color: var(--ml-text); - background: var(--ml-missing-control-bg-hover, rgba(255,255,255,0.05)); - border-color: var(--ml-missing-control-border-hover, rgba(255,255,255,0.16)); +.mr-missing-browser .mr-local-link-btn:hover:not(:disabled), +.mr-missing-browser .mr-btn-link-compact:hover:not(:disabled) { + color: var(--mr-text); + background: var(--mr-missing-control-bg-hover, rgba(255,255,255,0.05)); + border-color: var(--mr-missing-control-border-hover, rgba(255,255,255,0.16)); } -.ml-missing-browser .ml-local-link-btn { +.mr-missing-browser .mr-local-link-btn { flex: 0 0 30px; width: 30px; min-width: 30px; @@ -1695,131 +1695,131 @@ min-height: 30px; padding: 0; } -.ml-missing-browser .ml-local-link-btn > * { +.mr-missing-browser .mr-local-link-btn > * { display: none; } -.ml-missing-browser .ml-local-link-btn::before { +.mr-missing-browser .mr-local-link-btn::before { content: none; display: none; } -.ml-missing-browser .ml-local-link-btn > svg { +.mr-missing-browser .mr-local-link-btn > svg { display: block !important; width: 14px; height: 14px; } -.ml-btn-icon-only, -#model-linker-modal .ml-btn-icon-only { - width: var(--ml-missing-search-button-height, 34px); - min-width: var(--ml-missing-search-button-height, 34px); - height: var(--ml-missing-search-button-height, 34px); - min-height: var(--ml-missing-search-button-height, 34px); +.mr-btn-icon-only, +#model-resolver-modal .mr-btn-icon-only { + width: var(--mr-missing-search-button-height, 34px); + min-width: var(--mr-missing-search-button-height, 34px); + height: var(--mr-missing-search-button-height, 34px); + min-height: var(--mr-missing-search-button-height, 34px); padding: 0; aspect-ratio: 1; } -.ml-btn-icon, -#model-linker-modal .ml-btn-icon { - font-size: var(--ml-font-md); +.mr-btn-icon, +#model-resolver-modal .mr-btn-icon { + font-size: var(--mr-font-md); } -.ml-btn-icon svg, -#model-linker-modal .ml-btn-icon svg { - width: var(--ml-font-base); - height: var(--ml-font-base); +.mr-btn-icon svg, +#model-resolver-modal .mr-btn-icon svg { + width: var(--mr-font-base); + height: var(--mr-font-base); display: block; } -.ml-card-actions .ml-btn, -.ml-match-row .ml-btn, -.ml-combo-row .ml-btn { +.mr-card-actions .mr-btn, +.mr-match-row .mr-btn, +.mr-combo-row .mr-btn { min-height: 28px; } -.ml-search-source-btn { +.mr-search-source-btn { border-radius: 999px; padding-inline: 11px; background: rgba(255,255,255,0.03); - color: var(--ml-text); + color: var(--mr-text); border-color: rgba(255,255,255,0.1); box-shadow: inset 0 1px 0 rgba(255,255,255,0.02); } -.ml-search-source-btn.ml-btn-primary { +.mr-search-source-btn.mr-btn-primary { background: rgba(255,255,255,0.03); - color: var(--ml-text); + color: var(--mr-text); border-color: rgba(255,255,255,0.1); box-shadow: inset 0 1px 0 rgba(255,255,255,0.02); } -.ml-search-source-btn:hover:not(:disabled), -.ml-search-source-btn.ml-btn-primary:hover:not(:disabled) { +.mr-search-source-btn:hover:not(:disabled), +.mr-search-source-btn.mr-btn-primary:hover:not(:disabled) { background: rgba(255,255,255,0.05); - color: var(--ml-text); + color: var(--mr-text); border-color: rgba(255,255,255,0.16); } /* Download Section */ -.ml-download-section { - --ml-download-control-height: 36px; +.mr-download-section { + --mr-download-control-height: 36px; display: grid; gap: 10px; - padding: var(--ml-spacing-10); - background: var(--ml-surface-elevated); + padding: var(--mr-spacing-10); + background: var(--mr-surface-elevated); border-radius: 0; border: 1px solid transparent; box-shadow: inset 0 0 0 1px rgba(255,255,255,0.05); } -.ml-missing-browser .ml-download-section { +.mr-missing-browser .mr-download-section { padding: 10px; gap: 10px; background: rgba(255,255,255,0.012); border: 1px solid rgba(255,255,255,0.045); - border-radius: var(--ml-missing-control-radius, var(--ml-ui-radius-sm)); + border-radius: var(--mr-missing-control-radius, var(--mr-ui-radius-sm)); box-shadow: none; } -.ml-status-inline { +.mr-status-inline { display: flex; align-items: center; - gap: var(--ml-spacing-8); + gap: var(--mr-spacing-8); flex-wrap: wrap; } -.ml-download-info { - font-size: var(--ml-font-sm); - color: var(--ml-text-muted); +.mr-download-info { + font-size: var(--mr-font-sm); + color: var(--mr-text-muted); margin-top: 0; line-height: 1.55; } -.ml-missing-browser .ml-status-inline { +.mr-missing-browser .mr-status-inline { gap: 7px; } -.ml-missing-browser .ml-download-info { +.mr-missing-browser .mr-download-info { font-size: 11px; } -.ml-download-size { - color: var(--ml-text-dim); - margin-left: var(--ml-spacing-8); +.mr-download-size { + color: var(--mr-text-dim); + margin-left: var(--mr-spacing-8); } -.ml-search-source-bar { +.mr-search-source-bar { display: grid; grid-template-columns: auto minmax(178px, 1fr); align-items: center; gap: 10px; margin-bottom: 0; } -.ml-download-section .ml-search-source-bar > .ml-btn { - height: var(--ml-download-control-height); - min-height: var(--ml-download-control-height); +.mr-download-section .mr-search-source-bar > .mr-btn { + height: var(--mr-download-control-height); + min-height: var(--mr-download-control-height); padding: 0 12px; border-radius: 9px; font-size: 12px; line-height: 1; } -.ml-missing-browser .ml-download-section .ml-search-source-bar > .ml-btn { - background: var(--ml-missing-control-bg, rgba(255,255,255,0.035)); - border-color: var(--ml-missing-control-border, rgba(255,255,255,0.105)); - border-radius: var(--ml-missing-control-radius, 7px); - box-shadow: var(--ml-missing-control-shadow, none); +.mr-missing-browser .mr-download-section .mr-search-source-bar > .mr-btn { + background: var(--mr-missing-control-bg, rgba(255,255,255,0.035)); + border-color: var(--mr-missing-control-border, rgba(255,255,255,0.105)); + border-radius: var(--mr-missing-control-radius, 7px); + box-shadow: var(--mr-missing-control-shadow, none); } -.ml-missing-browser .ml-download-section .ml-search-source-bar > .ml-btn:hover:not(:disabled) { - background: var(--ml-missing-control-bg-hover, rgba(255,255,255,0.06)); - border-color: var(--ml-missing-control-border-hover, rgba(255,255,255,0.17)); +.mr-missing-browser .mr-download-section .mr-search-source-bar > .mr-btn:hover:not(:disabled) { + background: var(--mr-missing-control-bg-hover, rgba(255,255,255,0.06)); + border-color: var(--mr-missing-control-border-hover, rgba(255,255,255,0.17)); transform: none; } -.ml-search-source-picker { +.mr-search-source-picker { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; @@ -1828,22 +1828,22 @@ margin-left: auto; width: 100%; } -.ml-search-source-picker-label { - color: var(--ml-text-muted); +.mr-search-source-picker-label { + color: var(--mr-text-muted); font-size: 10px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap; } -.ml-search-source-select { +.mr-search-source-select { width: 100%; - height: var(--ml-download-control-height); - min-height: var(--ml-download-control-height); + height: var(--mr-download-control-height); + min-height: var(--mr-download-control-height); padding: 0 11px; background: rgba(255,255,255,0.04); - color: var(--ml-text); - border: 1px solid var(--ml-border); + color: var(--mr-text); + border: 1px solid var(--mr-border); border-radius: 9px; font-size: 12px; line-height: 1; @@ -1851,86 +1851,86 @@ appearance: none; box-sizing: border-box; } -.ml-missing-browser .ml-search-source-select { - background: var(--ml-missing-control-bg, rgba(255,255,255,0.035)); - border-color: var(--ml-missing-control-border, var(--ml-missing-line-strong, rgba(255,255,255,0.12))); - border-radius: var(--ml-missing-control-radius, 7px); +.mr-missing-browser .mr-search-source-select { + background: var(--mr-missing-control-bg, rgba(255,255,255,0.035)); + border-color: var(--mr-missing-control-border, var(--mr-missing-line-strong, rgba(255,255,255,0.12))); + border-radius: var(--mr-missing-control-radius, 7px); } -.ml-missing-browser .ml-search-source-select:focus { - border-color: var(--ml-missing-control-focus-border, rgba(114,211,138,0.4)); - box-shadow: 0 0 0 2px var(--ml-missing-control-focus-ring, rgba(114,211,138,0.12)); +.mr-missing-browser .mr-search-source-select:focus { + border-color: var(--mr-missing-control-focus-border, rgba(114,211,138,0.4)); + box-shadow: 0 0 0 2px var(--mr-missing-control-focus-ring, rgba(114,211,138,0.12)); } -.ml-search-source-select:focus { +.mr-search-source-select:focus { border-color: rgba(114,211,138,0.4); box-shadow: 0 0 0 3px rgba(114,211,138,0.12); } @media (max-width: 720px) { - .ml-search-source-bar { + .mr-search-source-bar { grid-template-columns: 1fr; } - .ml-download-section .ml-search-source-bar > .ml-btn { + .mr-download-section .mr-search-source-bar > .mr-btn { justify-self: start; } } -.ml-search-results { +.mr-search-results { margin-top: 8px; display: none; } -.ml-search-results-table-wrap { +.mr-search-results-table-wrap { margin-top: 8px; overflow-x: auto; background: rgba(255,255,255,0.025); - border: 1px solid var(--ml-border); + border: 1px solid var(--mr-border); border-radius: 8px; } -.ml-missing-browser .ml-search-results-table-wrap { +.mr-missing-browser .mr-search-results-table-wrap { background: rgba(255,255,255,0.018); border-color: rgba(255,255,255,0.052); - border-radius: var(--ml-missing-radius, 7px); + border-radius: var(--mr-missing-radius, 7px); } -.ml-search-results-table { +.mr-search-results-table { width: 100%; - min-width: var(--ml-table-min, 520px); + min-width: var(--mr-table-min, 520px); border-collapse: collapse; table-layout: fixed; font-size: 11px; } -.ml-search-results-table th, -.ml-search-results-table td { +.mr-search-results-table th, +.mr-search-results-table td { padding: 7px 10px; border-bottom: 1px solid rgba(255,255,255,0.065); vertical-align: middle; } -.ml-search-results-table th { - color: var(--ml-text-muted); +.mr-search-results-table th { + color: var(--mr-text-muted); font-size: 10px; font-weight: 700; text-align: left; background: rgba(255,255,255,0.035); } -.ml-missing-browser .ml-search-results-table th { - background: var(--ml-missing-surface-raised, rgba(255,255,255,0.04)); +.mr-missing-browser .mr-search-results-table th { + background: var(--mr-missing-surface-raised, rgba(255,255,255,0.04)); color: #bdbdbd; } -.ml-search-results-table tr:last-child td { +.mr-search-results-table tr:last-child td { border-bottom: 0; } -.ml-search-col-source { - width: var(--ml-source-col, 118px); +.mr-search-col-source { + width: var(--mr-source-col, 118px); } -.ml-search-col-model { +.mr-search-col-model { width: auto; } -.ml-search-col-match { - width: var(--ml-match-col, 64px); +.mr-search-col-match { + width: var(--mr-match-col, 64px); } -.ml-search-col-size { - width: var(--ml-size-col, 64px); +.mr-search-col-size { + width: var(--mr-size-col, 64px); } -.ml-search-col-actions { - width: var(--ml-actions-col, 72px); +.mr-search-col-actions { + width: var(--mr-actions-col, 72px); } -.ml-search-source-pill { +.mr-search-source-pill { display: inline-flex; gap: 5px; max-width: 100%; @@ -1938,7 +1938,7 @@ align-items: center; padding: 2px 7px; overflow: hidden; - color: var(--ml-text); + color: var(--mr-text); background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.08); border-radius: 999px; @@ -1947,67 +1947,67 @@ text-overflow: ellipsis; white-space: nowrap; } -.ml-search-source-pill > span { +.mr-search-source-pill > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; } -.ml-search-source-icon { +.mr-search-source-icon { display: block; flex: 0 0 12px; width: 12px; height: 12px; } -.ml-search-result-model { +.mr-search-result-model { display: grid; min-width: 0; gap: 2px; } -.ml-search-result-model span, -.ml-search-result-model small { +.mr-search-result-model span, +.mr-search-result-model small { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.ml-search-result-model span { - color: var(--ml-text); +.mr-search-result-model span { + color: var(--mr-text); font-weight: 650; } -.ml-model-version { - color: var(--ml-text-secondary); +.mr-model-version { + color: var(--mr-text-secondary); font-style: italic; font-weight: 500; } -.ml-search-result-model small, -.ml-search-size, -.ml-search-result-empty { - color: var(--ml-text-muted); +.mr-search-result-model small, +.mr-search-size, +.mr-search-result-empty { + color: var(--mr-text-muted); font-size: 10px; } -.ml-search-match { +.mr-search-match { font-weight: 750; } -.ml-search-match-strong { +.mr-search-match-strong { color: #72d38a; } -.ml-search-match-medium { +.mr-search-match-medium { color: #f1cf64; } -.ml-search-match-weak { +.mr-search-match-weak { color: #8fd0ff; } -.ml-search-match-neutral { - color: var(--ml-text-muted); +.mr-search-match-neutral { + color: var(--mr-text-muted); } -.ml-search-result-actions { +.mr-search-result-actions { display: flex; align-items: center; justify-content: flex-end; gap: 6px; min-height: 24px; } -#model-linker-modal .ml-search-result-action-btn { +#model-resolver-modal .mr-search-result-action-btn { display: inline-flex; align-items: center; justify-content: center; @@ -2019,11 +2019,11 @@ flex: 0 0 24px; margin: 0; padding: 0; - border: 1px solid var(--ml-missing-control-border, rgba(255,255,255,0.1)); - border-radius: var(--ml-missing-control-radius, 7px); - background: var(--ml-missing-control-bg, rgba(255,255,255,0.03)); - color: var(--ml-text); - box-shadow: var(--ml-missing-control-shadow, inset 0 1px 0 rgba(255,255,255,0.02)); + border: 1px solid var(--mr-missing-control-border, rgba(255,255,255,0.1)); + border-radius: var(--mr-missing-control-radius, 7px); + background: var(--mr-missing-control-bg, rgba(255,255,255,0.03)); + color: var(--mr-text); + box-shadow: var(--mr-missing-control-shadow, inset 0 1px 0 rgba(255,255,255,0.02)); box-sizing: border-box; cursor: pointer; appearance: none; @@ -2036,26 +2036,26 @@ vertical-align: middle; white-space: nowrap; overflow: hidden; - transition: var(--ml-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); + transition: var(--mr-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); } -#model-linker-modal .ml-search-result-action-btn:hover:not(:disabled) { - background: var(--ml-missing-control-bg-hover, rgba(255,255,255,0.05)); - border-color: var(--ml-missing-control-border-hover, rgba(255,255,255,0.16)); +#model-resolver-modal .mr-search-result-action-btn:hover:not(:disabled) { + background: var(--mr-missing-control-bg-hover, rgba(255,255,255,0.05)); + border-color: var(--mr-missing-control-border-hover, rgba(255,255,255,0.16)); transform: none; } -#model-linker-modal .ml-search-result-action-btn svg { - width: var(--ml-missing-icon-size, 13px); - height: var(--ml-missing-icon-size, 13px); +#model-resolver-modal .mr-search-result-action-btn svg { + width: var(--mr-missing-icon-size, 13px); + height: var(--mr-missing-icon-size, 13px); display: block; - flex: 0 0 var(--ml-missing-icon-size, 13px); + flex: 0 0 var(--mr-missing-icon-size, 13px); pointer-events: none; } -.ml-search-progress-list { +.mr-search-progress-list { display: grid; gap: 6px; margin: 8px 0; } -.ml-search-progress-list-compact { +.mr-search-progress-list-compact { display: flex; gap: 6px; align-items: center; @@ -2063,13 +2063,13 @@ overflow-x: auto; scrollbar-width: thin; } -.ml-search-progress-item { +.mr-search-progress-item { padding: 6px 8px; background: rgba(255,255,255,0.035); - border: 1px solid var(--ml-border); + border: 1px solid var(--mr-border); border-radius: 8px; } -.ml-search-progress-list-compact .ml-search-progress-item { +.mr-search-progress-list-compact .mr-search-progress-item { display: inline-flex; align-items: center; gap: 6px; @@ -2079,144 +2079,144 @@ padding: 3px 8px; border-radius: 999px; } -.ml-missing-browser .ml-search-progress-list-compact .ml-search-progress-item { - background: var(--ml-missing-surface, rgba(255,255,255,0.024)); - border-color: var(--ml-missing-line, rgba(255,255,255,0.075)); +.mr-missing-browser .mr-search-progress-list-compact .mr-search-progress-item { + background: var(--mr-missing-surface, rgba(255,255,255,0.024)); + border-color: var(--mr-missing-line, rgba(255,255,255,0.075)); } -.ml-search-progress-list-compact .ml-search-progress-item::before { +.mr-search-progress-list-compact .mr-search-progress-item::before { content: ""; flex: 0 0 6px; width: 6px; height: 6px; border-radius: 999px; - background: var(--ml-text-muted); + background: var(--mr-text-muted); } -.ml-search-progress-list-compact .ml-search-progress-found::before { +.mr-search-progress-list-compact .mr-search-progress-found::before { background: #72d38a; } -.ml-search-progress-list-compact .ml-search-progress-none::before { +.mr-search-progress-list-compact .mr-search-progress-none::before { background: rgba(255,255,255,0.48); } -.ml-search-progress-list-compact .ml-search-progress-error::before { +.mr-search-progress-list-compact .mr-search-progress-error::before { background: #ff8a80; } -.ml-search-progress-list-compact .ml-search-progress-source, -.ml-search-progress-list-compact .ml-search-progress-status { +.mr-search-progress-list-compact .mr-search-progress-source, +.mr-search-progress-list-compact .mr-search-progress-status { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 10px; } -.ml-search-progress-list-compact .ml-search-progress-source { - color: var(--ml-text); +.mr-search-progress-list-compact .mr-search-progress-source { + color: var(--mr-text); font-weight: 700; } -.ml-search-progress-list-compact .ml-search-progress-status { - color: var(--ml-text-muted); +.mr-search-progress-list-compact .mr-search-progress-status { + color: var(--mr-text-muted); } -.ml-search-progress-list-compact .ml-search-progress-found .ml-search-progress-status { +.mr-search-progress-list-compact .mr-search-progress-found .mr-search-progress-status { color: #72d38a; } -.ml-search-progress-list-compact .ml-search-progress-error .ml-search-progress-status { +.mr-search-progress-list-compact .mr-search-progress-error .mr-search-progress-status { color: #ff8a80; } -.ml-search-progress-head { +.mr-search-progress-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 5px; font-size: 11px; - color: var(--ml-text-muted); + color: var(--mr-text-muted); } -.ml-search-progress-head span { +.mr-search-progress-head span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.ml-search-progress-head span:first-child { - color: var(--ml-text); +.mr-search-progress-head span:first-child { + color: var(--mr-text); font-weight: 600; } -.ml-search-progress-head span:last-child { +.mr-search-progress-head span:last-child { flex: 0 1 auto; max-width: 55%; text-align: right; } -.ml-search-progress-bar { +.mr-search-progress-bar { height: 5px; overflow: hidden; background: rgba(255,255,255,0.08); border-radius: 5px; } -.ml-search-progress-fill { +.mr-search-progress-fill { height: 100%; - background: var(--ml-accent); + background: var(--mr-accent); border-radius: inherit; transition: width 0.42s ease, background 0.2s ease; } -.ml-search-progress-running .ml-search-progress-fill { - background: linear-gradient(90deg, rgba(114,211,138,0.62), var(--ml-accent)); +.mr-search-progress-running .mr-search-progress-fill { + background: linear-gradient(90deg, rgba(114,211,138,0.62), var(--mr-accent)); } -.ml-search-progress-found .ml-search-progress-fill { +.mr-search-progress-found .mr-search-progress-fill { background: #72d38a; } -.ml-search-progress-none .ml-search-progress-fill { +.mr-search-progress-none .mr-search-progress-fill { background: rgba(255,255,255,0.32); } -.ml-search-progress-error .ml-search-progress-fill { +.mr-search-progress-error .mr-search-progress-fill { background: #ff8a80; } -.ml-combo-section { +.mr-combo-section { position: relative; margin-top: 8px; padding-top: 8px; - border-top: 1px solid var(--ml-divider); + border-top: 1px solid var(--mr-divider); } -.ml-missing-browser .ml-combo-section { - border-top-color: var(--ml-missing-line, var(--ml-divider)); +.mr-missing-browser .mr-combo-section { + border-top-color: var(--mr-missing-line, var(--mr-divider)); } -.ml-combo-row { +.mr-combo-row { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; } -.ml-combo-label { +.mr-combo-label { opacity: 0.9; font-size: 10px; - color: var(--ml-text-muted); + color: var(--mr-text-muted); font-weight: 600; min-width: 42px; letter-spacing: 0.08em; text-transform: uppercase; } -.ml-combo-input { +.mr-combo-input { flex: 1; min-width: 0; min-height: 30px; padding: 5px 10px; background: rgba(255,255,255,0.04); - color: var(--ml-text); - border: 1px solid var(--ml-border); + color: var(--mr-text); + border: 1px solid var(--mr-border); border-radius: 10px; font-size: 12px; outline: none; transition: border-color 0.16s ease, box-shadow 0.16s ease, background 0.16s ease; } -.ml-missing-browser .ml-combo-input { +.mr-missing-browser .mr-combo-input { min-height: 34px; background: rgba(255,255,255,0.035); - border-color: var(--ml-missing-line-strong, rgba(255,255,255,0.12)); - border-radius: var(--ml-missing-control-radius, 7px); + border-color: var(--mr-missing-line-strong, rgba(255,255,255,0.12)); + border-radius: var(--mr-missing-control-radius, 7px); } -.ml-combo-input:focus { +.mr-combo-input:focus { border-color: rgba(114,211,138,0.4); box-shadow: 0 0 0 3px rgba(114,211,138,0.12); } -.ml-combo-list { +.mr-combo-list { position: absolute; top: calc(100% + 4px); left: 44px; @@ -2225,50 +2225,50 @@ max-height: 220px; overflow: auto; display: none; - z-index: var(--ml-z-notification); - background: linear-gradient(180deg, var(--ml-panel-bg-strong) 0%, var(--ml-card-bg) 100%); - border: 1px solid var(--ml-border-strong); + z-index: var(--mr-z-notification); + background: linear-gradient(180deg, var(--mr-panel-bg-strong) 0%, var(--mr-card-bg) 100%); + border: 1px solid var(--mr-border-strong); border-radius: 12px; - box-shadow: var(--ml-shadow-elevated); + box-shadow: var(--mr-shadow-elevated); } -.ml-missing-browser .ml-combo-list { +.mr-missing-browser .mr-combo-list { background: #1b1b1b; - border-color: var(--ml-missing-line-strong, rgba(255,255,255,0.12)); - border-radius: var(--ml-missing-radius, 7px); + border-color: var(--mr-missing-line-strong, rgba(255,255,255,0.12)); + border-radius: var(--mr-missing-radius, 7px); box-shadow: 0 16px 36px rgba(0,0,0,0.3); } -.ml-combo-option { +.mr-combo-option { padding: 8px 10px; cursor: pointer; border-bottom: 1px solid rgba(255,255,255,0.04); font-size: 12px; - color: var(--ml-text); + color: var(--mr-text); background: transparent; transition: background 0.14s ease, color 0.14s ease; } -.ml-combo-option:last-child { +.mr-combo-option:last-child { border-bottom: none; } -.ml-combo-option:hover, -.ml-combo-option.is-highlighted { +.mr-combo-option:hover, +.mr-combo-option.is-highlighted { background: rgba(114,211,138,0.12); } -.ml-combo-option-row { +.mr-combo-option-row { display: flex; align-items: center; gap: 6px; } -.ml-combo-option code { +.mr-combo-option code { flex: 1 1 0%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - color: var(--ml-text); + color: var(--mr-text); } -.ml-combo-folder { +.mr-combo-folder { margin-top: 4px; font-size: 10px; - color: var(--ml-text-dim); + color: var(--mr-text-dim); opacity: 0.9; overflow: hidden; text-overflow: ellipsis; @@ -2276,7 +2276,7 @@ } /* Status Messages */ -.ml-status { +.mr-status { display: flex; align-items: flex-start; gap: 10px; @@ -2286,75 +2286,75 @@ margin-top: 8px; border: 1px solid rgba(255,255,255,0.06); } -.ml-status-icon { +.mr-status-icon { font-size: 16px; flex-shrink: 0; } -.ml-status-error { +.mr-status-error { background: rgba(244, 67, 54, 0.1); border: 1px solid rgba(244, 67, 54, 0.3); color: #ef9a9a; } -.ml-status-success { +.mr-status-success { background: rgba(76, 175, 80, 0.1); border: 1px solid rgba(76, 175, 80, 0.3); color: #a5d6a7; } -.ml-status-info { +.mr-status-info { background: rgba(33, 150, 243, 0.1); border: 1px solid rgba(33, 150, 243, 0.3); color: #90caf9; } -.ml-status-warning { +.mr-status-warning { background: rgba(255, 152, 0, 0.1); border: 1px solid rgba(255, 152, 0, 0.3); color: #ffcc80; } /* Progress Bar */ -.ml-progress-container { +.mr-progress-container { margin-top: 8px; } -.ml-progress-bar { +.mr-progress-bar { height: 6px; background: #333; border-radius: 3px; overflow: hidden; } -.ml-progress-fill { +.mr-progress-fill { height: 100%; - background: var(--ml-accent); + background: var(--mr-accent); transition: width 0.3s ease; } -.ml-progress-text { +.mr-progress-text { display: flex; justify-content: space-between; align-items: center; margin-top: 6px; font-size: 11px; - color: var(--ml-text-muted); + color: var(--mr-text-muted); } /* Scrollbar */ -.ml-scrollable { +.mr-scrollable { overflow-y: auto; } -.ml-scrollable::-webkit-scrollbar { +.mr-scrollable::-webkit-scrollbar { width: 8px; } -.ml-scrollable::-webkit-scrollbar-track { +.mr-scrollable::-webkit-scrollbar-track { background: transparent; } -.ml-scrollable::-webkit-scrollbar-thumb { +.mr-scrollable::-webkit-scrollbar-thumb { background: #444; border-radius: 4px; } -.ml-scrollable::-webkit-scrollbar-thumb:hover { +.mr-scrollable::-webkit-scrollbar-thumb:hover { background: #555; } /* Footer */ -.ml-footer { +.mr-footer { display: flex; justify-content: flex-end; align-items: center; @@ -2364,7 +2364,7 @@ background: linear-gradient(180deg, rgba(255,255,255,0.018) 0%, rgba(255,255,255,0.032) 100%); border-top: 1px solid rgba(255,255,255,0.08); } -.ml-footer-btn { +.mr-footer-btn { min-height: 34px; min-width: 138px; padding: 0 13px; @@ -2373,20 +2373,20 @@ line-height: 1; backdrop-filter: none; } -.ml-footer-menu-wrap { +.mr-footer-menu-wrap { position: relative; display: inline-flex; } -.ml-footer-menu-button { +.mr-footer-menu-button { justify-content: center; } -.ml-footer-menu-button::after { +.mr-footer-menu-button::after { content: "\25BE"; margin-left: 7px; font-size: 10px; opacity: 0.68; } -.ml-footer-menu { +.mr-footer-menu { display: none; position: absolute; right: 0; @@ -2399,25 +2399,25 @@ border-radius: 8px; background: rgba(31,31,35,0.98); box-shadow: 0 18px 38px rgba(0,0,0,0.34); - z-index: var(--ml-z-dropdown, 10020); + z-index: var(--mr-z-dropdown, 10020); } -.ml-footer-menu.is-open { +.mr-footer-menu.is-open { display: grid; gap: 2px; } -.ml-footer-menu-item { +.mr-footer-menu-item { min-height: 30px; padding: 0 10px; border: 0; border-radius: 6px; background: transparent; - color: var(--ml-text); + color: var(--mr-text); font: inherit; font-size: 12px; text-align: left; cursor: pointer; } -#model-linker-modal .ml-footer-menu .ml-footer-menu-item { +#model-resolver-modal .mr-footer-menu .mr-footer-menu-item { width: 100%; min-height: 30px; margin: 0; @@ -2428,48 +2428,48 @@ border-radius: 6px; background: transparent !important; box-shadow: none !important; - color: var(--ml-text); + color: var(--mr-text); font: inherit; font-size: 12px; line-height: 1.25; text-align: left; justify-content: flex-start; } -.ml-footer-menu-item:hover, -.ml-footer-menu-item:focus-visible { +.mr-footer-menu-item:hover, +.mr-footer-menu-item:focus-visible { outline: none; background: rgba(255,255,255,0.07); } -#model-linker-modal .ml-footer-menu .ml-footer-menu-item:hover, -#model-linker-modal .ml-footer-menu .ml-footer-menu-item:focus-visible { +#model-resolver-modal .mr-footer-menu .mr-footer-menu-item:hover, +#model-resolver-modal .mr-footer-menu .mr-footer-menu-item:focus-visible { outline: none; background: rgba(255,255,255,0.07) !important; } -.ml-footer-menu-divider { +.mr-footer-menu-divider { height: 1px; margin: 4px 2px; background: rgba(255,255,255,0.08); } -.ml-btn.ml-footer-btn, -.ml-btn.ml-btn-primary.ml-footer-btn, -.ml-btn.ml-btn-download.ml-footer-btn { +.mr-btn.mr-footer-btn, +.mr-btn.mr-btn-primary.mr-footer-btn, +.mr-btn.mr-btn-download.mr-footer-btn { background: rgba(255,255,255,0.035); - color: var(--ml-text); + color: var(--mr-text); border-color: rgba(255,255,255,0.11); box-shadow: none; } -.ml-btn.ml-footer-btn:hover:not(:disabled), -.ml-btn.ml-btn-primary.ml-footer-btn:hover:not(:disabled), -.ml-btn.ml-btn-download.ml-footer-btn:hover:not(:disabled) { +.mr-btn.mr-footer-btn:hover:not(:disabled), +.mr-btn.mr-btn-primary.mr-footer-btn:hover:not(:disabled), +.mr-btn.mr-btn-download.mr-footer-btn:hover:not(:disabled) { background: rgba(255,255,255,0.05); - color: var(--ml-text); + color: var(--mr-text); border-color: rgba(255,255,255,0.16); box-shadow: none; transform: none; } -.ml-btn.ml-footer-btn:disabled, -.ml-btn.ml-btn-primary.ml-footer-btn:disabled, -.ml-btn.ml-btn-download.ml-footer-btn:disabled { +.mr-btn.mr-footer-btn:disabled, +.mr-btn.mr-btn-primary.mr-footer-btn:disabled, +.mr-btn.mr-btn-download.mr-footer-btn:disabled { opacity: 1; color: rgba(255,255,255,0.34); background: rgba(255,255,255,0.016); @@ -2477,9 +2477,9 @@ box-shadow: none; cursor: not-allowed; } -.ml-btn.ml-footer-btn.ml-btn-is-disabled, -.ml-btn.ml-btn-primary.ml-footer-btn.ml-btn-is-disabled, -.ml-btn.ml-btn-download.ml-footer-btn.ml-btn-is-disabled { +.mr-btn.mr-footer-btn.mr-btn-is-disabled, +.mr-btn.mr-btn-primary.mr-footer-btn.mr-btn-is-disabled, +.mr-btn.mr-btn-download.mr-footer-btn.mr-btn-is-disabled { opacity: 1; color: rgba(255,255,255,0.34); background: rgba(255,255,255,0.016); @@ -2489,7 +2489,7 @@ } /* Tabs */ -.ml-tabs { +.mr-tabs { display: flex; align-self: stretch; align-items: flex-end; @@ -2502,13 +2502,13 @@ overflow: visible; position: relative; z-index: 2; - --ml-tab-active-bg: var(--ml-bg, #121212); - --ml-tab-corner-size: 15px; - --ml-tab-hover-bg: rgba(255,255,255,0.075); - --ml-tab-separator: rgba(255,255,255,0.125); + --mr-tab-active-bg: var(--mr-bg, #121212); + --mr-tab-corner-size: 15px; + --mr-tab-hover-bg: rgba(255,255,255,0.075); + --mr-tab-separator: rgba(255,255,255,0.125); cursor: default; } -.ml-tab { +.mr-tab { display: inline-flex; align-items: center; justify-content: center; @@ -2536,163 +2536,163 @@ -webkit-appearance: none; transition: none; } -.ml-tab-label { +.mr-tab-label { position: relative; z-index: 2; pointer-events: none; transform: translateZ(0); backface-visibility: hidden; } -.ml-tab:not(.ml-tab-active):hover { +.mr-tab:not(.mr-tab-active):hover { padding: 0 24px 5px !important; background: transparent !important; border-radius: 0; transform: none !important; } -.ml-tab:not(.ml-tab-active):focus, -.ml-tab:not(.ml-tab-active):active { +.mr-tab:not(.mr-tab-active):focus, +.mr-tab:not(.mr-tab-active):active { padding: 0 24px 5px !important; transform: none !important; } -.ml-tab:not(.ml-tab-active)::after { +.mr-tab:not(.mr-tab-active)::after { content: ""; position: absolute; inset: 1px 5px 6px; border-radius: 8px; - background: var(--ml-tab-hover-bg); + background: var(--mr-tab-hover-bg); opacity: 0; pointer-events: none; z-index: 1; } -.ml-tab:not(.ml-tab-active):hover::after { +.mr-tab:not(.mr-tab-active):hover::after { opacity: 1; } -.ml-tab:not(.ml-tab-active):hover::before, -.ml-tab:not(.ml-tab-active):hover + .ml-tab:not(.ml-tab-active)::before { +.mr-tab:not(.mr-tab-active):hover::before, +.mr-tab:not(.mr-tab-active):hover + .mr-tab:not(.mr-tab-active)::before { opacity: 0; } -.ml-tab:not(.ml-tab-active) + .ml-tab:not(.ml-tab-active)::before { +.mr-tab:not(.mr-tab-active) + .mr-tab:not(.mr-tab-active)::before { content: ""; position: absolute; left: 0; top: 8px; bottom: 14px; width: 1px; - background: var(--ml-tab-separator); + background: var(--mr-tab-separator); pointer-events: none; } -.ml-tab.ml-tab-active { +.mr-tab.mr-tab-active { height: 36px; min-height: 36px; padding: 0 24px 5px; margin-bottom: 0; - color: var(--ml-text, #eef2f7); - background: var(--ml-tab-active-bg) !important; + color: var(--mr-text, #eef2f7); + background: var(--mr-tab-active-bg) !important; border-radius: 10px 10px 0 0; cursor: default; pointer-events: none; - box-shadow: 0 1px 0 var(--ml-tab-active-bg) !important; + box-shadow: 0 1px 0 var(--mr-tab-active-bg) !important; transform: none; z-index: 4; transition: none; } -.ml-tab.ml-tab-active:hover, -.ml-tab.ml-tab-active:focus, -.ml-tab.ml-tab-active:active { - color: var(--ml-text, #eef2f7); - background: var(--ml-tab-active-bg) !important; - box-shadow: 0 1px 0 var(--ml-tab-active-bg) !important; +.mr-tab.mr-tab-active:hover, +.mr-tab.mr-tab-active:focus, +.mr-tab.mr-tab-active:active { + color: var(--mr-text, #eef2f7); + background: var(--mr-tab-active-bg) !important; + box-shadow: 0 1px 0 var(--mr-tab-active-bg) !important; } -.ml-tab.ml-tab-active::before, -.ml-tab.ml-tab-active::after { +.mr-tab.mr-tab-active::before, +.mr-tab.mr-tab-active::after { content: ""; position: absolute; bottom: -1px; - width: var(--ml-tab-corner-size); - height: var(--ml-tab-corner-size); - background: var(--ml-tab-active-bg); + width: var(--mr-tab-corner-size); + height: var(--mr-tab-corner-size); + background: var(--mr-tab-active-bg); pointer-events: none; } -.ml-tab.ml-tab-active::before { +.mr-tab.mr-tab-active::before { left: -13px; -webkit-mask: radial-gradient(circle at 0 0, transparent 13px, #000 13px); mask: radial-gradient(circle at 0 0, transparent 13px, #000 13px); } -.ml-tab.ml-tab-active::after { +.mr-tab.mr-tab-active::after { right: -13px; -webkit-mask: radial-gradient(circle at 100% 0, transparent 13px, #000 13px); mask: radial-gradient(circle at 100% 0, transparent 13px, #000 13px); } -#model-linker-modal .ml-tab, -#model-linker-modal .ml-footer-btn, -#model-linker-modal .ml-local-link-btn, -#model-linker-modal .ml-local-alternatives-toggle { +#model-resolver-modal .mr-tab, +#model-resolver-modal .mr-footer-btn, +#model-resolver-modal .mr-local-link-btn, +#model-resolver-modal .mr-local-alternatives-toggle { box-shadow: none !important; outline: none; } -#model-linker-modal .ml-tab { +#model-resolver-modal .mr-tab { border-width: 0 !important; margin: 0 !important; } -#model-linker-modal .ml-tab:not(.ml-tab-active) { +#model-resolver-modal .mr-tab:not(.mr-tab-active) { background: transparent !important; border-radius: 0 !important; } -#model-linker-modal .ml-tab:not(.ml-tab-active):hover { +#model-resolver-modal .mr-tab:not(.mr-tab-active):hover { background: transparent !important; border-radius: 0 !important; } -#model-linker-modal .ml-tab.ml-tab-active { +#model-resolver-modal .mr-tab.mr-tab-active { margin-bottom: 0 !important; - box-shadow: 0 1px 0 var(--ml-tab-active-bg) !important; + box-shadow: 0 1px 0 var(--mr-tab-active-bg) !important; } /* Loaded Models Tab */ -.ml-loaded-models { +.mr-loaded-models { padding: 0; } -.ml-loaded-models-header { +.mr-loaded-models-header { display: flex; align-items: center; justify-content: space-between; - gap: var(--ml-spacing-12); + gap: var(--mr-spacing-12); padding: 10px 12px; - border-bottom: 1px solid var(--ml-border); + border-bottom: 1px solid var(--mr-border); } -.ml-loaded-title-block { +.mr-loaded-title-block { min-width: 0; } -.ml-loaded-models-title { +.mr-loaded-models-title { font-size: 15px; font-weight: 600; - color: var(--ml-text); + color: var(--mr-text); margin: 0; } -.ml-loaded-total { +.mr-loaded-total { display: inline-flex; align-items: center; justify-content: center; min-width: 22px; height: 20px; - margin-left: var(--ml-spacing-6); - padding: 0 var(--ml-spacing-7); + margin-left: var(--mr-spacing-6); + padding: 0 var(--mr-spacing-7); border-radius: 999px; background: rgba(114, 211, 138, 0.12); color: #dffbe5; - font-size: var(--ml-font-xs); + font-size: var(--mr-font-xs); } -.ml-loaded-models-subtitle { - margin: var(--ml-spacing-4) 0 0; +.mr-loaded-models-subtitle { + margin: var(--mr-spacing-4) 0 0; font-size: 12px; - color: var(--ml-text-muted); + color: var(--mr-text-muted); } -.ml-models-list { +.mr-models-list { padding: 8px 12px 10px; display: flex; flex-direction: column; gap: 6px; } -.ml-model-chip { +.mr-model-chip { display: inline-flex; align-items: center; padding: 5px 10px; @@ -2700,9 +2700,9 @@ border-radius: 6px; font-family: 'SF Mono', 'Consolas', 'Monaco', monospace; font-size: 12px; - color: var(--ml-text); + color: var(--mr-text); } -.ml-model-chip-category { +.mr-model-chip-category { padding: 2px 6px; background: #555; border-radius: 4px; @@ -2711,7 +2711,7 @@ margin-left: 8px; text-transform: uppercase; } -.ml-model-chip-strength { +.mr-model-chip-strength { padding: 2px 6px; background: #4CAF50; border-radius: 4px; @@ -2721,43 +2721,43 @@ } @media (max-width: 720px) { - .ml-loaded-models-header { + .mr-loaded-models-header { align-items: stretch; flex-direction: column; } } -.model-linker-selected { +.model-resolver-selected { margin: 8px 0; padding: 10px 12px; background: rgba(78, 161, 255, 0.12); border: 1px solid rgba(78, 161, 255, 0.28); border-radius: 0; - color: var(--ml-text); + color: var(--mr-text); font-size: 12px; } /* Link styling */ -.ml-link { - color: var(--ml-link-color); +.mr-link { + color: var(--mr-link-color); text-decoration: none; } -.ml-link:hover { +.mr-link:hover { text-decoration: underline; } /* Context menu */ -.ml-context-menu { +.mr-context-menu { position: fixed; background: var(--comfy-menu-bg, #202020); border: 1px solid var(--border-color, #555555); border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.5); - z-index: var(--ml-z-context-menu); + z-index: var(--mr-z-context-menu); min-width: 160px; overflow: hidden; } -.ml-context-menu-item { +.mr-context-menu-item { display: flex; align-items: center; gap: 8px; @@ -2767,34 +2767,34 @@ cursor: pointer; transition: background 0.15s ease; } -.ml-context-menu-item:hover { +.mr-context-menu-item:hover { background: rgba(255,255,255,0.1); } -.ml-context-menu-item-icon { +.mr-context-menu-item-icon { font-size: 14px; width: 20px; text-align: center; } -.ml-context-menu-divider { +.mr-context-menu-divider { height: 1px; background: var(--border-color, #555555); margin: 4px 0; } /* Model Info Dialog (similar to rgthree's RgthreeLoraInfoDialog) */ -.ml-info-dialog-backdrop { +.mr-info-dialog-backdrop { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0, 0, 0, 0.6); - z-index: var(--ml-z-tooltip); + z-index: var(--mr-z-tooltip); display: flex; align-items: center; justify-content: center; } -.ml-info-dialog { +.mr-info-dialog { background: var(--comfy-menu-bg, #202020); border: 2px solid var(--border-color, #555555); border-radius: 8px; @@ -2809,7 +2809,7 @@ box-shadow: 0 8px 32px rgba(0,0,0,0.5); resize: both; } -.ml-info-dialog-header { +.mr-info-dialog-header { display: flex; justify-content: space-between; align-items: center; @@ -2817,12 +2817,12 @@ border-bottom: 1px solid var(--border-color, #555555); background: rgba(0,0,0,0.2); } -.ml-info-dialog-header h3 { +.mr-info-dialog-header h3 { margin: 0; font-size: 16px; color: var(--input-text, #e0e0e0); } -.ml-info-dialog-close { +.mr-info-dialog-close { background: none; border: none; font-size: 24px; @@ -2836,64 +2836,64 @@ justify-content: center; border-radius: 4px; } -.ml-info-dialog-close:hover { +.mr-info-dialog-close:hover { background: rgba(255,255,255,0.1); } -.ml-info-dialog-content { +.mr-info-dialog-content { padding: 16px 20px; overflow-y: auto; flex: 1; } -.ml-info-dialog-loading { +.mr-info-dialog-loading { text-align: center; - color: var(--ml-text-muted, #888); + color: var(--mr-text-muted, #888); padding: 20px; } -.ml-info-section { +.mr-info-section { margin-bottom: 16px; padding-bottom: 16px; border-bottom: 1px solid var(--border-color, #555555); } -.ml-info-section-header { +.mr-info-section-header { font-size: 12px; font-weight: 600; - color: var(--ml-text-muted, #888); + color: var(--mr-text-muted, #888); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 12px; } -.ml-info-row { +.mr-info-row { display: flex; justify-content: space-between; align-items: center; padding: 6px 0; } -.ml-info-label { - color: var(--ml-text-muted, #888); +.mr-info-label { + color: var(--mr-text-muted, #888); font-size: 13px; } -.ml-info-value { +.mr-info-value { color: var(--input-text, #e0e0e0); font-size: 13px; font-weight: 500; } -.ml-info-value.ml-info-active { +.mr-info-value.mr-info-active { color: #4CAF50; } -.ml-info-value.ml-info-inactive { +.mr-info-value.mr-info-inactive { color: #888; } -.ml-info-section-civitai { +.mr-info-section-civitai { border-bottom: none; margin-bottom: 0; padding-bottom: 0; } -.ml-info-civitai-link { +.mr-info-civitai-link { display: flex; flex-direction: column; gap: 8px; } -.ml-info-link { +.mr-info-link { display: inline-flex; align-items: center; gap: 6px; @@ -2904,26 +2904,26 @@ text-decoration: none; font-size: 13px; } -.ml-info-link:hover { +.mr-info-link:hover { background: #1976D2; } -.ml-info-loading-small { - color: var(--ml-text-muted, #888); +.mr-info-loading-small { + color: var(--mr-text-muted, #888); font-size: 12px; font-style: italic; } -.ml-info-not-found { +.mr-info-not-found { color: #888; font-size: 12px; } /* Info Area (type/base model tags) */ -.ml-info-area { +.mr-info-area { display: flex; gap: 8px; margin-bottom: 16px; } -.ml-info-tag { +.mr-info-tag { display: inline-flex; align-items: center; padding: 4px 10px; @@ -2933,88 +2933,88 @@ font-weight: 600; color: var(--input-text, #e0e0e0); } -.ml-info-tag.-type-lora { background: rgba(var(--ml-type-lora-rgb, 194, 255, 174), 0.16); color: var(--ml-type-lora-text, #d7ffcb); } -.ml-info-tag.-type-checkpoint { background: rgba(var(--ml-type-model-rgb, 179, 157, 219), 0.16); color: var(--ml-type-model-text, #dbcfff); } -.ml-info-tag.-type-vae { background: rgba(var(--ml-type-vae-rgb, 255, 110, 110), 0.16); color: var(--ml-type-vae-text, #ffb8b8); } -.ml-info-tag.-basemodel-sd1 { background: rgba(244,67,54,0.2); color: #EF9A9A; } -.ml-info-tag.-basemodel-sdxl { background: rgba(33,150,243,0.2); color: #64B5F6; } -.ml-info-tag.-basemodel-sdxl-turbo { background: rgba(33,150,243,0.2); color: #64B5F6; } -.ml-info-tag.-basemodel-flux\.1 { background: rgba(255,152,0,0.2); color: #FFB74D; } -.ml-info-tag.-basemodel-flux\.1-d { background: rgba(255,152,0,0.2); color: #FFB74D; } +.mr-info-tag.-type-lora { background: rgba(var(--mr-type-lora-rgb, 194, 255, 174), 0.16); color: var(--mr-type-lora-text, #d7ffcb); } +.mr-info-tag.-type-checkpoint { background: rgba(var(--mr-type-model-rgb, 179, 157, 219), 0.16); color: var(--mr-type-model-text, #dbcfff); } +.mr-info-tag.-type-vae { background: rgba(var(--mr-type-vae-rgb, 255, 110, 110), 0.16); color: var(--mr-type-vae-text, #ffb8b8); } +.mr-info-tag.-basemodel-sd1 { background: rgba(244,67,54,0.2); color: #EF9A9A; } +.mr-info-tag.-basemodel-sdxl { background: rgba(33,150,243,0.2); color: #64B5F6; } +.mr-info-tag.-basemodel-sdxl-turbo { background: rgba(33,150,243,0.2); color: #64B5F6; } +.mr-info-tag.-basemodel-flux\.1 { background: rgba(255,152,0,0.2); color: #FFB74D; } +.mr-info-tag.-basemodel-flux\.1-d { background: rgba(255,152,0,0.2); color: #FFB74D; } /* Info Table */ -.ml-info-table { +.mr-info-table { width: 100%; border-collapse: collapse; margin-bottom: 16px; } -.ml-info-table tr { +.mr-info-table tr { border-bottom: 1px solid rgba(255,255,255,0.05); } -.ml-info-table tr:last-child { +.mr-info-table tr:last-child { border-bottom: none; } -.ml-info-table td { +.mr-info-table td { padding: 8px 4px; font-size: 13px; vertical-align: top; } -.ml-info-table td:first-child { - color: var(--ml-text-muted, #888); +.mr-info-table td:first-child { + color: var(--mr-text-muted, #888); white-space: nowrap; width: 140px; } -.ml-info-table td:last-child { +.mr-info-table td:last-child { color: var(--input-text, #e0e0e0); word-break: break-word; } -.ml-info-trained-words-label { +.mr-info-trained-words-label { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; } -.ml-info-trained-words-meta { +.mr-info-trained-words-meta { display: inline-flex; align-items: center; gap: 8px; font-size: 11px; - color: var(--ml-text-muted, #888); + color: var(--mr-text-muted, #888); } -.ml-info-trained-words-hint { +.mr-info-trained-words-hint { margin-bottom: 8px; font-size: 11px; - color: var(--ml-text-muted, #888); + color: var(--mr-text-muted, #888); } -.ml-info-copy-trained-words { +.mr-info-copy-trained-words { border: 1px solid rgba(255,255,255,0.12); background: rgba(255,255,255,0.05); - color: var(--ml-link-color, #8fc2ff); + color: var(--mr-link-color, #8fc2ff); border-radius: 999px; padding: 2px 10px; font-size: 11px; cursor: pointer; transition: background 0.16s ease, border-color 0.16s ease, color 0.16s ease; } -.ml-info-copy-trained-words:hover:not(:disabled) { +.mr-info-copy-trained-words:hover:not(:disabled) { background: rgba(78,161,255,0.14); border-color: rgba(78,161,255,0.28); color: #d6eaff; } -.ml-info-copy-trained-words:disabled { +.mr-info-copy-trained-words:disabled { opacity: 0.45; cursor: default; } -.ml-info-trained-words-list { +.mr-info-trained-words-list { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start; } -.ml-info-trained-word { +.mr-info-trained-word { border: 1px solid rgba(255,255,255,0.1); background: rgba(255,255,255,0.04); - color: var(--ml-text); + color: var(--mr-text); border-radius: 999px; padding: 6px 10px; font-size: 12px; @@ -3022,30 +3022,30 @@ cursor: pointer; transition: transform 0.14s ease, background 0.14s ease, border-color 0.14s ease, box-shadow 0.14s ease; } -.ml-info-trained-word:hover { +.mr-info-trained-word:hover { transform: translateY(-1px); background: rgba(255,255,255,0.07); border-color: rgba(255,255,255,0.18); } -.ml-info-trained-word.is-selected { +.mr-info-trained-word.is-selected { background: rgba(78,161,255,0.18); border-color: rgba(78,161,255,0.4); color: #d8ebff; box-shadow: 0 0 0 1px rgba(78,161,255,0.15) inset; } -.ml-info-description-wrap { +.mr-info-description-wrap { display: flex; flex-direction: column; gap: 8px; } -.ml-info-description { +.mr-info-description { line-height: 1.55; color: var(--input-text, #e0e0e0); max-height: 220px; overflow: hidden; position: relative; } -.ml-info-description:not(.is-expanded)::after { +.mr-info-description:not(.is-expanded)::after { content: ""; position: absolute; left: 0; @@ -3055,91 +3055,91 @@ background: linear-gradient(180deg, rgba(32,32,32,0) 0%, rgba(32,32,32,0.92) 100%); pointer-events: none; } -.ml-info-description.is-expanded { +.mr-info-description.is-expanded { max-height: none; overflow: visible; } -.ml-info-description p, -.ml-info-description ul, -.ml-info-description ol, -.ml-info-description blockquote, -.ml-info-description pre { +.mr-info-description p, +.mr-info-description ul, +.mr-info-description ol, +.mr-info-description blockquote, +.mr-info-description pre { margin: 0 0 10px 0; } -.ml-info-description h1, -.ml-info-description h2, -.ml-info-description h3, -.ml-info-description h4, -.ml-info-description h5, -.ml-info-description h6 { +.mr-info-description h1, +.mr-info-description h2, +.mr-info-description h3, +.mr-info-description h4, +.mr-info-description h5, +.mr-info-description h6 { margin: 14px 0 8px 0; - color: var(--ml-text); + color: var(--mr-text); line-height: 1.3; } -.ml-info-description ul, -.ml-info-description ol { +.mr-info-description ul, +.mr-info-description ol { padding-left: 18px; } -.ml-info-description code, -.ml-info-description pre { +.mr-info-description code, +.mr-info-description pre { background: rgba(255,255,255,0.05); border-radius: 6px; } -.ml-info-description code { +.mr-info-description code { padding: 1px 5px; font-family: 'SF Mono', 'Consolas', 'Monaco', monospace; font-size: 12px; } -.ml-info-description pre { +.mr-info-description pre { padding: 10px 12px; overflow-x: auto; white-space: pre-wrap; } -.ml-info-description a { - color: var(--ml-link-color, #8fc2ff); +.mr-info-description a { + color: var(--mr-link-color, #8fc2ff); text-decoration: none; } -.ml-info-description a:hover { +.mr-info-description a:hover { text-decoration: underline; } -.ml-info-description-actions { +.mr-info-description-actions { display: flex; justify-content: flex-end; } -.ml-info-description-toggle { +.mr-info-description-toggle { border: 1px solid rgba(255,255,255,0.12); background: rgba(255,255,255,0.05); - color: var(--ml-link-color, #8fc2ff); + color: var(--mr-link-color, #8fc2ff); border-radius: 999px; padding: 4px 12px; font-size: 11px; cursor: pointer; transition: background 0.16s ease, border-color 0.16s ease, color 0.16s ease; } -.ml-info-description-toggle:hover { +.mr-info-description-toggle:hover { background: rgba(78,161,255,0.14); border-color: rgba(78,161,255,0.28); color: #d6eaff; } /* Images Section */ -.ml-info-images { +.mr-info-images { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border-color, #555555); } -.ml-info-images-header { +.mr-info-images-header { font-size: 12px; font-weight: 600; - color: var(--ml-text-muted, #888); + color: var(--mr-text-muted, #888); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 12px; } -.ml-info-images-layout { +.mr-info-images-layout { column-count: 3; column-gap: 14px; } -.ml-info-image-item { +.mr-info-image-item { border-radius: 6px; overflow: hidden; background: rgba(0,0,0,0.2); @@ -3147,20 +3147,20 @@ break-inside: avoid; margin-bottom: 14px; } -.ml-info-image-item figure { +.mr-info-image-item figure { margin: 0; position: relative; display: block; background: rgba(0,0,0,0.3); } -.ml-info-image-item img { +.mr-info-image-item img { width: 100%; height: auto; display: block; object-fit: contain; transition: transform 0.24s ease, filter 0.24s ease; } -.ml-info-image-item figcaption { +.mr-info-image-item figcaption { position: absolute; inset: auto 0 0 0; max-height: 60%; @@ -3174,18 +3174,18 @@ transition: opacity 0.2s ease, transform 0.2s ease; pointer-events: none; } -.ml-info-image-item figcaption span { +.mr-info-image-item figcaption span { display: block; margin-bottom: 4px; line-height: 1.4; } -.ml-info-image-item figcaption span label { +.mr-info-image-item figcaption span label { font-weight: 600; color: #b9c8d8; margin-right: 4px; text-transform: lowercase; } -.ml-info-image-link { +.mr-info-image-link { color: #8fc2ff; text-decoration: none; display: inline-flex; @@ -3193,55 +3193,55 @@ pointer-events: auto; font-weight: 700; } -.ml-info-image-item:hover img { +.mr-info-image-item:hover img { transform: scale(1.01); filter: brightness(0.82); } -.ml-info-image-item:hover figcaption, -.ml-info-image-item:focus-within figcaption { +.mr-info-image-item:hover figcaption, +.mr-info-image-item:focus-within figcaption { opacity: 1; transform: translateY(0); } @media (max-width: 900px) { - .ml-info-images-layout { + .mr-info-images-layout { column-count: 2; } } @media (max-width: 640px) { - .ml-info-images-layout { + .mr-info-images-layout { column-count: 1; } } /* CivitAI Logo */ -.ml-info-civitai-logo { +.mr-info-civitai-logo { width: 16px; height: 16px; } /* Footer */ -.ml-info-dialog-footer { +.mr-info-dialog-footer { padding: 12px 20px; border-top: 1px solid var(--border-color, #555555); display: flex; justify-content: flex-end; gap: 8px; } -.ml-info-dialog-close-btn { +.mr-info-dialog-close-btn { padding: 8px 16px; } -.ml-info-error { +.mr-info-error { color: #f44336; font-size: 12px; } -.ml-options-wrap { +.mr-options-wrap { max-width: 1120px; margin: 0 auto; padding: 0 0 0 0; height: 100%; } -.ml-options-shell { +.mr-options-shell { display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: 0; @@ -3251,7 +3251,7 @@ overflow: hidden; background: #171717; } -.ml-options-sidebar { +.mr-options-sidebar { display: flex; flex-direction: column; align-items: stretch; @@ -3263,7 +3263,7 @@ overflow: hidden; min-width: 0; } -.ml-options-sidebar-title { +.mr-options-sidebar-title { margin: 0; padding: 0 12px; color: rgba(255,255,255,0.58); @@ -3273,14 +3273,14 @@ line-height: 1.2; text-transform: uppercase; } -.ml-options-sidebar-group { +.mr-options-sidebar-group { display: grid; gap: 10px; min-height: 0; align-content: start; flex: 0 0 auto; } -.ml-options-sidebar-label { +.mr-options-sidebar-label { padding: 0 12px; font-size: 10px; font-weight: 700; @@ -3288,14 +3288,14 @@ text-transform: uppercase; color: rgba(255,255,255,0.34); } -.ml-options-nav { +.mr-options-nav { display: grid; gap: 2px; align-content: start; grid-auto-rows: min-content; } -.ml-options-nav-btn, -#model-linker-modal .ml-options-nav-btn { +.mr-options-nav-btn, +#model-resolver-modal .mr-options-nav-btn { display: flex; align-items: center; justify-content: space-between; @@ -3313,35 +3313,35 @@ line-height: 1; text-align: left; cursor: pointer; - transition: var(--ml-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); + transition: var(--mr-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); } -.ml-options-nav-btn:hover, -#model-linker-modal .ml-options-nav-btn:hover { - color: var(--ml-text); +.mr-options-nav-btn:hover, +#model-resolver-modal .mr-options-nav-btn:hover { + color: var(--mr-text); background: rgba(255,255,255,0.085); border-color: transparent; } -.ml-options-nav-btn:focus-visible, -#model-linker-modal .ml-options-nav-btn:focus-visible { +.mr-options-nav-btn:focus-visible, +#model-resolver-modal .mr-options-nav-btn:focus-visible { outline: none; border-color: rgba(255,255,255,0.12); box-shadow: 0 0 0 2px rgba(255,255,255,0.06); } -.ml-options-nav-btn.is-active, -#model-linker-modal .ml-options-nav-btn.is-active { +.mr-options-nav-btn.is-active, +#model-resolver-modal .mr-options-nav-btn.is-active { color: #ffffff; background: #3d3d44; border-color: transparent; } -.ml-options-nav-main, -#model-linker-modal .ml-options-nav-main { +.mr-options-nav-main, +#model-resolver-modal .mr-options-nav-main { display: inline-flex; align-items: center; min-width: 0; gap: 10px; } -.ml-options-nav-icon, -#model-linker-modal .ml-options-nav-icon { +.mr-options-nav-icon, +#model-resolver-modal .mr-options-nav-icon { display: inline-flex; align-items: center; justify-content: center; @@ -3350,50 +3350,50 @@ flex: 0 0 16px; color: currentColor; } -.ml-options-nav-icon svg, -#model-linker-modal .ml-options-nav-icon svg { +.mr-options-nav-icon svg, +#model-resolver-modal .mr-options-nav-icon svg { display: block; width: 15px; height: 15px; } -.ml-options-provider-icon-civitai svg path:nth-of-type(1), -#model-linker-modal .ml-options-provider-icon-civitai svg path:nth-of-type(1) { +.mr-options-provider-icon-civitai svg path:nth-of-type(1), +#model-resolver-modal .mr-options-provider-icon-civitai svg path:nth-of-type(1) { fill: transparent; stroke: rgba(255,255,255,0.2); stroke-width: 3; } -.ml-options-provider-icon-civitai svg path:nth-of-type(2), -.ml-options-provider-icon-civitai svg path:nth-of-type(3), -#model-linker-modal .ml-options-provider-icon-civitai svg path:nth-of-type(2), -#model-linker-modal .ml-options-provider-icon-civitai svg path:nth-of-type(3) { +.mr-options-provider-icon-civitai svg path:nth-of-type(2), +.mr-options-provider-icon-civitai svg path:nth-of-type(3), +#model-resolver-modal .mr-options-provider-icon-civitai svg path:nth-of-type(2), +#model-resolver-modal .mr-options-provider-icon-civitai svg path:nth-of-type(3) { fill: #ffffff; } -.ml-options-provider-icon-huggingface svg path, -#model-linker-modal .ml-options-provider-icon-huggingface svg path { +.mr-options-provider-icon-huggingface svg path, +#model-resolver-modal .mr-options-provider-icon-huggingface svg path { fill: #ffffff; stroke: rgba(0,0,0,0.42); stroke-width: 1.4; paint-order: stroke fill; vector-effect: non-scaling-stroke; } -.ml-options-provider-icon-huggingface svg path:nth-of-type(3), -.ml-options-provider-icon-huggingface svg path:nth-of-type(4), -.ml-options-provider-icon-huggingface svg path:nth-of-type(5), -#model-linker-modal .ml-options-provider-icon-huggingface svg path:nth-of-type(3), -#model-linker-modal .ml-options-provider-icon-huggingface svg path:nth-of-type(4), -#model-linker-modal .ml-options-provider-icon-huggingface svg path:nth-of-type(5) { +.mr-options-provider-icon-huggingface svg path:nth-of-type(3), +.mr-options-provider-icon-huggingface svg path:nth-of-type(4), +.mr-options-provider-icon-huggingface svg path:nth-of-type(5), +#model-resolver-modal .mr-options-provider-icon-huggingface svg path:nth-of-type(3), +#model-resolver-modal .mr-options-provider-icon-huggingface svg path:nth-of-type(4), +#model-resolver-modal .mr-options-provider-icon-huggingface svg path:nth-of-type(5) { fill: #202024; stroke: rgba(255,255,255,0.22); } -.ml-options-nav-meta, -#model-linker-modal .ml-options-nav-meta { +.mr-options-nav-meta, +#model-resolver-modal .mr-options-nav-meta { display: none; } -.ml-options-nav-btn.is-active .ml-options-nav-meta, -#model-linker-modal .ml-options-nav-btn.is-active .ml-options-nav-meta { +.mr-options-nav-btn.is-active .mr-options-nav-meta, +#model-resolver-modal .mr-options-nav-btn.is-active .mr-options-nav-meta { display: none; } -.ml-options-main { +.mr-options-main { display: grid; gap: 0; min-height: 0; @@ -3409,22 +3409,22 @@ scrollbar-width: auto; scrollbar-color: rgba(255,255,255,0.34) rgba(255,255,255,0.08); } -.ml-options-main::-webkit-scrollbar { +.mr-options-main::-webkit-scrollbar { width: 12px; } -.ml-options-main::-webkit-scrollbar-track { +.mr-options-main::-webkit-scrollbar-track { background: rgba(255,255,255,0.06); border-radius: 999px; } -.ml-options-main::-webkit-scrollbar-thumb { +.mr-options-main::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.34); border-radius: 999px; border: 2px solid rgba(23,23,23,0.95); } -.ml-options-main::-webkit-scrollbar-thumb:hover { +.mr-options-main::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.48); } -.ml-options-card { +.mr-options-card { background: transparent; border: none; border-radius: 0; @@ -3432,13 +3432,13 @@ box-shadow: none; align-self: start; } -.ml-options-title { +.mr-options-title { margin: 0; font-size: 17px; font-weight: 700; - color: var(--ml-text); + color: var(--mr-text); } -.ml-options-section { +.mr-options-section { display: grid; gap: 0; align-content: start; @@ -3446,20 +3446,20 @@ scroll-margin-top: 24px; min-width: 0; } -.ml-options-section.is-hidden { +.mr-options-section.is-hidden { display: none; } -.ml-options-section-head { +.mr-options-section-head { display: block; padding: 0 0 10px 0; } -.ml-options-section-title { +.mr-options-section-title { margin: 0; font-size: 20px; font-weight: 700; - color: var(--ml-text); + color: var(--mr-text); } -.ml-options-grid { +.mr-options-grid { display: grid; grid-template-columns: 1fr; gap: 0; @@ -3467,13 +3467,13 @@ align-items: start; min-width: 0; } -.ml-options-stack { +.mr-options-stack { display: grid; gap: 0; align-content: start; min-width: 0; } -.ml-options-panel { +.mr-options-panel { display: grid; gap: 0; align-content: start; @@ -3482,17 +3482,17 @@ background: transparent; min-width: 0; } -.ml-options-panel-title { +.mr-options-panel-title { margin: 0 0 6px 0; font-size: 16px; font-weight: 700; - color: var(--ml-text); + color: var(--mr-text); } -.ml-options-comfyui-icon svg, -.ml-options-comfyui-icon svg path { +.mr-options-comfyui-icon svg, +.mr-options-comfyui-icon svg path { fill: currentColor; } -.ml-options-db-summary { +.mr-options-db-summary { display: grid; gap: 1px; border: 1px solid rgba(255,255,255,0.08); @@ -3500,7 +3500,7 @@ overflow: hidden; background: rgba(255,255,255,0.03); } -.ml-options-db-row { +.mr-options-db-row { display: flex; align-items: center; justify-content: space-between; @@ -3508,36 +3508,36 @@ min-height: 34px; padding: 7px 10px; background: rgba(0,0,0,0.16); - color: var(--ml-text-secondary); + color: var(--mr-text-secondary); font-size: 12px; } -.ml-options-db-row strong { - color: var(--ml-text); +.mr-options-db-row strong { + color: var(--mr-text); font-size: 12px; font-weight: 700; text-align: right; } -.ml-options-db-message { +.mr-options-db-message { margin-top: 10px; - color: var(--ml-text-secondary); + color: var(--mr-text-secondary); font-size: 12px; line-height: 1.35; } -.ml-options-db-actions { +.mr-options-db-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 12px; } -.ml-options-db-actions .ml-btn { +.mr-options-db-actions .mr-btn { gap: 6px; } -.ml-options-db-actions .ml-btn svg { +.mr-options-db-actions .mr-btn svg { width: 14px; height: 14px; } -.ml-options-field { +.mr-options-field { display: flex; flex-direction: column; gap: 0; @@ -3545,69 +3545,69 @@ padding-bottom: 14px; border-bottom: 1px solid rgba(255,255,255,0.1); } -.ml-options-help, -#model-linker-modal .ml-options-help { +.mr-options-help, +#model-resolver-modal .mr-options-help { margin: 8px 0 0; - color: var(--ml-text-muted); - font-size: var(--ml-font-sm); + color: var(--mr-text-muted); + font-size: var(--mr-font-sm); line-height: 1.45; } -.ml-options-help summary, -#model-linker-modal .ml-options-help summary { +.mr-options-help summary, +#model-resolver-modal .mr-options-help summary { width: fit-content; - color: var(--ml-text-secondary); + color: var(--mr-text-secondary); cursor: pointer; font-weight: 700; } -.ml-options-help summary:hover, -#model-linker-modal .ml-options-help summary:hover { - color: var(--ml-accent); +.mr-options-help summary:hover, +#model-resolver-modal .mr-options-help summary:hover { + color: var(--mr-accent); } -.ml-options-help ol, -#model-linker-modal .ml-options-help ol { +.mr-options-help ol, +#model-resolver-modal .mr-options-help ol { margin: 8px 0 0 18px; padding: 0; } -.ml-options-help li, -#model-linker-modal .ml-options-help li { +.mr-options-help li, +#model-resolver-modal .mr-options-help li { margin: 4px 0; } -.ml-options-help p, -#model-linker-modal .ml-options-help p { +.mr-options-help p, +#model-resolver-modal .mr-options-help p { margin: 8px 0 0; } -.ml-options-help code, -#model-linker-modal .ml-options-help code { - color: var(--ml-text); - font-size: var(--ml-font-xs); +.mr-options-help code, +#model-resolver-modal .mr-options-help code { + color: var(--mr-text); + font-size: var(--mr-font-xs); } -.ml-options-token-check, -#model-linker-modal .ml-options-token-check { +.mr-options-token-check, +#model-resolver-modal .mr-options-token-check { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-top: 10px; } -.ml-options-token-check-status, -#model-linker-modal .ml-options-token-check-status { - color: var(--ml-text-muted); - font-size: var(--ml-font-sm); +.mr-options-token-check-status, +#model-resolver-modal .mr-options-token-check-status { + color: var(--mr-text-muted); + font-size: var(--mr-font-sm); font-weight: 600; } -.ml-options-token-check-status.is-pending, -#model-linker-modal .ml-options-token-check-status.is-pending { - color: var(--ml-text-secondary); +.mr-options-token-check-status.is-pending, +#model-resolver-modal .mr-options-token-check-status.is-pending { + color: var(--mr-text-secondary); } -.ml-options-token-check-status.is-valid, -#model-linker-modal .ml-options-token-check-status.is-valid { - color: var(--ml-color-success); +.mr-options-token-check-status.is-valid, +#model-resolver-modal .mr-options-token-check-status.is-valid { + color: var(--mr-color-success); } -.ml-options-token-check-status.is-invalid, -#model-linker-modal .ml-options-token-check-status.is-invalid { - color: var(--ml-color-error-light); +.mr-options-token-check-status.is-invalid, +#model-resolver-modal .mr-options-token-check-status.is-invalid { + color: var(--mr-color-error-light); } -.ml-options-label { +.mr-options-label { display: flex; align-items: center; flex-wrap: wrap; @@ -3616,7 +3616,7 @@ font-weight: 600; color: #d8d8dd; } -.ml-options-inline-link { +.mr-options-inline-link { border: none; background: none; font-size: 11px; @@ -3626,11 +3626,11 @@ text-decoration: none; color: rgba(255,255,255,0.6); } -.ml-options-inline-link:hover { +.mr-options-inline-link:hover { color: #ffffff; text-decoration: underline; } -.ml-tooltip-badge { +.mr-tooltip-badge { display: inline-flex; align-items: center; justify-content: center; @@ -3648,14 +3648,14 @@ vertical-align: middle; user-select: none; } -.ml-tooltip-badge:hover, -.ml-tooltip-badge:focus-visible { +.mr-tooltip-badge:hover, +.mr-tooltip-badge:focus-visible { background: rgba(78,161,255,0.18); color: #d9ecff; border-color: rgba(78,161,255,0.3); outline: none; } -.ml-global-tooltip { +.mr-global-tooltip { position: fixed; min-width: 220px; max-width: min(320px, calc(100vw - 24px)); @@ -3663,7 +3663,7 @@ border-radius: 10px; background: rgba(34, 34, 38, 0.98); border: 1px solid rgba(255,255,255,0.08); - color: var(--ml-text); + color: var(--mr-text); font-size: 12px; font-weight: 400; line-height: 1.5; @@ -3671,9 +3671,9 @@ text-align: left; box-shadow: 0 12px 28px rgba(0,0,0,0.32); pointer-events: none; - z-index: var(--ml-z-tooltip); + z-index: var(--mr-z-tooltip); } -.ml-options-input-row { +.mr-options-input-row { display: grid; grid-template-columns: minmax(150px, 1fr) minmax(0, 380px) 42px; align-items: center; @@ -3681,30 +3681,30 @@ padding: 14px 0 0; min-width: 0; } -.ml-options-input-row > .ml-options-label { +.mr-options-input-row > .mr-options-label { min-width: 0; padding-right: 8px; } -.ml-options-input { +.mr-options-input { width: 100%; min-width: 0; min-height: 42px; padding: 11px 14px; background: #0f1013; - color: var(--ml-text); + color: var(--mr-text); border: 1px solid rgba(255,255,255,0.16); border-radius: 8px; font-size: 13px; outline: none; transition: border-color 0.16s ease, background 0.16s ease, box-shadow 0.16s ease; } -.ml-options-input:focus { +.mr-options-input:focus { background: #0f1013; border-color: rgba(78,161,255,0.45); box-shadow: none; } -.ml-options-visibility-btn, -#model-linker-modal .ml-options-visibility-btn { +.mr-options-visibility-btn, +#model-resolver-modal .mr-options-visibility-btn { width: 42px; min-width: 42px; height: 42px; @@ -3713,55 +3713,55 @@ align-items: center; justify-content: center; padding: 0; - border: 1px solid var(--ml-missing-control-border, rgba(255,255,255,0.105)); - border-radius: var(--ml-missing-control-radius, 7px); - background: var(--ml-missing-control-bg, rgba(255,255,255,0.035)); - color: var(--ml-text); - box-shadow: var(--ml-missing-control-shadow, none); + border: 1px solid var(--mr-missing-control-border, rgba(255,255,255,0.105)); + border-radius: var(--mr-missing-control-radius, 7px); + background: var(--mr-missing-control-bg, rgba(255,255,255,0.035)); + color: var(--mr-text); + box-shadow: var(--mr-missing-control-shadow, none); cursor: pointer; - transition: var(--ml-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); + transition: var(--mr-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); } -.ml-options-visibility-btn:hover, -#model-linker-modal .ml-options-visibility-btn:hover { - background: var(--ml-missing-control-bg-hover, rgba(255,255,255,0.06)); - color: var(--ml-text); - border-color: var(--ml-missing-control-border-hover, rgba(255,255,255,0.17)); +.mr-options-visibility-btn:hover, +#model-resolver-modal .mr-options-visibility-btn:hover { + background: var(--mr-missing-control-bg-hover, rgba(255,255,255,0.06)); + color: var(--mr-text); + border-color: var(--mr-missing-control-border-hover, rgba(255,255,255,0.17)); } -.ml-options-visibility-btn[aria-pressed="true"], -#model-linker-modal .ml-options-visibility-btn[aria-pressed="true"] { +.mr-options-visibility-btn[aria-pressed="true"], +#model-resolver-modal .mr-options-visibility-btn[aria-pressed="true"] { color: #dffbe5; border-color: rgba(114,211,138,0.32); background: rgba(114,211,138,0.13); } -.ml-options-visibility-btn:focus-visible, -#model-linker-modal .ml-options-visibility-btn:focus-visible { +.mr-options-visibility-btn:focus-visible, +#model-resolver-modal .mr-options-visibility-btn:focus-visible { outline: none; - border-color: var(--ml-missing-control-focus-border, rgba(114,211,138,0.30)); - box-shadow: 0 0 0 2px var(--ml-missing-control-focus-ring, rgba(114,211,138,0.08)); + border-color: var(--mr-missing-control-focus-border, rgba(114,211,138,0.30)); + box-shadow: 0 0 0 2px var(--mr-missing-control-focus-ring, rgba(114,211,138,0.08)); } -.ml-options-visibility-btn.ml-is-muted, -#model-linker-modal .ml-options-visibility-btn.ml-is-muted { - color: var(--ml-text-muted); +.mr-options-visibility-btn.mr-is-muted, +#model-resolver-modal .mr-options-visibility-btn.mr-is-muted { + color: var(--mr-text-muted); } -.ml-options-visibility-btn svg, -#model-linker-modal .ml-options-visibility-btn svg { - width: var(--ml-font-base); - height: var(--ml-font-base); +.mr-options-visibility-btn svg, +#model-resolver-modal .mr-options-visibility-btn svg { + width: var(--mr-font-base); + height: var(--mr-font-base); display: block; } -.ml-options-toggle-list { +.mr-options-toggle-list { display: grid; gap: 0; } -.ml-options-dependent-block, -#model-linker-modal .ml-options-dependent-block { +.mr-options-dependent-block, +#model-resolver-modal .mr-options-dependent-block { display: grid; gap: 10px; margin: 0 0 8px 16px; padding: 12px 0 4px 14px; border-left: 1px solid rgba(255,255,255,0.12); } -.ml-options-toggle-row { +.mr-options-toggle-row { display: flex; align-items: center; justify-content: space-between; @@ -3777,15 +3777,15 @@ transition: background 0.16s ease; min-width: 0; } -.ml-options-toggle-row:hover { +.mr-options-toggle-row:hover { background: transparent; } -.ml-options-toggle-copy { +.mr-options-toggle-copy { display: grid; gap: 0; min-width: 0; } -.ml-options-toggle-title { +.mr-options-toggle-title { display: flex; align-items: center; flex-wrap: wrap; @@ -3794,7 +3794,7 @@ font-weight: 500; color: #d8d8dd; } -.ml-options-source-icon { +.mr-options-source-icon { display: inline-flex; align-items: center; justify-content: center; @@ -3803,12 +3803,12 @@ flex: 0 0 16px; color: currentColor; } -.ml-options-source-icon svg { +.mr-options-source-icon svg { display: block; width: 16px; height: 16px; } -.ml-options-toggle-control { +.mr-options-toggle-control { display: inline-flex; align-items: center; justify-content: center; @@ -3817,12 +3817,12 @@ flex: 0 0 auto; margin-left: auto; } -.ml-options-switch-input { +.mr-options-switch-input { position: absolute; opacity: 0; pointer-events: none; } -.ml-options-switch { +.mr-options-switch { position: relative; width: 46px; height: 26px; @@ -3831,7 +3831,7 @@ border: 1px solid rgba(255,255,255,0.06); transition: background 0.16s ease, border-color 0.16s ease, box-shadow 0.16s ease; } -.ml-options-switch::after { +.mr-options-switch::after { content: ""; position: absolute; top: 2px; @@ -3843,15 +3843,15 @@ box-shadow: 0 3px 8px rgba(0,0,0,0.3); transition: transform 0.16s ease; } -.ml-options-switch-input:checked + .ml-options-switch { +.mr-options-switch-input:checked + .mr-options-switch { background: #4c97ff; border-color: #4c97ff; box-shadow: none; } -.ml-options-switch-input:checked + .ml-options-switch::after { +.mr-options-switch-input:checked + .mr-options-switch::after { transform: translateX(20px); } -.ml-options-number-row { +.mr-options-number-row { display: grid; grid-template-columns: minmax(150px, 1fr) minmax(72px, 118px); gap: 12px; @@ -3860,16 +3860,16 @@ border-bottom: 1px solid rgba(255,255,255,0.1); min-width: 0; } -.ml-options-number-copy { +.mr-options-number-copy { display: grid; gap: 0; min-width: 0; } -.ml-options-number-row .ml-options-input { +.mr-options-number-row .mr-options-input { width: 100%; min-width: 0; } -.ml-options-actions { +.mr-options-actions { display: flex; flex-direction: column; align-items: stretch; @@ -3880,178 +3880,178 @@ gap: 10px; flex: 0 0 auto; } -.ml-options-actions .ml-footer-btn { +.mr-options-actions .mr-footer-btn { width: 100%; min-width: 0; } -.ml-options-actions .ml-btn.ml-btn-primary.ml-footer-btn { - background: var(--ml-missing-control-bg, rgba(255,255,255,0.035)); - border-color: var(--ml-missing-control-border, rgba(255,255,255,0.105)); - border-radius: var(--ml-missing-control-radius, 7px); - color: var(--ml-text); - box-shadow: var(--ml-missing-control-shadow, none); +.mr-options-actions .mr-btn.mr-btn-primary.mr-footer-btn { + background: var(--mr-missing-control-bg, rgba(255,255,255,0.035)); + border-color: var(--mr-missing-control-border, rgba(255,255,255,0.105)); + border-radius: var(--mr-missing-control-radius, 7px); + color: var(--mr-text); + box-shadow: var(--mr-missing-control-shadow, none); } -.ml-options-actions .ml-btn.ml-btn-primary.ml-footer-btn:hover:not(:disabled) { - background: var(--ml-missing-control-bg-hover, rgba(255,255,255,0.06)); - border-color: var(--ml-missing-control-border-hover, rgba(255,255,255,0.17)); - color: var(--ml-text); +.mr-options-actions .mr-btn.mr-btn-primary.mr-footer-btn:hover:not(:disabled) { + background: var(--mr-missing-control-bg-hover, rgba(255,255,255,0.06)); + border-color: var(--mr-missing-control-border-hover, rgba(255,255,255,0.17)); + color: var(--mr-text); } -.ml-options-status { +.mr-options-status { font-size: 12px; - color: var(--ml-text-muted); + color: var(--mr-text-muted); text-align: left; } -.ml-options-status.is-dirty { +.mr-options-status.is-dirty { color: #ffd48a; } -.ml-options-status.is-saved { +.mr-options-status.is-saved { color: #9dd8a9; } @media (max-width: 980px) { - .ml-options-shell { + .mr-options-shell { grid-template-columns: 1fr; border-radius: 16px; } - .ml-options-sidebar { + .mr-options-sidebar { border-right: none; border-bottom: 1px solid rgba(255,255,255,0.08); height: auto; } } @media (max-width: 900px) { - .ml-options-main { + .mr-options-main { padding: 16px 18px 0px 18px; } - .ml-options-input-row { + .mr-options-input-row { grid-template-columns: minmax(120px, 1fr) minmax(0, 1fr) 42px; gap: 8px; } - .ml-options-number-row { + .mr-options-number-row { grid-template-columns: minmax(120px, 1fr) minmax(64px, 96px); gap: 8px; } - .ml-options-toggle-row { + .mr-options-toggle-row { gap: 10px; } } @media (max-width: 760px) { - .ml-options-input-row { + .mr-options-input-row { grid-template-columns: 1fr; } - .ml-options-input-row > .ml-options-label { + .mr-options-input-row > .mr-options-label { padding-right: 0; } - .ml-options-visibility-btn { + .mr-options-visibility-btn { justify-self: start; } - .ml-options-toggle-row, - .ml-options-number-row { + .mr-options-toggle-row, + .mr-options-number-row { grid-template-columns: 1fr; flex-direction: column; align-items: flex-start; } - .ml-options-toggle-control { + .mr-options-toggle-control { min-width: 0; margin-left: 0; } - .ml-options-number-row { + .mr-options-number-row { grid-template-columns: 1fr; } } @media (max-width: 640px) { - .ml-options-section-head, - .ml-options-actions, - .ml-options-toggle-row, - .ml-options-number-row { + .mr-options-section-head, + .mr-options-actions, + .mr-options-toggle-row, + .mr-options-number-row { grid-template-columns: 1fr; flex-direction: column; align-items: flex-start; } - .ml-options-toggle-control { + .mr-options-toggle-control { min-width: 0; } - .ml-options-number-row { + .mr-options-number-row { grid-template-columns: 1fr; } - .ml-options-input { + .mr-options-input { width: 100%; } } -.ml-download-target { +.mr-download-target { margin-top: 0; padding-top: 10px; border-top: 1px solid rgba(255,255,255,0.06); display: grid; gap: 8px; } -.ml-missing-browser .ml-download-target { - border-top-color: var(--ml-missing-line, rgba(255,255,255,0.075)); +.mr-missing-browser .mr-download-target { + border-top-color: var(--mr-missing-line, rgba(255,255,255,0.075)); } -.ml-download-target-grid { +.mr-download-target-grid { display: grid; grid-template-columns: minmax(120px, 33%) minmax(0, 1fr); grid-template-rows: auto auto; gap: 8px 10px; align-items: start; } -.ml-download-target-row { +.mr-download-target-row { display: grid; gap: 6px; } @media (max-width: 720px) { - .ml-download-target-grid { + .mr-download-target-grid { grid-template-columns: 1fr; grid-template-rows: auto; } } -.ml-download-target-label { +.mr-download-target-label { display: flex; align-items: flex-end; font-size: 11px; font-weight: 700; - color: var(--ml-text-muted); + color: var(--mr-text-muted); text-transform: uppercase; letter-spacing: 0.06em; line-height: 1.2; } -.ml-download-target-input, -.ml-download-target-select { +.mr-download-target-input, +.mr-download-target-select { display: block; width: 100%; - height: var(--ml-download-control-height, 36px); - min-height: var(--ml-download-control-height, 36px); + height: var(--mr-download-control-height, 36px); + min-height: var(--mr-download-control-height, 36px); margin: 0; padding: 0 11px; background: rgba(255,255,255,0.04); - color: var(--ml-text); - border: 1px solid var(--ml-border); + color: var(--mr-text); + border: 1px solid var(--mr-border); border-radius: 9px; font-size: 12px; line-height: 1; outline: none; box-sizing: border-box; } -.ml-missing-browser .ml-download-target-input, -.ml-missing-browser .ml-download-target-select { +.mr-missing-browser .mr-download-target-input, +.mr-missing-browser .mr-download-target-select { background: rgba(255,255,255,0.035); - border-color: var(--ml-missing-line-strong, rgba(255,255,255,0.12)); - border-radius: var(--ml-missing-control-radius, 7px); + border-color: var(--mr-missing-line-strong, rgba(255,255,255,0.12)); + border-radius: var(--mr-missing-control-radius, 7px); } -.ml-download-target-select { +.mr-download-target-select { appearance: none; -webkit-appearance: none; -moz-appearance: none; cursor: pointer; } -.ml-search-source-select { +.mr-search-source-select { cursor: pointer; } -.ml-download-target-input:focus, -.ml-download-target-select:focus { +.mr-download-target-input:focus, +.mr-download-target-select:focus { border-color: rgba(114,211,138,0.4); box-shadow: 0 0 0 3px rgba(114,211,138,0.12); } -.ml-download-target-wrap { +.mr-download-target-wrap { position: relative; display: flex; align-items: stretch; @@ -4059,11 +4059,11 @@ width: 100%; } @media (max-width: 720px) { - .ml-download-target-label { + .mr-download-target-label { min-height: 0; } } -.ml-download-target-list { +.mr-download-target-list { position: absolute; top: calc(100% + 4px); left: 0; @@ -4071,76 +4071,76 @@ max-height: 220px; overflow: auto; display: none; - z-index: var(--ml-z-notification); - background: linear-gradient(180deg, var(--ml-panel-bg-strong) 0%, var(--ml-card-bg) 100%); - border: 1px solid var(--ml-border-strong); + z-index: var(--mr-z-notification); + background: linear-gradient(180deg, var(--mr-panel-bg-strong) 0%, var(--mr-card-bg) 100%); + border: 1px solid var(--mr-border-strong); border-radius: 12px; - box-shadow: var(--ml-shadow-elevated); + box-shadow: var(--mr-shadow-elevated); } -.ml-missing-browser .ml-download-target-list { +.mr-missing-browser .mr-download-target-list { background: #1b1b1b; - border-color: var(--ml-missing-line-strong, rgba(255,255,255,0.12)); - border-radius: var(--ml-missing-radius, 7px); + border-color: var(--mr-missing-line-strong, rgba(255,255,255,0.12)); + border-radius: var(--mr-missing-radius, 7px); box-shadow: 0 16px 36px rgba(0,0,0,0.3); } -.ml-download-target-option { +.mr-download-target-option { padding: 8px 10px; cursor: pointer; border-bottom: 1px solid rgba(255,255,255,0.04); - color: var(--ml-text); + color: var(--mr-text); font-size: 12px; } -.ml-download-target-option:last-child { +.mr-download-target-option:last-child { border-bottom: none; } -.ml-download-target-option:hover, -.ml-download-target-option.is-highlighted { +.mr-download-target-option:hover, +.mr-download-target-option.is-highlighted { background: rgba(114,211,138,0.12); } /* Missing detail panel polish */ -#model-linker-modal .ml-missing-detail-pane { - background: var(--ml-missing-bg); +#model-resolver-modal .mr-missing-detail-pane { + background: var(--mr-missing-bg); } -#model-linker-modal .ml-missing-detail-pane .ml-card { +#model-resolver-modal .mr-missing-detail-pane .mr-card { padding: 18px 0; } -#model-linker-modal .ml-missing-detail-pane .ml-card-header { +#model-resolver-modal .mr-missing-detail-pane .mr-card-header { margin-bottom: 12px; } -#model-linker-modal .ml-missing-detail-pane .ml-card-title { +#model-resolver-modal .mr-missing-detail-pane .mr-card-title { font-size: 17px; font-weight: 750; } -#model-linker-modal .ml-missing-detail-pane .ml-node-chip, -#model-linker-modal .ml-missing-detail-pane .ml-category-chip { - min-height: var(--ml-missing-chip-height, 20px); +#model-resolver-modal .mr-missing-detail-pane .mr-node-chip, +#model-resolver-modal .mr-missing-detail-pane .mr-category-chip { + min-height: var(--mr-missing-chip-height, 20px); padding: 2px 8px; font-size: 10px; } -#model-linker-modal .ml-missing-detail-pane .ml-node-chip, -#model-linker-modal .ml-missing-detail-pane .ml-category-chip:not(.ml-type-chip) { - background: var(--ml-missing-chip-bg, rgba(255,255,255,0.045)); - border-color: var(--ml-missing-chip-border, rgba(255,255,255,0.08)); +#model-resolver-modal .mr-missing-detail-pane .mr-node-chip, +#model-resolver-modal .mr-missing-detail-pane .mr-category-chip:not(.mr-type-chip) { + background: var(--mr-missing-chip-bg, rgba(255,255,255,0.045)); + border-color: var(--mr-missing-chip-border, rgba(255,255,255,0.08)); } -#model-linker-modal .ml-missing-detail-pane .ml-category-chip.ml-type-chip { +#model-resolver-modal .mr-missing-detail-pane .mr-category-chip.mr-type-chip { background: linear-gradient(180deg, - rgba(var(--ml-type-rgb), var(--ml-type-bg-alpha-strong)) 0%, - rgba(var(--ml-type-rgb), var(--ml-type-bg-alpha)) 100%); - border-color: rgba(var(--ml-type-rgb), var(--ml-type-border-alpha)); - color: var(--ml-type-text); + rgba(var(--mr-type-rgb), var(--mr-type-bg-alpha-strong)) 0%, + rgba(var(--mr-type-rgb), var(--mr-type-bg-alpha)) 100%); + border-color: rgba(var(--mr-type-rgb), var(--mr-type-border-alpha)); + color: var(--mr-type-text); box-shadow: inset 0 0 0 1px rgba(255,255,255,0.026), - 0 0 12px rgba(var(--ml-type-rgb), var(--ml-type-glow-alpha)); + 0 0 12px rgba(var(--mr-type-rgb), var(--mr-type-glow-alpha)); } -#model-linker-modal .ml-missing-detail-pane .ml-column { +#model-resolver-modal .mr-missing-detail-pane .mr-column { padding: 14px; background: transparent; border-color: transparent; border-radius: 0; } -#model-linker-modal .ml-missing-detail-pane .ml-column-header { +#model-resolver-modal .mr-missing-detail-pane .mr-column-header { margin-bottom: 12px; padding-bottom: 10px; color: #c3c3c3; @@ -4148,7 +4148,7 @@ font-size: 11px; letter-spacing: 0.075em; } -#model-linker-modal .ml-missing-detail-pane .ml-match-row { +#model-resolver-modal .mr-missing-detail-pane .mr-match-row { min-height: 42px; margin-bottom: 8px; padding: 7px 10px; @@ -4156,77 +4156,77 @@ border-color: rgba(255,255,255,0.065); border-radius: 7px; } -#model-linker-modal .ml-missing-detail-pane .ml-match-row.ml-best-match { +#model-resolver-modal .mr-missing-detail-pane .mr-match-row.mr-best-match { background: linear-gradient(90deg, rgba(114,211,138,0.135) 0%, rgba(114,211,138,0.07) 55%, rgba(114,211,138,0.035) 100%); border-color: rgba(114,211,138,0.26); } -#model-linker-modal .ml-missing-detail-pane .ml-match-row:hover { +#model-resolver-modal .mr-missing-detail-pane .mr-match-row:hover { background: rgba(255,255,255,0.042); border-color: rgba(255,255,255,0.10); } -#model-linker-modal .ml-missing-detail-pane .ml-match-row.ml-best-match:hover { +#model-resolver-modal .mr-missing-detail-pane .mr-match-row.mr-best-match:hover { background: linear-gradient(90deg, rgba(114,211,138,0.15) 0%, rgba(114,211,138,0.08) 55%, rgba(114,211,138,0.04) 100%); border-color: rgba(114,211,138,0.32); } -#model-linker-modal .ml-missing-detail-pane .ml-match-filename { +#model-resolver-modal .mr-missing-detail-pane .mr-match-filename { font-family: "Segoe UI Variable", "Segoe UI", system-ui, sans-serif; font-size: 11.5px; font-weight: 650; color: #e7e7e7; } -#model-linker-modal .ml-missing-detail-pane .ml-badge, -#model-linker-modal .ml-missing-detail-pane .ml-match-status { +#model-resolver-modal .mr-missing-detail-pane .mr-badge, +#model-resolver-modal .mr-missing-detail-pane .mr-match-status { min-height: 20px; padding: 2px 7px; border-radius: 6px; font-size: 10px; font-weight: 750; } -#model-linker-modal .ml-missing-detail-pane .ml-local-link-btn, -#model-linker-modal .ml-missing-detail-pane .ml-combo-refresh-btn, -#model-linker-modal .ml-missing-detail-pane .ml-search-result-action-btn, -#model-linker-modal .ml-missing-detail-pane .ml-download-section .ml-search-source-bar > .ml-btn { - background: var(--ml-missing-control-bg, rgba(255,255,255,0.035)); - border: 1px solid var(--ml-missing-control-border, rgba(255,255,255,0.105)); - border-radius: var(--ml-missing-control-radius, 7px); - box-shadow: var(--ml-missing-control-shadow, none); - color: var(--ml-text); - transition: var(--ml-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); +#model-resolver-modal .mr-missing-detail-pane .mr-local-link-btn, +#model-resolver-modal .mr-missing-detail-pane .mr-combo-refresh-btn, +#model-resolver-modal .mr-missing-detail-pane .mr-search-result-action-btn, +#model-resolver-modal .mr-missing-detail-pane .mr-download-section .mr-search-source-bar > .mr-btn { + background: var(--mr-missing-control-bg, rgba(255,255,255,0.035)); + border: 1px solid var(--mr-missing-control-border, rgba(255,255,255,0.105)); + border-radius: var(--mr-missing-control-radius, 7px); + box-shadow: var(--mr-missing-control-shadow, none); + color: var(--mr-text); + transition: var(--mr-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); } -#model-linker-modal .ml-missing-detail-pane .ml-local-link-btn:hover:not(:disabled), -#model-linker-modal .ml-missing-detail-pane .ml-combo-refresh-btn:hover:not(:disabled), -#model-linker-modal .ml-missing-detail-pane .ml-search-result-action-btn:hover:not(:disabled), -#model-linker-modal .ml-missing-detail-pane .ml-download-section .ml-search-source-bar > .ml-btn:hover:not(:disabled) { - background: var(--ml-missing-control-bg-hover, rgba(255,255,255,0.06)); - border-color: var(--ml-missing-control-border-hover, rgba(255,255,255,0.17)); - color: var(--ml-text); +#model-resolver-modal .mr-missing-detail-pane .mr-local-link-btn:hover:not(:disabled), +#model-resolver-modal .mr-missing-detail-pane .mr-combo-refresh-btn:hover:not(:disabled), +#model-resolver-modal .mr-missing-detail-pane .mr-search-result-action-btn:hover:not(:disabled), +#model-resolver-modal .mr-missing-detail-pane .mr-download-section .mr-search-source-bar > .mr-btn:hover:not(:disabled) { + background: var(--mr-missing-control-bg-hover, rgba(255,255,255,0.06)); + border-color: var(--mr-missing-control-border-hover, rgba(255,255,255,0.17)); + color: var(--mr-text); transform: none; } -#model-linker-modal .ml-missing-detail-pane .ml-local-link-btn:focus-visible, -#model-linker-modal .ml-missing-detail-pane .ml-combo-refresh-btn:focus-visible, -#model-linker-modal .ml-missing-detail-pane .ml-search-result-action-btn:focus-visible, -#model-linker-modal .ml-missing-detail-pane .ml-download-section .ml-search-source-bar > .ml-btn:focus-visible { +#model-resolver-modal .mr-missing-detail-pane .mr-local-link-btn:focus-visible, +#model-resolver-modal .mr-missing-detail-pane .mr-combo-refresh-btn:focus-visible, +#model-resolver-modal .mr-missing-detail-pane .mr-search-result-action-btn:focus-visible, +#model-resolver-modal .mr-missing-detail-pane .mr-download-section .mr-search-source-bar > .mr-btn:focus-visible { outline: none; - border-color: var(--ml-missing-control-focus-border, rgba(114,211,138,0.30)); - box-shadow: 0 0 0 2px var(--ml-missing-control-focus-ring, rgba(114,211,138,0.08)) !important; + border-color: var(--mr-missing-control-focus-border, rgba(114,211,138,0.30)); + box-shadow: 0 0 0 2px var(--mr-missing-control-focus-ring, rgba(114,211,138,0.08)) !important; } -#model-linker-modal .ml-missing-detail-pane .ml-local-link-btn { - width: var(--ml-missing-icon-button-size, 28px); - min-width: var(--ml-missing-icon-button-size, 28px); - max-width: var(--ml-missing-icon-button-size, 28px); - height: var(--ml-missing-icon-button-size, 28px); - min-height: var(--ml-missing-icon-button-size, 28px); - flex: 0 0 var(--ml-missing-icon-button-size, 28px); +#model-resolver-modal .mr-missing-detail-pane .mr-local-link-btn { + width: var(--mr-missing-icon-button-size, 28px); + min-width: var(--mr-missing-icon-button-size, 28px); + max-width: var(--mr-missing-icon-button-size, 28px); + height: var(--mr-missing-icon-button-size, 28px); + min-height: var(--mr-missing-icon-button-size, 28px); + flex: 0 0 var(--mr-missing-icon-button-size, 28px); padding: 0; } -#model-linker-modal .ml-missing-detail-pane .ml-local-link-btn > svg { +#model-resolver-modal .mr-missing-detail-pane .mr-local-link-btn > svg { display: block !important; - width: var(--ml-missing-icon-size, 13px) !important; - height: var(--ml-missing-icon-size, 13px) !important; - flex: 0 0 var(--ml-missing-icon-size, 13px); + width: var(--mr-missing-icon-size, 13px) !important; + height: var(--mr-missing-icon-size, 13px) !important; + flex: 0 0 var(--mr-missing-icon-size, 13px); pointer-events: none; } -#model-linker-modal .ml-missing-detail-pane .ml-local-alternatives-toggle { +#model-resolver-modal .mr-missing-detail-pane .mr-local-alternatives-toggle { min-height: 28px; margin: 6px 0; padding: 0 9px; @@ -4235,110 +4235,110 @@ border-radius: 7px; box-shadow: none !important; } -#model-linker-modal .ml-missing-detail-pane .ml-local-alternatives-toggle:hover, -#model-linker-modal .ml-missing-detail-pane .ml-local-alternatives-toggle:focus, -#model-linker-modal .ml-missing-detail-pane .ml-local-alternatives-toggle:focus-visible { +#model-resolver-modal .mr-missing-detail-pane .mr-local-alternatives-toggle:hover, +#model-resolver-modal .mr-missing-detail-pane .mr-local-alternatives-toggle:focus, +#model-resolver-modal .mr-missing-detail-pane .mr-local-alternatives-toggle:focus-visible { background: rgba(255,255,255,0.038); border-color: rgba(255,255,255,0.095) !important; box-shadow: none !important; } -#model-linker-modal .ml-missing-detail-pane .ml-combo-section { +#model-resolver-modal .mr-missing-detail-pane .mr-combo-section { margin-top: 10px; padding-top: 10px; border-top-color: rgba(255,255,255,0.07); } -#model-linker-modal .ml-missing-detail-pane .ml-combo-input, -#model-linker-modal .ml-missing-detail-pane .ml-search-source-select, -#model-linker-modal .ml-missing-detail-pane .ml-download-target-input, -#model-linker-modal .ml-missing-detail-pane .ml-download-target-select { - min-height: var(--ml-missing-field-height, 38px); - height: var(--ml-missing-field-height, 38px); - background: var(--ml-missing-control-bg, rgba(255,255,255,0.035)); - border-color: var(--ml-missing-control-border, rgba(255,255,255,0.10)); - border-radius: var(--ml-missing-control-radius, 7px); +#model-resolver-modal .mr-missing-detail-pane .mr-combo-input, +#model-resolver-modal .mr-missing-detail-pane .mr-search-source-select, +#model-resolver-modal .mr-missing-detail-pane .mr-download-target-input, +#model-resolver-modal .mr-missing-detail-pane .mr-download-target-select { + min-height: var(--mr-missing-field-height, 38px); + height: var(--mr-missing-field-height, 38px); + background: var(--mr-missing-control-bg, rgba(255,255,255,0.035)); + border-color: var(--mr-missing-control-border, rgba(255,255,255,0.10)); + border-radius: var(--mr-missing-control-radius, 7px); box-shadow: none; font-size: 13px; } -#model-linker-modal .ml-missing-detail-pane .ml-combo-input:focus, -#model-linker-modal .ml-missing-detail-pane .ml-search-source-select:focus, -#model-linker-modal .ml-missing-detail-pane .ml-download-target-input:focus, -#model-linker-modal .ml-missing-detail-pane .ml-download-target-select:focus { - background: var(--ml-missing-control-bg-hover, rgba(255,255,255,0.045)); - border-color: var(--ml-missing-control-focus-border, rgba(114,211,138,0.34)); - box-shadow: 0 0 0 2px var(--ml-missing-control-focus-ring, rgba(114,211,138,0.08)); +#model-resolver-modal .mr-missing-detail-pane .mr-combo-input:focus, +#model-resolver-modal .mr-missing-detail-pane .mr-search-source-select:focus, +#model-resolver-modal .mr-missing-detail-pane .mr-download-target-input:focus, +#model-resolver-modal .mr-missing-detail-pane .mr-download-target-select:focus { + background: var(--mr-missing-control-bg-hover, rgba(255,255,255,0.045)); + border-color: var(--mr-missing-control-focus-border, rgba(114,211,138,0.34)); + box-shadow: 0 0 0 2px var(--mr-missing-control-focus-ring, rgba(114,211,138,0.08)); } -#model-linker-modal .ml-missing-detail-pane .ml-combo-refresh-btn { +#model-resolver-modal .mr-missing-detail-pane .mr-combo-refresh-btn { display: inline-flex; align-items: center; justify-content: center; - flex: 0 0 var(--ml-missing-field-height, 38px); - width: var(--ml-missing-field-height, 38px); - min-width: var(--ml-missing-field-height, 38px); - height: var(--ml-missing-field-height, 38px); - min-height: var(--ml-missing-field-height, 38px); + flex: 0 0 var(--mr-missing-field-height, 38px); + width: var(--mr-missing-field-height, 38px); + min-width: var(--mr-missing-field-height, 38px); + height: var(--mr-missing-field-height, 38px); + min-height: var(--mr-missing-field-height, 38px); padding: 0; aspect-ratio: auto; font-size: 0; line-height: 1; overflow: hidden; } -#model-linker-modal .ml-missing-detail-pane .ml-combo-refresh-icon { - width: var(--ml-missing-icon-size, 13px); - height: var(--ml-missing-icon-size, 13px); +#model-resolver-modal .mr-missing-detail-pane .mr-combo-refresh-icon { + width: var(--mr-missing-icon-size, 13px); + height: var(--mr-missing-icon-size, 13px); display: block; } -#model-linker-modal .ml-missing-detail-pane .ml-download-section { +#model-resolver-modal .mr-missing-detail-pane .mr-download-section { padding: 0; background: transparent; border-color: transparent; border-radius: 0; } -#model-linker-modal .ml-missing-detail-pane .ml-download-section .ml-search-source-bar > .ml-btn { - min-height: var(--ml-missing-search-button-height, 34px); - height: var(--ml-missing-search-button-height, 34px); +#model-resolver-modal .mr-missing-detail-pane .mr-download-section .mr-search-source-bar > .mr-btn { + min-height: var(--mr-missing-search-button-height, 34px); + height: var(--mr-missing-search-button-height, 34px); padding: 0 12px; font-size: 12px; font-weight: 700; } -#model-linker-modal .ml-missing-detail-pane .ml-download-section .ml-search-source-bar > .ml-btn .ml-btn-icon { - width: var(--ml-missing-icon-size, 13px); - height: var(--ml-missing-icon-size, 13px); - font-size: var(--ml-missing-icon-size, 13px); +#model-resolver-modal .mr-missing-detail-pane .mr-download-section .mr-search-source-bar > .mr-btn .mr-btn-icon { + width: var(--mr-missing-icon-size, 13px); + height: var(--mr-missing-icon-size, 13px); + font-size: var(--mr-missing-icon-size, 13px); } -#model-linker-modal .ml-missing-detail-pane .ml-download-section .ml-search-source-bar > .ml-btn .ml-btn-icon svg { - width: var(--ml-missing-icon-size, 13px); - height: var(--ml-missing-icon-size, 13px); +#model-resolver-modal .mr-missing-detail-pane .mr-download-section .mr-search-source-bar > .mr-btn .mr-btn-icon svg { + width: var(--mr-missing-icon-size, 13px); + height: var(--mr-missing-icon-size, 13px); display: block; } -#model-linker-modal .ml-missing-detail-pane .ml-download-target { +#model-resolver-modal .mr-missing-detail-pane .mr-download-target { padding-top: 12px; border-top-color: rgba(255,255,255,0.07); } -#model-linker-modal .ml-missing-detail-pane .ml-download-target-grid { +#model-resolver-modal .mr-missing-detail-pane .mr-download-target-grid { gap: 10px 12px; } -#model-linker-modal .ml-missing-detail-pane .model-linker-selected { +#model-resolver-modal .mr-missing-detail-pane .model-resolver-selected { margin: 0 0 12px; padding: 9px 11px; background: linear-gradient(90deg, rgba(114,211,138,0.11) 0%, rgba(114,211,138,0.045) 100%); border: 1px solid rgba(114,211,138,0.20); border-radius: 7px; - color: var(--ml-text-soft); + color: var(--mr-text-soft); font-size: 12px; box-shadow: none; } /* Flatten right-side sections */ -#model-linker-modal .ml-missing-detail-pane .ml-columns { +#model-resolver-modal .mr-missing-detail-pane .mr-columns { gap: 0; } -#model-linker-modal .ml-missing-detail-pane .ml-column + .ml-column { +#model-resolver-modal .mr-missing-detail-pane .mr-column + .mr-column { position: relative; margin-top: 24px; padding-top: 20px; border-top: 1px solid rgba(255,255,255,0.12); } -#model-linker-modal .ml-missing-detail-pane .ml-column + .ml-column::before { +#model-resolver-modal .mr-missing-detail-pane .mr-column + .mr-column::before { content: ""; position: absolute; top: -2px; @@ -4347,107 +4347,107 @@ height: 1px; background: linear-gradient(90deg, rgba(114,211,138,0.28), rgba(255,255,255,0.08) 34%, transparent 100%); } -#model-linker-modal .ml-missing-detail-pane .ml-column-header { +#model-resolver-modal .mr-missing-detail-pane .mr-column-header { background: transparent; } -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] { +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] { background: rgba(255,255,255,0.014); border-color: rgba(255,255,255,0.06); } -#model-linker-modal .ml-missing-detail-pane .ml-download-section .ml-status-inline { +#model-resolver-modal .mr-missing-detail-pane .mr-download-section .mr-status-inline { margin-bottom: 10px; } -#model-linker-modal .ml-missing-detail-pane .ml-download-section .ml-search-source-bar, -#model-linker-modal .ml-missing-detail-pane .ml-download-target { +#model-resolver-modal .mr-missing-detail-pane .mr-download-section .mr-search-source-bar, +#model-resolver-modal .mr-missing-detail-pane .mr-download-target { padding: 0; } -#model-linker-modal .ml-missing-detail-pane .ml-download-section .ml-search-source-bar { +#model-resolver-modal .mr-missing-detail-pane .mr-download-section .mr-search-source-bar { padding-bottom: 12px; border-bottom: 1px solid rgba(255,255,255,0.065); } -#model-linker-modal .ml-missing-detail-pane .ml-download-target { +#model-resolver-modal .mr-missing-detail-pane .mr-download-target { padding-top: 12px; border-top: 0; } -#model-linker-modal .ml-missing-detail-pane .ml-selected-bar-inner { +#model-resolver-modal .mr-missing-detail-pane .mr-selected-bar-inner { gap: 8px; flex-wrap: nowrap; } -#model-linker-modal .ml-missing-detail-pane .ml-selected-label { +#model-resolver-modal .mr-missing-detail-pane .mr-selected-label { color: #72d38a; font-size: 11px; font-weight: 750; white-space: nowrap; } -#model-linker-modal .ml-missing-detail-pane .ml-selected-code { +#model-resolver-modal .mr-missing-detail-pane .mr-selected-code { min-width: 0; color: #d9d9d9; font-family: "Segoe UI Variable", "Segoe UI", system-ui, sans-serif; font-size: 11px; white-space: nowrap; } -#model-linker-modal .ml-missing-detail-pane .model-linker-selected .ml-btn { - min-height: var(--ml-missing-search-button-height, 34px); - height: var(--ml-missing-search-button-height, 34px); +#model-resolver-modal .mr-missing-detail-pane .model-resolver-selected .mr-btn { + min-height: var(--mr-missing-search-button-height, 34px); + height: var(--mr-missing-search-button-height, 34px); padding: 0 12px; margin-left: auto; - background: var(--ml-missing-control-bg, rgba(255,255,255,0.035)); - border-color: var(--ml-missing-control-border, rgba(255,255,255,0.105)); - border-radius: var(--ml-missing-control-radius, 7px); - color: var(--ml-text); - box-shadow: var(--ml-missing-control-shadow, none) !important; + background: var(--mr-missing-control-bg, rgba(255,255,255,0.035)); + border-color: var(--mr-missing-control-border, rgba(255,255,255,0.105)); + border-radius: var(--mr-missing-control-radius, 7px); + color: var(--mr-text); + box-shadow: var(--mr-missing-control-shadow, none) !important; font-size: 12px; font-weight: 700; } -#model-linker-modal .ml-missing-detail-pane .model-linker-selected .ml-btn:hover:not(:disabled) { - background: var(--ml-missing-control-bg-hover, rgba(255,255,255,0.06)); - border-color: var(--ml-missing-control-border-hover, rgba(255,255,255,0.17)); - color: var(--ml-text); +#model-resolver-modal .mr-missing-detail-pane .model-resolver-selected .mr-btn:hover:not(:disabled) { + background: var(--mr-missing-control-bg-hover, rgba(255,255,255,0.06)); + border-color: var(--mr-missing-control-border-hover, rgba(255,255,255,0.17)); + color: var(--mr-text); } -#model-linker-modal .ml-missing-detail-pane .ml-search-progress-list-compact { +#model-resolver-modal .mr-missing-detail-pane .mr-search-progress-list-compact { gap: 7px; margin: 10px 0 8px; padding-bottom: 1px; } -#model-linker-modal .ml-missing-detail-pane .ml-search-progress-list-compact .ml-search-progress-item { +#model-resolver-modal .mr-missing-detail-pane .mr-search-progress-list-compact .mr-search-progress-item { min-height: 24px; padding: 3px 9px; background: rgba(255,255,255,0.028); border-color: rgba(255,255,255,0.07); border-radius: 999px; } -#model-linker-modal .ml-missing-detail-pane .ml-search-progress-list-compact .ml-search-progress-source { +#model-resolver-modal .mr-missing-detail-pane .mr-search-progress-list-compact .mr-search-progress-source { font-size: 10px; font-weight: 750; } -#model-linker-modal .ml-missing-detail-pane .ml-search-progress-list-compact .ml-search-progress-status { +#model-resolver-modal .mr-missing-detail-pane .mr-search-progress-list-compact .mr-search-progress-status { font-size: 10px; } -#model-linker-modal .ml-missing-detail-pane .ml-search-results-table-wrap { +#model-resolver-modal .mr-missing-detail-pane .mr-search-results-table-wrap { margin-top: 8px; background: rgba(255,255,255,0.018); border-color: rgba(255,255,255,0.065); border-radius: 7px; box-shadow: none; } -#model-linker-modal .ml-missing-detail-pane .ml-search-results-table { +#model-resolver-modal .mr-missing-detail-pane .mr-search-results-table { font-size: 11px; } -#model-linker-modal .ml-missing-detail-pane .ml-search-results-table th { +#model-resolver-modal .mr-missing-detail-pane .mr-search-results-table th { padding: 9px 10px; background: rgba(255,255,255,0.04); color: #bdbdbd; font-size: 10px; letter-spacing: 0.02em; } -#model-linker-modal .ml-missing-detail-pane .ml-search-results-table td { +#model-resolver-modal .mr-missing-detail-pane .mr-search-results-table td { padding: 9px 10px; border-bottom-color: rgba(255,255,255,0.055); } -#model-linker-modal .ml-missing-detail-pane .ml-search-results-table tr:hover td { +#model-resolver-modal .mr-missing-detail-pane .mr-search-results-table tr:hover td { background: rgba(255,255,255,0.016); } -#model-linker-modal .ml-missing-detail-pane .ml-search-source-pill { +#model-resolver-modal .mr-missing-detail-pane .mr-search-source-pill { min-height: 21px; padding: 2px 8px; background: rgba(255,255,255,0.055); @@ -4455,23 +4455,23 @@ border-radius: 999px; font-size: 10px; } -#model-linker-modal .ml-missing-detail-pane .ml-search-result-model span { +#model-resolver-modal .mr-missing-detail-pane .mr-search-result-model span { font-size: 12px; font-weight: 700; } -#model-linker-modal .ml-missing-detail-pane .ml-search-result-model small, -#model-linker-modal .ml-missing-detail-pane .ml-search-size { +#model-resolver-modal .mr-missing-detail-pane .mr-search-result-model small, +#model-resolver-modal .mr-missing-detail-pane .mr-search-size { font-size: 10px; color: #a9a9a9; } -#model-linker-modal .ml-missing-detail-pane .ml-search-result-action-btn { - width: var(--ml-missing-icon-button-size, 28px); - height: var(--ml-missing-icon-button-size, 28px); - min-width: var(--ml-missing-icon-button-size, 28px); - min-height: var(--ml-missing-icon-button-size, 28px); - max-width: var(--ml-missing-icon-button-size, 28px); +#model-resolver-modal .mr-missing-detail-pane .mr-search-result-action-btn { + width: var(--mr-missing-icon-button-size, 28px); + height: var(--mr-missing-icon-button-size, 28px); + min-width: var(--mr-missing-icon-button-size, 28px); + min-height: var(--mr-missing-icon-button-size, 28px); + max-width: var(--mr-missing-icon-button-size, 28px); } -#model-linker-modal #queue-toggle-icon { +#model-resolver-modal #queue-toggle-icon { right: 0; min-width: 12px; width: 12px; @@ -4483,54 +4483,54 @@ border-radius: 0; box-shadow: none; } -#model-linker-modal #queue-toggle-icon:hover { +#model-resolver-modal #queue-toggle-icon:hover { background: transparent; } -#model-linker-modal #model-linker-content, -#model-linker-modal .ml-missing-detail-pane, -#model-linker-modal .ml-missing-list, -#model-linker-modal .ml-search-results-table-wrap { +#model-resolver-modal #model-resolver-content, +#model-resolver-modal .mr-missing-detail-pane, +#model-resolver-modal .mr-missing-list, +#model-resolver-modal .mr-search-results-table-wrap { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,0.20) transparent; } -#model-linker-modal #model-linker-content::-webkit-scrollbar, -#model-linker-modal .ml-missing-detail-pane::-webkit-scrollbar, -#model-linker-modal .ml-missing-list::-webkit-scrollbar, -#model-linker-modal .ml-search-results-table-wrap::-webkit-scrollbar { +#model-resolver-modal #model-resolver-content::-webkit-scrollbar, +#model-resolver-modal .mr-missing-detail-pane::-webkit-scrollbar, +#model-resolver-modal .mr-missing-list::-webkit-scrollbar, +#model-resolver-modal .mr-search-results-table-wrap::-webkit-scrollbar { width: 8px; height: 8px; } -#model-linker-modal #model-linker-content::-webkit-scrollbar-track, -#model-linker-modal .ml-missing-detail-pane::-webkit-scrollbar-track, -#model-linker-modal .ml-missing-list::-webkit-scrollbar-track, -#model-linker-modal .ml-search-results-table-wrap::-webkit-scrollbar-track { +#model-resolver-modal #model-resolver-content::-webkit-scrollbar-track, +#model-resolver-modal .mr-missing-detail-pane::-webkit-scrollbar-track, +#model-resolver-modal .mr-missing-list::-webkit-scrollbar-track, +#model-resolver-modal .mr-search-results-table-wrap::-webkit-scrollbar-track { background: transparent; } -#model-linker-modal #model-linker-content::-webkit-scrollbar-thumb, -#model-linker-modal .ml-missing-detail-pane::-webkit-scrollbar-thumb, -#model-linker-modal .ml-missing-list::-webkit-scrollbar-thumb, -#model-linker-modal .ml-search-results-table-wrap::-webkit-scrollbar-thumb { +#model-resolver-modal #model-resolver-content::-webkit-scrollbar-thumb, +#model-resolver-modal .mr-missing-detail-pane::-webkit-scrollbar-thumb, +#model-resolver-modal .mr-missing-list::-webkit-scrollbar-thumb, +#model-resolver-modal .mr-search-results-table-wrap::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.18); border: 2px solid transparent; border-radius: 999px; background-clip: content-box; } -#model-linker-modal #model-linker-content::-webkit-scrollbar-thumb:hover, -#model-linker-modal .ml-missing-detail-pane::-webkit-scrollbar-thumb:hover, -#model-linker-modal .ml-missing-list::-webkit-scrollbar-thumb:hover, -#model-linker-modal .ml-search-results-table-wrap::-webkit-scrollbar-thumb:hover { +#model-resolver-modal #model-resolver-content::-webkit-scrollbar-thumb:hover, +#model-resolver-modal .mr-missing-detail-pane::-webkit-scrollbar-thumb:hover, +#model-resolver-modal .mr-missing-list::-webkit-scrollbar-thumb:hover, +#model-resolver-modal .mr-search-results-table-wrap::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.28); background-clip: content-box; } /* Local matches as one compact table-like list */ -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] { +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] { overflow: hidden; background: rgba(255,255,255,0.018); border: 1px solid rgba(255,255,255,0.075); border-radius: 7px; } -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] .ml-match-row { +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] .mr-match-row { min-height: 42px; margin: 0; padding: 8px 10px; @@ -4539,27 +4539,27 @@ border-bottom: 1px solid rgba(255,255,255,0.058); border-radius: 0; } -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] .ml-match-row:hover { +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] .mr-match-row:hover { background: rgba(255,255,255,0.034); border-bottom-color: rgba(255,255,255,0.07); } -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] .ml-match-row.ml-best-match { +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] .mr-match-row.mr-best-match { background: linear-gradient(90deg, rgba(114,211,138,0.13) 0%, rgba(114,211,138,0.065) 58%, rgba(114,211,138,0.025) 100%); border-bottom-color: rgba(114,211,138,0.20); } -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] .ml-match-row.ml-best-match:hover { +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] .mr-match-row.mr-best-match:hover { background: linear-gradient(90deg, rgba(114,211,138,0.15) 0%, rgba(114,211,138,0.075) 58%, rgba(114,211,138,0.03) 100%); } -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] > .ml-match-row:last-child, -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] > .ml-stack-sm:last-child .ml-match-row:last-child { +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] > .mr-match-row:last-child, +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] > .mr-stack-sm:last-child .mr-match-row:last-child { border-bottom: 0; } -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] > .ml-stack-sm { +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] > .mr-stack-sm { display: grid; gap: 0; margin: 0; } -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] .ml-local-alternatives-toggle { +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] .mr-local-alternatives-toggle { min-height: 32px; margin: 0; padding: 0 10px; @@ -4568,12 +4568,12 @@ border-bottom: 1px solid rgba(255,255,255,0.058) !important; border-radius: 0; } -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] .ml-local-alternatives-toggle:hover, -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] .ml-local-alternatives-toggle:focus, -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] .ml-local-alternatives-toggle:focus-visible { +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] .mr-local-alternatives-toggle:hover, +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] .mr-local-alternatives-toggle:focus, +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] .mr-local-alternatives-toggle:focus-visible { background: rgba(255,255,255,0.034); border-bottom-color: rgba(255,255,255,0.07) !important; } -#model-linker-modal .ml-missing-detail-pane [id^="local-matches-body-"] .ml-local-alternatives-label { +#model-resolver-modal .mr-missing-detail-pane [id^="local-matches-body-"] .mr-local-alternatives-label { color: #bdbdbd; } diff --git a/web/css/linker-shell.css b/web/css/resolver-shell.css similarity index 65% rename from web/css/linker-shell.css rename to web/css/resolver-shell.css index d558caf..8af4330 100644 --- a/web/css/linker-shell.css +++ b/web/css/resolver-shell.css @@ -1,12 +1,12 @@ -.model-linker-backdrop { +.model-resolver-backdrop { position: fixed; inset: 0; background: transparent; - z-index: var(--ml-z-dropdown); + z-index: var(--mr-z-dropdown); display: none; } -.model-linker-modal { +.model-resolver-modal { position: fixed; top: 50%; left: 50%; @@ -23,7 +23,7 @@ flex-direction: column; overflow: hidden; resize: both; - z-index: var(--ml-z-dialog); + z-index: var(--mr-z-dialog); color: var(--input-text, #fff); background: linear-gradient(180deg, #171717 0%, #111 100%); border: 1px solid rgba(255, 255, 255, 0.14); @@ -32,30 +32,30 @@ box-shadow: 0 18px 46px rgba(0, 0, 0, 0.42); } -.ml-context-menu { +.mr-context-menu { position: fixed; display: none; - z-index: var(--ml-z-context-menu); + z-index: var(--mr-z-context-menu); } -.ml-context-menu-item { +.mr-context-menu-item { cursor: pointer; } -.ml-global-tooltip { +.mr-global-tooltip { display: none; } -.ml-dialog-shell { +.mr-dialog-shell { display: flex; flex-direction: column; } -.ml-dialog-topbar { +.mr-dialog-topbar { display: flex; justify-content: space-between; align-items: center; - gap: var(--ml-spacing-10); + gap: var(--mr-spacing-10); min-height: 42px; padding: 6px 10px 0; border-bottom: 1px solid rgba(0, 0, 0, 0.38); @@ -64,32 +64,32 @@ user-select: none; } -.ml-dialog-topbar.ml-is-dragging { +.mr-dialog-topbar.mr-is-dragging { cursor: grabbing; } -.ml-dialog-brand, -.ml-dialog-controls, -.ml-dialog-control-row { +.mr-dialog-brand, +.mr-dialog-controls, +.mr-dialog-control-row { display: flex; align-items: center; - gap: var(--ml-spacing-8); + gap: var(--mr-spacing-8); } -.ml-dialog-brand { +.mr-dialog-brand { min-width: 0; flex: 1 1 auto; align-self: stretch; } -.ml-dialog-controls { +.mr-dialog-controls { flex: 0 0 auto; align-self: stretch; gap: 0; margin: -6px -10px 0 0; } -#model-linker-drag-handle { +#model-resolver-drag-handle { display: flex; align-self: flex-start; align-items: center; @@ -107,11 +107,11 @@ box-sizing: border-box; } -.ml-dialog-topbar.ml-is-dragging #model-linker-drag-handle { +.mr-dialog-topbar.mr-is-dragging #model-resolver-drag-handle { cursor: grabbing; } -#model-linker-modal .ml-window-btn { +#model-resolver-modal .mr-window-btn { display: flex; align-items: center; justify-content: center; @@ -124,20 +124,20 @@ line-height: 1; appearance: none; -webkit-appearance: none; - transition: var(--ml-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); + transition: var(--mr-missing-control-transition, background 0.15s ease, border-color 0.15s ease, color 0.15s ease); } -#model-linker-modal .ml-window-btn:hover { +#model-resolver-modal .mr-window-btn:hover { color: rgba(255, 255, 255, 0.92); background: rgba(255, 255, 255, 0.075) !important; } -#model-linker-modal .ml-window-btn:focus-visible { +#model-resolver-modal .mr-window-btn:focus-visible { outline: none; box-shadow: none !important; } -#model-linker-modal .ml-window-btn--fullscreen { +#model-resolver-modal .mr-window-btn--fullscreen { width: 46px; min-width: 46px; height: 100%; @@ -145,7 +145,7 @@ padding: 0; } -#model-linker-modal .ml-window-btn--dock { +#model-resolver-modal .mr-window-btn--dock { width: 46px; min-width: 46px; height: 100%; @@ -153,7 +153,7 @@ padding: 0; } -#model-linker-modal .ml-window-btn--close { +#model-resolver-modal .mr-window-btn--close { width: 46px; min-width: 46px; height: 100%; @@ -161,19 +161,19 @@ padding: 0; } -#model-linker-modal .ml-window-btn--close:hover { +#model-resolver-modal .mr-window-btn--close:hover { color: #ffffff; background: #c42b1c !important; } -#model-linker-modal .ml-window-btn-icon { +#model-resolver-modal .mr-window-btn-icon { display: block; width: 23px; height: 23px; pointer-events: none; } -#model-linker-body { +#model-resolver-body { display: flex; gap: 0; padding: 8px 6px 6px; @@ -181,18 +181,18 @@ min-height: 0; align-items: stretch; position: relative; - background: var(--ml-bg, #121212); + background: var(--mr-bg, #121212); } -#model-linker-content { +#model-resolver-content { overflow-y: auto; flex: 1; min-height: 0; contain: layout paint style; - background: var(--ml-bg, #222); + background: var(--mr-bg, #222); } -#model-linker-queue { +#model-resolver-queue { width: 320px; min-width: 240px; max-width: 70%; @@ -201,28 +201,28 @@ padding-left: 0; border-left: 0; contain: layout paint style; - background: var(--ml-bg, #121212); + background: var(--mr-bg, #121212); } -#model-linker-body.ml-is-resizing-queue #model-linker-content, -#model-linker-body.ml-is-resizing-queue #model-linker-queue { +#model-resolver-body.mr-is-resizing-queue #model-resolver-content, +#model-resolver-body.mr-is-resizing-queue #model-resolver-queue { pointer-events: none; user-select: none; } -#model-linker-splitter { +#model-resolver-splitter { position: relative; width: 10px; min-width: 10px; opacity: 1; cursor: col-resize; - background: var(--ml-bg, #121212); + background: var(--mr-bg, #121212); border-left: 1px solid rgba(255, 255, 255, 0.075); border-right: 1px solid rgba(255, 255, 255, 0.075); border-radius: 0; } -#model-linker-splitter::before { +#model-resolver-splitter::before { content: ""; position: absolute; top: 16px; @@ -235,10 +235,10 @@ transition: background 0.15s ease, box-shadow 0.15s ease; } -#model-linker-splitter:hover::before, -#model-linker-splitter:focus-visible::before, -#model-linker-body.ml-is-resizing-queue #model-linker-splitter::before, -#model-linker-body.ml-queue-preview-collapsed #model-linker-splitter::before { +#model-resolver-splitter:hover::before, +#model-resolver-splitter:focus-visible::before, +#model-resolver-body.mr-is-resizing-queue #model-resolver-splitter::before, +#model-resolver-body.mr-queue-preview-collapsed #model-resolver-splitter::before { background: rgba(114, 211, 138, 0.78); box-shadow: 0 0 0 3px rgba(114, 211, 138, 0.12); } @@ -287,37 +287,37 @@ box-shadow: 0 0 0 3px rgba(114, 211, 138, 0.12); } -.ml-queue-panel, -.ml-queue-stack { +.mr-queue-panel, +.mr-queue-stack { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; } -.ml-queue-header { +.mr-queue-header { display: flex; justify-content: space-between; align-items: center; - gap: var(--ml-spacing-10); + gap: var(--mr-spacing-10); min-height: 44px; margin-bottom: 0; padding: 0 0 10px; } -.ml-queue-title { - color: var(--ml-text, #f3f3f3); +.mr-queue-title { + color: var(--mr-text, #f3f3f3); font-size: 14px; font-weight: 700; line-height: 1.25; } -.ml-queue-actions { +.mr-queue-actions { display: flex; - gap: var(--ml-spacing-6); + gap: var(--mr-spacing-6); } -.ml-queue-list { +.mr-queue-list { overflow-y: auto; flex: 1; min-height: 0; @@ -327,19 +327,19 @@ border-radius: 6px; } -.ml-queue-empty { +.mr-queue-empty { padding: 12px; - color: var(--ml-text-muted, #b1b1b1); + color: var(--mr-text-muted, #b1b1b1); font-size: 13px; } -.ml-queue-items { +.mr-queue-items { display: flex; flex-direction: column; gap: 0; } -.ml-queue-item { +.mr-queue-item { display: grid; gap: 4px; padding: 10px 0; @@ -347,41 +347,41 @@ border: 0; border-bottom: 1px solid rgba(255, 255, 255, 0.052); border-radius: 0; - color: var(--ml-text, #f3f3f3); + color: var(--mr-text, #f3f3f3); transition: background 0.14s ease, box-shadow 0.14s ease; } -.ml-queue-item:last-child { +.mr-queue-item:last-child { border-bottom: 0; } -.ml-queue-item:hover { +.mr-queue-item:hover { background: rgba(255, 255, 255, 0.032); } -.ml-queue-item-title, -.ml-selected-label { +.mr-queue-item-title, +.mr-selected-label { font-weight: 700; } -.ml-queue-item-meta, -.ml-queue-item-selection { +.mr-queue-item-meta, +.mr-queue-item-selection { display: grid; grid-template-columns: 50px minmax(0, 1fr); align-items: baseline; gap: 6px; - color: var(--ml-text-muted, #b1b1b1); + color: var(--mr-text-muted, #b1b1b1); font-size: 11px; line-height: 1.35; } -.ml-queue-item-meta span, -.ml-queue-item-selection span { - color: var(--ml-text-dim, #7b7b7b); +.mr-queue-item-meta span, +.mr-queue-item-selection span { + color: var(--mr-text-dim, #7b7b7b); font-weight: 700; } -.ml-queue-item code { +.mr-queue-item code { min-width: 0; overflow: hidden; color: #dedede; @@ -391,86 +391,86 @@ white-space: nowrap; } -.ml-queue-item-actions, -.ml-selected-bar-inner { +.mr-queue-item-actions, +.mr-selected-bar-inner { display: flex; align-items: center; - gap: var(--ml-spacing-8); + gap: var(--mr-spacing-8); flex-wrap: wrap; } -.ml-queue-item-actions { +.mr-queue-item-actions { margin-top: 6px; } -.model-linker-selected { +.model-resolver-selected { display: none; } -.ml-selected-label { +.mr-selected-label { color: #4caf50; } -.ml-selected-code { +.mr-selected-code { flex: 1; overflow: hidden; text-overflow: ellipsis; } -.ml-inline-note-link { +.mr-inline-note-link { cursor: pointer; - color: var(--ml-accent-blue); + color: var(--mr-accent-blue); } -.ml-footer { +.mr-footer { position: sticky; bottom: 0; - background: var(--ml-bg, #222); + background: var(--mr-bg, #222); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); } -.ml-notification { +.mr-notification { position: fixed; top: 0; left: 50%; display: flex; align-items: center; - gap: var(--ml-spacing-12); + gap: var(--mr-spacing-12); min-width: 300px; max-width: 600px; - padding: var(--ml-spacing-12) var(--ml-spacing-24); + padding: var(--mr-spacing-12) var(--mr-spacing-24); color: #fff; - font-size: var(--ml-font-lg); + font-size: var(--mr-font-lg); font-weight: 500; text-align: center; transform: translateX(-50%); - border-radius: 0 0 var(--ml-ui-radius-sm) var(--ml-ui-radius-sm); + border-radius: 0 0 var(--mr-ui-radius-sm) var(--mr-ui-radius-sm); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); - z-index: var(--ml-z-notification); - animation: ml-slide-down 0.3s ease; + z-index: var(--mr-z-notification); + animation: mr-slide-down 0.3s ease; } -.ml-notification--success { +.mr-notification--success { background: #28a745; } -.ml-notification--error { +.mr-notification--error { background: #dc3545; } -.ml-notification--info { +.mr-notification--info { background: #007acc; } -.ml-notification-icon { - font-size: var(--ml-font-2xl); +.mr-notification-icon { + font-size: var(--mr-font-2xl); font-weight: 700; } -.ml-notification-close { - width: var(--ml-spacing-24); - height: var(--ml-spacing-24); +.mr-notification-close { + width: var(--mr-spacing-24); + height: var(--mr-spacing-24); margin-left: auto; padding: 0; display: flex; @@ -478,104 +478,104 @@ justify-content: center; opacity: 0.8; color: #fff; - font-size: var(--ml-font-3xl); + font-size: var(--mr-font-3xl); cursor: pointer; background: none; border: none; - border-radius: var(--ml-radius-md); + border-radius: var(--mr-radius-md); } -.ml-popup-auto-resolve-btn, -.model-linker-floating-button { +.mr-popup-auto-resolve-btn, +.model-resolver-floating-button { cursor: pointer; font-weight: 600; transition: all 0.2s ease; white-space: nowrap; } -.ml-popup-auto-resolve-btn { - padding: var(--ml-spacing-6) var(--ml-spacing-12); +.mr-popup-auto-resolve-btn { + padding: var(--mr-spacing-6) var(--mr-spacing-12); color: #fff; - font-size: var(--ml-font-md); + font-size: var(--mr-font-md); background: #4caf50; border: none; - border-radius: var(--ml-radius-lg); + border-radius: var(--mr-radius-lg); } -.ml-popup-auto-resolve-btn:hover { +.mr-popup-auto-resolve-btn:hover { background: #45a049; } -.ml-popup-inline-actions { +.mr-popup-inline-actions { display: flex; align-items: center; - gap: var(--ml-spacing-16); - padding: 0 var(--ml-spacing-16); - margin-bottom: var(--ml-spacing-8); + gap: var(--mr-spacing-16); + padding: 0 var(--mr-spacing-16); + margin-bottom: var(--mr-spacing-8); } -.ml-popup-actions-wrap { +.mr-popup-actions-wrap { display: flex; justify-content: flex-end; - padding: 0 var(--ml-spacing-16); - margin-bottom: var(--ml-spacing-8); + padding: 0 var(--mr-spacing-16); + margin-bottom: var(--mr-spacing-8); } -.ml-resolved-entry { +.mr-resolved-entry { transition: all 0.3s ease; background: rgba(76, 175, 80, 0.2); border: 1px solid #4caf50; - border-radius: var(--ml-radius-lg); + border-radius: var(--mr-radius-lg); } -.ml-resolved-badge { +.mr-resolved-badge { display: inline-flex; align-items: center; - padding: var(--ml-spacing-4) var(--ml-spacing-12); + padding: var(--mr-spacing-4) var(--mr-spacing-12); color: #fff; - font-size: var(--ml-font-md); + font-size: var(--mr-font-md); font-weight: 600; background: #4caf50; - border-radius: var(--ml-radius-md); + border-radius: var(--mr-radius-md); } -.model-linker-floating-button { +.model-resolver-floating-button { position: fixed; - top: var(--ml-spacing-10); - right: var(--ml-spacing-10); - z-index: var(--ml-z-floating-button); - padding: var(--ml-spacing-8) var(--ml-spacing-16); + top: var(--mr-spacing-10); + right: var(--mr-spacing-10); + z-index: var(--mr-z-floating-button); + padding: var(--mr-spacing-8) var(--mr-spacing-16); color: var(--input-text, #fff); - font-size: var(--ml-font-lg); + font-size: var(--mr-font-lg); background: var(--comfy-input-bg, #353535); border: 2px solid var(--primary-color, #007acc); - border-radius: var(--ml-radius-lg); + border-radius: var(--mr-radius-lg); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); } -.model-linker-floating-button:hover { +.model-resolver-floating-button:hover { background: var(--primary-color, #007acc); transform: scale(1.05); } -.comfyui-model-linker-tab-button .mdi, -.comfyui-model-linker-tab-button .mdi-link-variant { +.comfyui-model-resolver-tab-button .mdi, +.comfyui-model-resolver-tab-button .mdi-link-variant { font-size: 18px; line-height: 1; } -.ml-sidebar-dock-panel { +.mr-sidebar-dock-panel { box-sizing: border-box; width: 100%; height: 100%; min-width: 0; min-height: 0; overflow: hidden; - color: var(--ml-text); - background: var(--ml-bg); + color: var(--mr-text); + background: var(--mr-bg); } -#model-linker-modal.ml-is-docked { +#model-resolver-modal.mr-is-docked { position: relative; inset: auto; top: auto; @@ -594,7 +594,7 @@ z-index: auto; } -#model-linker-modal .ml-window-btn--undock { +#model-resolver-modal .mr-window-btn--undock { display: none; width: 46px; min-width: 46px; @@ -603,15 +603,15 @@ padding: 0; } -#model-linker-modal.ml-is-docked .ml-window-btn--undock { +#model-resolver-modal.mr-is-docked .mr-window-btn--undock { display: flex; } -#model-linker-modal.ml-is-docked .ml-window-btn--dock { +#model-resolver-modal.mr-is-docked .mr-window-btn--dock { display: none; } -@keyframes ml-slide-down { +@keyframes mr-slide-down { from { opacity: 0; transform: translateX(-50%) translateY(-100%); diff --git a/web/linker.js b/web/linker.js deleted file mode 100644 index 818923d..0000000 --- a/web/linker.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * ComfyUI Model Linker Extension - Frontend - * - * Provides a menu button and dialog interface for relinking missing models in workflows. - */ - -import { app } from "../../../scripts/app.js"; -import { ModelLinker } from "./linker/model_linker.js"; -import { registerGlobalHelpers } from "./linker/globals.js"; - -registerGlobalHelpers(); - -const modelLinker = new ModelLinker(); - -app.registerExtension({ - name: "Model Linker", - setup: modelLinker.setup -}); diff --git a/web/log_system/config.js b/web/log_system/config.js index 2d1b178..7997e06 100644 --- a/web/log_system/config.js +++ b/web/log_system/config.js @@ -1,4 +1,4 @@ -/** +/** author: Azornes title: AzLogs version: 1.5.5 @@ -9,10 +9,10 @@ description: Logging Configuration export const LOG_LEVEL = 'DEBUG'; // Logger module name. Set to null to use the default project name. -export const LOG_MODULE_NAME = "MLinker"; +export const LOG_MODULE_NAME = "MResolver"; // Default project/logger name used when LOG_MODULE_NAME is not set. -export const DEFAULT_LOGGER_NAME = 'MLinker'; +export const DEFAULT_LOGGER_NAME = 'MResolver'; // Enable styled console logs. export const USE_COLORS = true; diff --git a/web/resolver.js b/web/resolver.js new file mode 100644 index 0000000..17d2da0 --- /dev/null +++ b/web/resolver.js @@ -0,0 +1,18 @@ +/** + * ComfyUI Model Resolver Extension - Frontend + * + * Provides a menu button and dialog interface for relinking missing models in workflows. + */ + +import { app } from "../../../scripts/app.js"; +import { ModelResolver as ModelResolverClass } from "./resolver/model_resolver.js"; +import { registerGlobalHelpers } from "./resolver/globals.js"; + +registerGlobalHelpers(); + +const modelResolver = new ModelResolverClass(); + +app.registerExtension({ + name: "Model Resolver", + setup: modelResolver.setup +}); diff --git a/web/linker/actions/queue_methods.js b/web/resolver/actions/queue_methods.js similarity index 86% rename from web/linker/actions/queue_methods.js rename to web/resolver/actions/queue_methods.js index c92d79e..646916f 100644 --- a/web/linker/actions/queue_methods.js +++ b/web/resolver/actions/queue_methods.js @@ -1,4 +1,4 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; @@ -6,22 +6,22 @@ export const queueMethods = { createContent() { // Wrap the body in a two-column layout: left = items, right = queued panel const body = $el("div", { - id: "model-linker-body" + id: "model-resolver-body" }); - this.contentElement = $el("div.ml-scrollable", { - id: "model-linker-content" + this.contentElement = $el("div.mr-scrollable", { + id: "model-resolver-content" }); this.queueElement = $el("div", { - id: "model-linker-queue" + id: "model-resolver-queue" }, [ this.createQueuePanel() ]); // Splitter between content and queue this.splitterElement = $el("div", { - id: "model-linker-splitter", + id: "model-resolver-splitter", ondragstart: (e) => e.preventDefault() }); @@ -31,7 +31,7 @@ export const queueMethods = { // Restore saved queue width and wire splitter try { - const savedSplit = localStorage.getItem('model_linker_split_w'); + const savedSplit = localStorage.getItem('model_resolver_split_w'); if (savedSplit) { const w = parseInt(savedSplit, 10); if (!isNaN(w) && w > 0) { @@ -61,7 +61,7 @@ export const queueMethods = { // Restore queue collapsed state try { - const col = localStorage.getItem('model_linker_queue_collapsed'); + const col = localStorage.getItem('model_resolver_queue_collapsed'); if (col === '1') this.setQueueCollapsed(true); } catch (e) { } @@ -70,18 +70,18 @@ export const queueMethods = { createQueuePanel() { // Header row with title and clear button - this.queueHeader = $el("div.ml-queue-header", {}, [ - $el("div#queue-title.ml-queue-title", { textContent: "Queued Selections (0)" }), - $el("div.ml-queue-actions", {}, [ + this.queueHeader = $el("div.mr-queue-header", {}, [ + $el("div#queue-title.mr-queue-title", { textContent: "Queued Selections (0)" }), + $el("div.mr-queue-actions", {}, [ $el("button", { id: "queue-toggle", - className: "ml-btn ml-btn-secondary ml-btn-sm", + className: "mr-btn mr-btn-secondary mr-btn-sm", textContent: "Collapse", onclick: () => this.toggleQueueCollapsed() }), $el("button", { id: "queue-clear", - className: "ml-btn ml-btn-secondary ml-btn-sm", + className: "mr-btn mr-btn-secondary mr-btn-sm", textContent: "Clear All", onclick: () => this.clearAllQueued() }) @@ -89,10 +89,10 @@ export const queueMethods = { ]); // Scrollable list - this.queueList = $el("div#queue-list.ml-queue-list"); + this.queueList = $el("div#queue-list.mr-queue-list"); - const panel = $el("div.ml-queue-panel", {}, [ - $el("div.ml-queue-stack", {}, [this.queueHeader, this.queueList]) + const panel = $el("div.mr-queue-panel", {}, [ + $el("div.mr-queue-stack", {}, [this.queueHeader, this.queueList]) ]); return panel; }, @@ -107,22 +107,22 @@ export const queueMethods = { if (toggleBtn) toggleBtn.textContent = this.queueCollapsed ? 'Expand' : 'Collapse'; if (!list.length) { - this.queueList.innerHTML = '

No selections queued.
'; + this.queueList.innerHTML = '
No selections queued.
'; return; } - let html = '
'; + let html = '
'; for (let i = 0; i < list.length; i++) { const r = list[i]; const label = (r.resolved_model?.relative_path || r.resolved_model?.filename || r.resolved_path || '').toString(); const nodeLabel = r.node_label || r.node_type || (r.subgraph_id ? 'Subgraph' : 'Node'); const orig = (r.original_path || '').toString(); const rmId = `queue-remove-${i}`; - html += `
`; - html += `
${this.escapeHtml(nodeLabel)} #${this.escapeHtml(String(r.node_id))}
`; - html += `
Original${this.escapeHtml(orig)}
`; - html += `
Selected${this.escapeHtml(label)}
`; - html += `
`; + html += `
`; + html += `
${this.escapeHtml(nodeLabel)} #${this.escapeHtml(String(r.node_id))}
`; + html += `
Original${this.escapeHtml(orig)}
`; + html += `
Selected${this.escapeHtml(label)}
`; + html += `
`; html += `
`; } html += '
'; @@ -162,7 +162,7 @@ export const queueMethods = { this.updateApplyPendingButton?.(); this.updateQueuePanel(); try { - document.querySelectorAll('.model-linker-selected').forEach(el => { el.style.display = 'none'; el.innerHTML = ''; }); + document.querySelectorAll('.model-resolver-selected').forEach(el => { el.style.display = 'none'; el.innerHTML = ''; }); } catch (e) { /* ignore */ } }, @@ -199,10 +199,10 @@ export const queueMethods = { const label = selection.resolved_model?.relative_path || selection.resolved_model?.filename || selection.resolved_path || ''; const resolveBtnId = `selected-remove-${nodeId}-${widgetIndex}`; - selectedBar.innerHTML = `
`; - selectedBar.innerHTML += `✓ Selected:`; - selectedBar.innerHTML += `${label}`; - selectedBar.innerHTML += ``; + selectedBar.innerHTML = `
`; + selectedBar.innerHTML += `✓ Selected:`; + selectedBar.innerHTML += `${label}`; + selectedBar.innerHTML += ``; selectedBar.innerHTML += `
`; selectedBar.style.display = 'block'; @@ -254,9 +254,9 @@ export const queueMethods = { setQueueCollapsed(collapsed) { this.queueCollapsed = !!collapsed; if (this.queueCollapsed) { - try { localStorage.setItem('model_linker_queue_collapsed', '1'); } catch (e) { } + try { localStorage.setItem('model_resolver_queue_collapsed', '1'); } catch (e) { } } else { - try { localStorage.setItem('model_linker_queue_collapsed', '0'); } catch (e) { } + try { localStorage.setItem('model_resolver_queue_collapsed', '0'); } catch (e) { } } this.updateQueueVisibility(); this.updateQueuePanel(); @@ -313,7 +313,7 @@ export const queueMethods = { document.body.style.cursor = 'col-resize'; this._suppressQueueEdgeClick = true; this.splitterElement.style.display = ''; - document.getElementById('model-linker-body')?.classList.add('ml-queue-preview-collapsed'); + document.getElementById('model-resolver-body')?.classList.add('mr-queue-preview-collapsed'); this.queueElement.style.display = 'none'; this.queueElement.style.width = '0px'; this.startSplitDrag( @@ -328,10 +328,10 @@ export const queueMethods = { e?.preventDefault?.(); if (!this.queueElement) return; const rect = this.queueElement.getBoundingClientRect(); - const body = document.getElementById('model-linker-body'); + const body = document.getElementById('model-resolver-body'); const bodyRect = body ? body.getBoundingClientRect() : { width: window.innerWidth }; this._splitDragging = true; - body?.classList.add('ml-is-resizing-queue'); + body?.classList.add('mr-is-resizing-queue'); this._splitStart = { x: e.clientX, startWidth: Number.isFinite(startWidth) ? startWidth : rect.width, @@ -364,7 +364,7 @@ export const queueMethods = { this._splitEdgeOpenedPastThreshold = true; if (this.queueCollapsed) { this.queueCollapsed = false; - try { localStorage.setItem('model_linker_queue_collapsed', '0'); } catch (error) { } + try { localStorage.setItem('model_resolver_queue_collapsed', '0'); } catch (error) { } this.updateQueueToggleIcon(); this.updateQueuePanel(); } @@ -374,8 +374,8 @@ export const queueMethods = { : this._pendingSplitWidth <= 140; if (previewCollapsed !== this._splitPreviewCollapsed) { this._splitPreviewCollapsed = previewCollapsed; - const body = document.getElementById('model-linker-body'); - body?.classList.toggle('ml-queue-preview-collapsed', previewCollapsed); + const body = document.getElementById('model-resolver-body'); + body?.classList.toggle('mr-queue-preview-collapsed', previewCollapsed); this.queueElement.style.display = previewCollapsed ? 'none' : ''; } const now = performance.now(); @@ -399,9 +399,9 @@ export const queueMethods = { if (this.queueElement && this._pendingSplitWidth && !this._splitPreviewCollapsed) { this.queueElement.style.width = `${this._pendingSplitWidth}px`; } - const body = document.getElementById('model-linker-body'); - body?.classList.remove('ml-is-resizing-queue'); - body?.classList.remove('ml-queue-preview-collapsed'); + const body = document.getElementById('model-resolver-body'); + body?.classList.remove('mr-is-resizing-queue'); + body?.classList.remove('mr-queue-preview-collapsed'); document.removeEventListener('mousemove', this._onSplitMove); if (this._splitEdgeOpen && !this._pendingSplitWidth) { try { @@ -409,10 +409,10 @@ export const queueMethods = { this.queueElement.style.width = `${restoreWidth}px`; this.queueElement.style.display = ''; if (this.splitterElement) this.splitterElement.style.display = ''; - localStorage.setItem('model_linker_split_w', String(restoreWidth)); + localStorage.setItem('model_resolver_split_w', String(restoreWidth)); } catch (e) { } this.queueCollapsed = false; - try { localStorage.setItem('model_linker_queue_collapsed', '0'); } catch (e) { } + try { localStorage.setItem('model_resolver_queue_collapsed', '0'); } catch (e) { } this.updateQueueVisibility(); this.updateQueuePanel(); this._splitEdgeOpen = false; @@ -432,7 +432,7 @@ export const queueMethods = { const restoreWidth = Math.max(240, Math.round(this._splitStart?.startWidth || 320)); this.queueElement.style.width = `${restoreWidth}px`; this.queueElement.style.display = ''; - localStorage.setItem('model_linker_split_w', String(restoreWidth)); + localStorage.setItem('model_resolver_split_w', String(restoreWidth)); } catch (e) { } this._pendingSplitWidth = null; this._lastSplitDragApply = 0; @@ -449,7 +449,7 @@ export const queueMethods = { if (this.queueElement) this.queueElement.style.display = ''; try { const rect = this.queueElement.getBoundingClientRect(); - localStorage.setItem('model_linker_split_w', String(Math.round(rect.width))); + localStorage.setItem('model_resolver_split_w', String(Math.round(rect.width))); } catch (e) { } this._pendingSplitWidth = null; this._lastSplitDragApply = 0; @@ -520,7 +520,7 @@ export const queueMethods = { return; } - const response = await api.fetchApi('/model_linker/resolve', { + const response = await api.fetchApi('/model_resolver/resolve', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workflow, resolutions: list }) @@ -543,7 +543,7 @@ export const queueMethods = { this.showNotification('Failed to apply selections: ' + (data.error || 'Unknown error'), 'error'); } } catch (e) { - console.error('Model Linker: applyPendingResolutions error', e); + console.error('Model Resolver: applyPendingResolutions error', e); this.showNotification('Error applying selections: ' + e.message, 'error'); } }, @@ -558,7 +558,7 @@ export const queueMethods = { this.applyPendingBtn.textContent = `Apply Selected (${count})`; this.setTooltip(this.applyPendingBtn, tooltip); this.applyPendingBtn.setAttribute('aria-disabled', String(isEmpty)); - this.applyPendingBtn.classList.toggle('ml-btn-is-disabled', isEmpty); + this.applyPendingBtn.classList.toggle('mr-btn-is-disabled', isEmpty); this.updateBatchFooterButtons(); }, @@ -573,18 +573,18 @@ export const queueMethods = { if (this.selectMenuButton) { this.selectMenuButton.textContent = `Select (${selectedCount}/${totalCount})`; - this.selectMenuButton.classList.toggle('ml-btn-is-disabled', totalCount === 0); + this.selectMenuButton.classList.toggle('mr-btn-is-disabled', totalCount === 0); } if (this.searchMenuButton) { this.searchMenuButton.textContent = this.batchSearchRunning ? 'Searching...' : 'Search'; - this.searchMenuButton.classList.toggle('ml-btn-is-disabled', totalCount === 0 || this.batchSearchRunning); + this.searchMenuButton.classList.toggle('mr-btn-is-disabled', totalCount === 0 || this.batchSearchRunning); } if (this.downloadMenuButton) { const label = activeCount > 0 ? `Cancel Downloads (${activeCount})` : 'Download'; this.downloadMenuButton.textContent = label; - this.downloadMenuButton.classList.toggle('ml-btn-danger', activeCount > 0); - this.downloadMenuButton.classList.toggle('ml-btn-download', activeCount === 0); - this.downloadMenuButton.classList.toggle('ml-btn-is-disabled', activeCount === 0 && downloadableAll === 0); + this.downloadMenuButton.classList.toggle('mr-btn-danger', activeCount > 0); + this.downloadMenuButton.classList.toggle('mr-btn-download', activeCount === 0); + this.downloadMenuButton.classList.toggle('mr-btn-is-disabled', activeCount === 0 && downloadableAll === 0); this.setTooltip( this.downloadMenuButton, activeCount > 0 @@ -597,14 +597,14 @@ export const queueMethods = { } }, - createFooterMenu(name, label, items = [], buttonClass = 'ml-btn-secondary') { - const button = $el(`button.ml-btn.${buttonClass}.ml-footer-btn.ml-footer-menu-button`, { + createFooterMenu(name, label, items = [], buttonClass = 'mr-btn-secondary') { + const button = $el(`button.mr-btn.${buttonClass}.mr-footer-btn.mr-footer-menu-button`, { type: 'button', 'aria-haspopup': 'menu', 'aria-expanded': 'false', onclick: (event) => { event.stopPropagation(); - if (button.classList.contains('ml-btn-is-disabled')) { + if (button.classList.contains('mr-btn-is-disabled')) { if (name === 'search' && this.batchSearchRunning) { this.showNotification('Batch search is already running.', 'info'); } else if (name === 'download') { @@ -618,10 +618,10 @@ export const queueMethods = { } }, [$el("span", { textContent: label })]); - const menu = $el("div.ml-footer-menu", { role: 'menu' }, items.map(item => ( + const menu = $el("div.mr-footer-menu", { role: 'menu' }, items.map(item => ( item === 'divider' - ? $el("div.ml-footer-menu-divider", {}) - : $el("button.ml-footer-menu-item", { + ? $el("div.mr-footer-menu-divider", {}) + : $el("button.mr-footer-menu-item", { type: 'button', role: 'menuitem', onclick: (event) => { @@ -634,7 +634,7 @@ export const queueMethods = { this.footerMenuButtons.set(name, button); this.footerMenus.set(name, menu); - return $el("div.ml-footer-menu-wrap", {}, [button, menu]); + return $el("div.mr-footer-menu-wrap", {}, [button, menu]); }, createFooter() { @@ -672,25 +672,25 @@ export const queueMethods = { this.searchMenuWrap = searchMenu; // Store reference to download all button so we can update its text - this.downloadAllButton = $el("button.ml-btn.ml-btn-download.ml-footer-btn", { + this.downloadAllButton = $el("button.mr-btn.mr-btn-download.mr-footer-btn", { "data-tooltip": "Download every missing model that has a known download source.", "aria-label": "Download all missing models", onclick: () => this.handleDownloadAllClick() }, [ - $el("span.ml-btn-icon", { textContent: "☁" }), + $el("span.mr-btn-icon", { textContent: "☁" }), $el("span", { textContent: " Download All Missing" }) ]); // Auto-resolve button (secondary style) - this.autoResolveButton = $el("button.ml-btn.ml-btn-secondary.ml-footer-btn", { + this.autoResolveButton = $el("button.mr-btn.mr-btn-secondary.mr-footer-btn", { "data-tooltip": "Automatically link all missing models with a 100% local match.", "aria-label": "Auto-link all 100 percent local matches", onclick: () => this.autoResolve100Percent() }, [ - $el("span.ml-btn-icon", { textContent: "🔗" }), + $el("span.mr-btn-icon", { textContent: "🔗" }), $el("span", { textContent: " Auto-Link 100%" }) ]); - this.queueExactButton = $el("button.ml-btn.ml-btn-secondary.ml-footer-btn", { + this.queueExactButton = $el("button.mr-btn.mr-btn-secondary.mr-footer-btn", { type: 'button', onclick: () => this.queueExactLocalMatchesBatch('selected') }, [ @@ -698,7 +698,7 @@ export const queueMethods = { ]); // Apply pending resolutions button - this.applyPendingBtn = $el("button.ml-btn.ml-btn-primary.ml-footer-btn", { + this.applyPendingBtn = $el("button.mr-btn.mr-btn-primary.mr-footer-btn", { id: "apply-pending-resolutions", "data-tooltip": "Apply the model links you selected from local matches or search results.", "aria-label": "Apply selected model links", @@ -709,7 +709,7 @@ export const queueMethods = { this.applyPendingResolutions(); } }); - this.applyPendingBtn.classList.add('ml-btn-is-disabled'); + this.applyPendingBtn.classList.add('mr-btn-is-disabled'); this.downloadAllButton.setAttribute('aria-label', 'Download all missing models'); this.autoResolveButton.setAttribute('aria-label', 'Auto-link all 100 percent local matches'); this.queueExactButton.setAttribute('aria-label', 'Queue exact local matches'); @@ -726,14 +726,14 @@ export const queueMethods = { { label: 'Download All With Sources', action: () => this.downloadMissingBatch('all') }, 'divider', { label: 'Cancel Downloads', action: () => { this.closeFooterMenus(); this.cancelAllDownloads(); } } - ], 'ml-btn-download'); + ], 'mr-btn-download'); this.downloadMenuButton = this.footerMenuButtons.get('download'); this.downloadMenuWrap = downloadMenu; this.downloadAllButton = this.downloadMenuButton; this.downloadAllButton.setAttribute('aria-label', 'Download missing models'); this.setTooltip(this.downloadAllButton, 'Download selected models or all missing models with known download sources.'); - return $el("div.ml-footer", {}, [ + return $el("div.mr-footer", {}, [ selectMenu, searchMenu, this.queueExactButton, @@ -758,7 +758,7 @@ export const queueMethods = { } ); } catch (error) { - console.warn('Model Linker: tab content animation failed', error); + console.warn('Model Resolver: tab content animation failed', error); } }, @@ -786,11 +786,11 @@ export const queueMethods = { for (const downloadId of downloadIds) { try { - await api.fetchApi(`/model_linker/cancel/${downloadId}`, { + await api.fetchApi(`/model_resolver/cancel/${downloadId}`, { method: 'POST' }); } catch (error) { - console.error('Model Linker: Error cancelling download:', error); + console.error('Model Resolver: Error cancelling download:', error); } } }, @@ -807,23 +807,23 @@ export const queueMethods = { const activeCount = Object.keys(this.activeDownloads).length; if (activeCount > 0) { - this.downloadAllButton.innerHTML = `✕ Cancel All (${activeCount})`; + this.downloadAllButton.innerHTML = `✕ Cancel All (${activeCount})`; this.downloadAllButton.setAttribute( 'data-tooltip', `Cancel ${activeCount} active download${activeCount > 1 ? 's' : ''}.` ); this.downloadAllButton.setAttribute('aria-label', 'Cancel all active downloads'); - this.downloadAllButton.classList.remove('ml-btn-download'); - this.downloadAllButton.classList.add('ml-btn-danger'); + this.downloadAllButton.classList.remove('mr-btn-download'); + this.downloadAllButton.classList.add('mr-btn-danger'); } else { - this.downloadAllButton.innerHTML = `☁ Download All Missing`; + this.downloadAllButton.innerHTML = `☁ Download All Missing`; this.downloadAllButton.setAttribute( 'data-tooltip', 'Download every missing model that has a known download source.' ); this.downloadAllButton.setAttribute('aria-label', 'Download all missing models'); - this.downloadAllButton.classList.remove('ml-btn-danger'); - this.downloadAllButton.classList.add('ml-btn-download'); + this.downloadAllButton.classList.remove('mr-btn-danger'); + this.downloadAllButton.classList.add('mr-btn-download'); } } }; diff --git a/web/linker/actions/resolve_download_methods.js b/web/resolver/actions/resolve_download_methods.js similarity index 93% rename from web/linker/actions/resolve_download_methods.js rename to web/resolver/actions/resolve_download_methods.js index fade45b..f5bdb06 100644 --- a/web/linker/actions/resolve_download_methods.js +++ b/web/resolver/actions/resolve_download_methods.js @@ -1,4 +1,4 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; @@ -37,7 +37,7 @@ export const resolveDownloadMethods = { original_lora_name: ref.name || ref.original_path })); - const response = await api.fetchApi('/model_linker/resolve', { + const response = await api.fetchApi('/model_resolver/resolve', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ @@ -71,7 +71,7 @@ export const resolveDownloadMethods = { } } catch (error) { - console.error('Model Linker: Error resolving model:', error); + console.error('Model Resolver: Error resolving model:', error); this.showNotification('Error resolving model: ' + error.message, 'error'); } }, @@ -89,7 +89,7 @@ export const resolveDownloadMethods = { } // Analyze workflow first - const analyzeResponse = await api.fetchApi('/model_linker/analyze', { + const analyzeResponse = await api.fetchApi('/model_resolver/analyze', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workflow }) @@ -129,7 +129,7 @@ export const resolveDownloadMethods = { } // Apply resolutions - const resolveResponse = await api.fetchApi('/model_linker/resolve', { + const resolveResponse = await api.fetchApi('/model_resolver/resolve', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ @@ -167,7 +167,7 @@ export const resolveDownloadMethods = { } } catch (error) { - console.error('Model Linker: Error auto-resolving:', error); + console.error('Model Resolver: Error auto-resolving:', error); this.showNotification('Error auto-resolving: ' + error.message, 'error'); return null; } @@ -187,7 +187,7 @@ export const resolveDownloadMethods = { } // Analyze workflow first - const analyzeResponse = await api.fetchApi('/model_linker/analyze', { + const analyzeResponse = await api.fetchApi('/model_resolver/analyze', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workflow }) @@ -232,7 +232,7 @@ export const resolveDownloadMethods = { this.updateDownloadAllButtonState(); } catch (error) { - console.error('Model Linker: Error in downloadAllMissing:', error); + console.error('Model Resolver: Error in downloadAllMissing:', error); this.showNotification('Error starting downloads: ' + error.message, 'error'); } }, @@ -351,7 +351,7 @@ export const resolveDownloadMethods = { await this.searchOnline(missing); } catch (error) { failed += 1; - console.error('Model Linker: batch search item failed:', error); + console.error('Model Resolver: batch search item failed:', error); } completed += 1; this.updateBatchFooterButtons(); @@ -436,7 +436,7 @@ export const resolveDownloadMethods = { } // Re-analyze workflow to find the newly downloaded model - const analyzeResponse = await api.fetchApi('/model_linker/analyze', { + const analyzeResponse = await api.fetchApi('/model_resolver/analyze', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workflow }) @@ -488,7 +488,7 @@ export const resolveDownloadMethods = { original_lora_name: ref.name || ref.original_path })); - const resolveResponse = await api.fetchApi('/model_linker/resolve', { + const resolveResponse = await api.fetchApi('/model_resolver/resolve', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ @@ -513,7 +513,7 @@ export const resolveDownloadMethods = { await this.loadWorkflowData(); } catch (error) { - console.error('Model Linker: Error auto-resolving after download:', error); + console.error('Model Resolver: Error auto-resolving after download:', error); // Still reload UI even on error await this.loadWorkflowData(); } @@ -544,24 +544,24 @@ export const resolveDownloadMethods = { // Disable button and show progress with cancel button immediately if (downloadBtn) { downloadBtn.disabled = true; - downloadBtn.classList.remove('ml-is-success-action', 'ml-btn-primary'); + downloadBtn.classList.remove('mr-is-success-action', 'mr-btn-primary'); downloadBtn.textContent = 'Starting...'; } if (progressDiv) { - progressDiv.classList.remove('ml-is-hidden'); - progressDiv.classList.add('ml-is-visible'); + progressDiv.classList.remove('mr-is-hidden'); + progressDiv.classList.add('mr-is-visible'); // Show progress bar with cancel button immediately progressDiv.innerHTML = this.renderProgressWithAction({ percent: 0, - leftText: 'Connecting...', + leftText: 'Connecting...', rightText: '', - actionClass: 'cancel-download-btn-pending ml-btn ml-btn-danger ml-btn-sm', + actionClass: 'cancel-download-btn-pending mr-btn mr-btn-danger mr-btn-sm', actionText: 'Cancel' }); } // Start download - const response = await api.fetchApi('/model_linker/download', { + const response = await api.fetchApi('/model_resolver/download', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ @@ -599,14 +599,14 @@ export const resolveDownloadMethods = { this.pollDownloadProgress(downloadId); } catch (error) { - console.error('Model Linker: Download error:', error); + console.error('Model Resolver: Download error:', error); if (progressDiv) { progressDiv.innerHTML = this.renderStatusMessage(error.message, 'error'); } if (downloadBtn) { downloadBtn.disabled = false; - downloadBtn.classList.remove('ml-is-success-action', 'ml-btn-primary'); - downloadBtn.innerHTML = '☁ Retry'; + downloadBtn.classList.remove('mr-is-success-action', 'mr-btn-primary'); + downloadBtn.innerHTML = '☁ Retry'; } this.showNotification('Download failed: ' + error.message, 'error'); } @@ -620,7 +620,7 @@ export const resolveDownloadMethods = { if (!info) return; try { - const response = await api.fetchApi(`/model_linker/progress/${downloadId}`); + const response = await api.fetchApi(`/model_resolver/progress/${downloadId}`); if (!response.ok) { throw new Error('Failed to get progress'); } @@ -639,7 +639,7 @@ export const resolveDownloadMethods = { percent, leftText: `${downloaded} / ${total} (${percent}%)`, rightText: speed, - actionClass: 'cancel-download-btn ml-btn ml-btn-danger ml-btn-sm', + actionClass: 'cancel-download-btn mr-btn mr-btn-danger mr-btn-sm', actionText: 'Cancel', actionDataAttr: `data-download-id="${downloadId}"` }); @@ -663,8 +663,8 @@ export const resolveDownloadMethods = { } if (downloadBtn) { downloadBtn.textContent = '✓ Done'; - downloadBtn.classList.remove('ml-is-success-action'); - downloadBtn.classList.add('ml-btn-primary'); + downloadBtn.classList.remove('mr-is-success-action'); + downloadBtn.classList.add('mr-btn-primary'); } delete this.activeDownloads[downloadId]; this.updateDownloadAllButtonState(); @@ -682,7 +682,7 @@ export const resolveDownloadMethods = { } if (downloadBtn) { downloadBtn.disabled = false; - downloadBtn.classList.remove('ml-is-success-action', 'ml-btn-primary'); + downloadBtn.classList.remove('mr-is-success-action', 'mr-btn-primary'); downloadBtn.textContent = 'Retry'; } delete this.activeDownloads[downloadId]; @@ -694,8 +694,8 @@ export const resolveDownloadMethods = { } if (downloadBtn) { downloadBtn.disabled = false; - downloadBtn.classList.remove('ml-is-success-action', 'ml-btn-primary'); - downloadBtn.innerHTML = '☁ Download'; + downloadBtn.classList.remove('mr-is-success-action', 'mr-btn-primary'); + downloadBtn.innerHTML = '☁ Download'; } delete this.activeDownloads[downloadId]; this.updateDownloadAllButtonState(); @@ -707,7 +707,7 @@ export const resolveDownloadMethods = { } } catch (error) { - console.error('Model Linker: Progress poll error:', error); + console.error('Model Resolver: Progress poll error:', error); const info = this.activeDownloads[downloadId]; // Update UI to show error state instead of just disappearing if (info) { @@ -718,8 +718,8 @@ export const resolveDownloadMethods = { if (downloadBtn) { downloadBtn.disabled = false; downloadBtn.textContent = 'Retry'; - downloadBtn.classList.remove('ml-btn-primary'); - downloadBtn.classList.add('ml-is-success-action'); + downloadBtn.classList.remove('mr-btn-primary'); + downloadBtn.classList.add('mr-is-success-action'); } } delete this.activeDownloads[downloadId]; @@ -732,7 +732,7 @@ export const resolveDownloadMethods = { */ async cancelDownload(downloadId) { try { - const response = await api.fetchApi(`/model_linker/cancel/${downloadId}`, { + const response = await api.fetchApi(`/model_resolver/cancel/${downloadId}`, { method: 'POST' }); @@ -746,7 +746,7 @@ export const resolveDownloadMethods = { } } catch (error) { - console.error('Model Linker: Cancel error:', error); + console.error('Model Resolver: Cancel error:', error); this.showNotification('Failed to cancel download', 'error'); } }, @@ -829,8 +829,8 @@ export const resolveDownloadMethods = { searchBtn.innerHTML = `${this.getSearchIconHtml()} Searching ${selectedSourceLabel}...`; } if (resultsDiv) { - resultsDiv.classList.remove('ml-is-hidden'); - resultsDiv.classList.add('ml-is-visible'); + resultsDiv.classList.remove('mr-is-hidden'); + resultsDiv.classList.add('mr-is-visible'); this.displaySearchResults(missing, state, resultsDiv); } for (const source of sourceIds) { @@ -877,9 +877,9 @@ export const resolveDownloadMethods = { }; try { - console.log('Model Linker: Search request:', JSON.stringify(searchData)); + console.log('Model Resolver: Search request:', JSON.stringify(searchData)); - const response = await api.fetchApi('/model_linker/search', { + const response = await api.fetchApi('/model_resolver/search', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(searchData) @@ -890,7 +890,7 @@ export const resolveDownloadMethods = { } const data = await response.json(); - console.log('Model Linker: Search response:', JSON.stringify(data)); + console.log('Model Resolver: Search response:', JSON.stringify(data)); if (state.activeSearchRunId !== searchRunId) { return { source, stale: true }; @@ -939,7 +939,7 @@ export const resolveDownloadMethods = { this.applySearchResultSuggestion(missing); return { source, data }; } catch (error) { - console.error(`Model Linker: Search error for ${source}:`, error); + console.error(`Model Resolver: Search error for ${source}:`, error); if (state.activeSearchRunId !== searchRunId) { return { source, stale: true, error }; } @@ -975,7 +975,7 @@ export const resolveDownloadMethods = { } } catch (error) { - console.error('Model Linker: Search error:', error); + console.error('Model Resolver: Search error:', error); this.clearSearchProgressTimers(searchRunId); state.lastAttemptError = error.message; this.persistSearchStateForActiveWorkflow(); @@ -1027,7 +1027,7 @@ export const resolveDownloadMethods = { }; console.log('resolveUrnAsync payload:', JSON.stringify(payload)); - const response = await api.fetchApi('/model_linker/search', { + const response = await api.fetchApi('/model_resolver/search', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) @@ -1043,16 +1043,16 @@ export const resolveDownloadMethods = { if (data) { const loadingEl = document.getElementById(loadingElementId); if (loadingEl && data.civitai) { - loadingEl.classList.remove('ml-is-muted', 'ml-is-error'); + loadingEl.classList.remove('mr-is-muted', 'mr-is-error'); const civitai = data.civitai; const labelHtml = this.renderVersionedModelNameHtml(civitai.name, civitai.version_name) || this.escapeHtml(civitai.filename || 'Model'); const url = modelUrl || `https://civitai.com/models/${modelId}?modelVersionId=${versionId}`; - loadingEl.innerHTML = `${labelHtml}`; + loadingEl.innerHTML = `${labelHtml}`; } else if (loadingEl) { loadingEl.textContent = 'Not found'; - loadingEl.classList.remove('ml-is-error'); - loadingEl.classList.add('ml-is-muted'); + loadingEl.classList.remove('mr-is-error'); + loadingEl.classList.add('mr-is-muted'); } const downloadEl = document.getElementById(downloadContainerId); @@ -1065,33 +1065,33 @@ export const resolveDownloadMethods = { this.refreshUrnLocalMatches(missing); } } else if (downloadEl) { - downloadEl.innerHTML = `
Unable to resolve direct download for this URN.
`; + downloadEl.innerHTML = `
Unable to resolve direct download for this URN.
`; } } else { const loadingEl = document.getElementById(loadingElementId); if (loadingEl) { loadingEl.textContent = 'Error'; - loadingEl.classList.remove('ml-is-muted'); - loadingEl.classList.add('ml-is-error'); + loadingEl.classList.remove('mr-is-muted'); + loadingEl.classList.add('mr-is-error'); } const downloadContainerId = loadingElementId.replace('urn-loading-', 'urn-download-'); const downloadEl = document.getElementById(downloadContainerId); if (downloadEl) { - downloadEl.innerHTML = `
Failed to resolve URN download.
`; + downloadEl.innerHTML = `
Failed to resolve URN download.
`; } } } catch (error) { - console.error('Model Linker: URN resolve error:', error); + console.error('Model Resolver: URN resolve error:', error); const loadingEl = document.getElementById(loadingElementId); if (loadingEl) { loadingEl.textContent = 'Error'; - loadingEl.classList.remove('ml-is-muted'); - loadingEl.classList.add('ml-is-error'); + loadingEl.classList.remove('mr-is-muted'); + loadingEl.classList.add('mr-is-error'); } const downloadContainerId = loadingElementId.replace('urn-loading-', 'urn-download-'); const downloadEl = document.getElementById(downloadContainerId); if (downloadEl) { - downloadEl.innerHTML = `
Failed to resolve URN download.
`; + downloadEl.innerHTML = `
Failed to resolve URN download.
`; } } }, @@ -1148,10 +1148,10 @@ export const resolveDownloadMethods = { const renderSourceOptions = () => { const options = this.getSearchSourceOptions(); sourceList.innerHTML = options - .map(option => `
${this.escapeHtml(option.label)}
`) + .map(option => `
${this.escapeHtml(option.label)}
`) .join(''); sourceList.style.display = 'block'; - sourceList.querySelectorAll('.ml-download-target-option').forEach(optionEl => { + sourceList.querySelectorAll('.mr-download-target-option').forEach(optionEl => { optionEl.addEventListener('mousedown', (event) => { event.preventDefault(); const value = decodeURIComponent(optionEl.dataset.value || ''); @@ -1372,23 +1372,23 @@ export const resolveDownloadMethods = { try { btn.disabled = true; - btn.classList.remove('ml-is-success-action', 'ml-btn-primary'); + btn.classList.remove('mr-is-success-action', 'mr-btn-primary'); btn.textContent = 'Starting...'; if (progressDiv) { - progressDiv.classList.remove('ml-is-hidden'); - progressDiv.classList.add('ml-is-visible'); + progressDiv.classList.remove('mr-is-hidden'); + progressDiv.classList.add('mr-is-visible'); // Show progress bar with cancel button immediately progressDiv.innerHTML = this.renderProgressWithAction({ percent: 0, - leftText: 'Connecting...', + leftText: 'Connecting...', rightText: '', - actionClass: 'cancel-download-btn-pending ml-btn ml-btn-danger ml-btn-sm', + actionClass: 'cancel-download-btn-pending mr-btn mr-btn-danger mr-btn-sm', actionText: 'Cancel' }); } - const response = await api.fetchApi('/model_linker/download', { + const response = await api.fetchApi('/model_resolver/download', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ @@ -1426,12 +1426,12 @@ export const resolveDownloadMethods = { this.pollDownloadProgress(downloadId); } catch (error) { - console.error('Model Linker: Download error:', error); + console.error('Model Resolver: Download error:', error); if (progressDiv) { progressDiv.innerHTML = this.renderStatusMessage(error.message, 'error'); } btn.disabled = false; - btn.classList.remove('ml-is-success-action', 'ml-btn-primary'); + btn.classList.remove('mr-is-success-action', 'mr-btn-primary'); btn.textContent = 'Retry'; this.showNotification('Download failed: ' + error.message, 'error'); } diff --git a/web/linker/actions/selection_methods.js b/web/resolver/actions/selection_methods.js similarity index 96% rename from web/linker/actions/selection_methods.js rename to web/resolver/actions/selection_methods.js index 6e9d4d4..ab2b552 100644 --- a/web/linker/actions/selection_methods.js +++ b/web/resolver/actions/selection_methods.js @@ -1,4 +1,4 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; @@ -15,7 +15,7 @@ export const selectionMethods = { handleFooterMenuOutsideClick(e) { if (!this.activeFooterMenu) return; - if (e.target?.closest?.('.ml-footer-menu-wrap')) return; + if (e.target?.closest?.('.mr-footer-menu-wrap')) return; this.closeFooterMenus(); }, @@ -166,11 +166,11 @@ export const selectionMethods = { refreshBatchSelectionUi() { const selectedKeys = this.batchSelectedMissingKeys || new Set(); - this.contentElement?.querySelectorAll?.('.ml-missing-list-row')?.forEach(row => { + this.contentElement?.querySelectorAll?.('.mr-missing-list-row')?.forEach(row => { const key = row.getAttribute('data-missing-key'); const selected = selectedKeys.has(key); row.classList.toggle('is-batch-selected', selected); - const checkbox = row.querySelector('.ml-missing-row-check'); + const checkbox = row.querySelector('.mr-missing-row-check'); if (checkbox) { checkbox.checked = selected; } @@ -179,7 +179,7 @@ export const selectionMethods = { }, updateBatchSelectAllCheckbox() { - const checkbox = this.contentElement?.querySelector?.('.ml-missing-select-all-check'); + const checkbox = this.contentElement?.querySelector?.('.mr-missing-select-all-check'); if (!checkbox) return; const totalCount = (this.missingModels || []).length; diff --git a/web/linker/globals.js b/web/resolver/globals.js similarity index 83% rename from web/linker/globals.js rename to web/resolver/globals.js index 235e185..fad295d 100644 --- a/web/linker/globals.js +++ b/web/resolver/globals.js @@ -1,14 +1,14 @@ -export function registerGlobalHelpers() { +export function registerGlobalHelpers() { // Global helper functions for inline onclick handlers window.MLToggleHidden = function(id, trigger, collapsedText, expandedText) { const element = document.getElementById(id); if (!element) return; - const isHidden = element.classList.toggle('ml-hidden'); + const isHidden = element.classList.toggle('mr-hidden'); if (trigger) { trigger.setAttribute('aria-expanded', String(!isHidden)); - const label = trigger.querySelector?.('.ml-local-alternatives-label'); - const state = trigger.querySelector?.('.ml-local-alternatives-state'); + const label = trigger.querySelector?.('.mr-local-alternatives-label'); + const state = trigger.querySelector?.('.mr-local-alternatives-state'); if (label || state) { if (label) label.textContent = isHidden ? collapsedText : expandedText; if (state) state.textContent = isHidden ? 'Show' : 'Hide'; @@ -23,9 +23,9 @@ export function registerGlobalHelpers() { if (!section) return; const normalizedMode = ['all', 'active', 'inactive'].includes(mode) ? mode : 'all'; - const codeEl = section.querySelector('.ml-copy-code'); - const labelEl = section.querySelector('.ml-copy-label'); - const metaEl = section.querySelector('.ml-copy-meta'); + const codeEl = section.querySelector('.mr-copy-code'); + const labelEl = section.querySelector('.mr-copy-label'); + const metaEl = section.querySelector('.mr-copy-meta'); const dataKey = normalizedMode === 'all' ? 'mlAll' : normalizedMode === 'active' ? 'mlActive' : 'mlInactive'; const countKey = normalizedMode === 'all' ? 'mlAllCount' : normalizedMode === 'active' ? 'mlActiveCount' : 'mlInactiveCount'; const labelMap = { @@ -41,7 +41,7 @@ export function registerGlobalHelpers() { metaEl.textContent = `${count} token${count === 1 ? '' : 's'}`; } - section.querySelectorAll('.ml-copy-mode').forEach(btn => { + section.querySelectorAll('.mr-copy-mode').forEach(btn => { btn.classList.toggle('active', btn.dataset.mlCopyMode === normalizedMode); }); }; @@ -61,16 +61,16 @@ export function registerGlobalHelpers() { if (!filterBtn) return; // Update button states - document.querySelectorAll('.ml-btn-filter').forEach(b => b.classList.remove('active')); + document.querySelectorAll('.mr-btn-filter').forEach(b => b.classList.remove('active')); filterBtn.classList.add('active'); // Filter model sections - document.querySelectorAll('.ml-model-section').forEach(s => { + document.querySelectorAll('.mr-model-section').forEach(s => { const hasActive = s.getAttribute('data-ml-active') === 'true'; const hasInactive = s.getAttribute('data-ml-inactive') === 'true'; - const activeSection = s.querySelector('.ml-model-group-active'); - const inactiveSection = s.querySelector('.ml-model-group-inactive'); + const activeSection = s.querySelector('.mr-model-group-active'); + const inactiveSection = s.querySelector('.mr-model-group-inactive'); if (filter === 'all') { s.style.display = 'block'; @@ -87,7 +87,7 @@ export function registerGlobalHelpers() { } }); - const copySection = document.querySelector('[id^="ml-copy-"]'); + const copySection = document.querySelector('[id^="mr-copy-"]'); if (copySection) { window.MLSetCopyMode(copySection.id, filter); } @@ -118,12 +118,12 @@ export function registerGlobalHelpers() { const model = JSON.parse(decodeURIComponent(modelData)); // Get dialog instance - const dialog = window.modelLinkerDialog; + const dialog = window.ModelResolverDialog; if (dialog && dialog.showContextMenu) { dialog.showContextMenu(event.clientX, event.clientY, model); } } catch (e) { - console.error('Model Linker: Error opening context menu:', e); + console.error('Model Resolver: Error opening context menu:', e); } }; } diff --git a/web/linker/model_linker.js b/web/resolver/model_resolver.js similarity index 77% rename from web/linker/model_linker.js rename to web/resolver/model_resolver.js index 5290093..73db7c2 100644 --- a/web/linker/model_linker.js +++ b/web/resolver/model_resolver.js @@ -1,18 +1,18 @@ -import { app } from "../../../../scripts/app.js"; +import { app } from "../../../../scripts/app.js"; import { api } from "../../../../scripts/api.js"; import { $el } from "../../../../scripts/ui.js"; import { loadStylesWhenNeeded } from "../utils/css_loader.js"; -import { LinkerManagerDialog } from "./linker_dialog.js"; +import { ResolverManagerDialog } from "./resolver_dialog.js"; // Main extension class -export class ModelLinker { +export class ModelResolver { constructor() { - this.linkerButton = null; + this.resolverButton = null; this.buttonGroup = null; - this.buttonId = "model-linker-button"; - this.sidebarTabId = "comfyui-model-linker"; + this.buttonId = "model-resolver-button"; + this.sidebarTabId = "comfyui-model-resolver"; this.sidebarRegistered = false; - this.openTooltip = "Open Model Linker to find or download missing workflow models. Shortcut: Ctrl+Shift+L."; + this.openTooltip = "Open Model Resolver to find or download missing workflow models. Shortcut: Ctrl+Shift+L."; this.dialog = null; this.isCheckingMissing = false; // Prevent multiple simultaneous checks this.lastCheckedWorkflow = null; // Track to avoid duplicate checks @@ -26,15 +26,15 @@ export class ModelLinker { // Create dialog instance if (!this.dialog) { - this.dialog = new LinkerManagerDialog(); - window.modelLinkerDialog = this.dialog; + this.dialog = new ResolverManagerDialog(); + window.ModelResolverDialog = this.dialog; } // Register keyboard shortcut (Ctrl+Shift+L) document.addEventListener('keydown', (e) => { if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === 'l') { e.preventDefault(); - this.openLinkerManager(); + this.openResolverManager(); } }); @@ -56,7 +56,7 @@ export class ModelLinker { return false; } - if (this.sidebarRegistered || window.__modelLinkerSidebarRegistered) { + if (this.sidebarRegistered || window.__ModelResolverSidebarRegistered) { this.sidebarRegistered = true; return true; } @@ -65,29 +65,29 @@ export class ModelLinker { registerSidebarTab.call(app.extensionManager, { id: this.sidebarTabId, icon: "mdi mdi-link-variant", - title: "Model Linker", + title: "Model Resolver", tooltip: this.openTooltip, type: "custom", render: (element) => this.renderSidebarPanel(element), }); this.sidebarRegistered = true; - window.__modelLinkerSidebarRegistered = true; + window.__ModelResolverSidebarRegistered = true; return true; } catch (error) { - console.warn("Model Linker: Sidebar tab registration failed, falling back to top menu button.", error); + console.warn("Model Resolver: Sidebar tab registration failed, falling back to top menu button.", error); return false; } } attachSidebarButtonToggleHandler() { - window.__modelLinkerSidebarToggleOwner = this; - if (window.__modelLinkerSidebarToggleHandlerAttached) return; + window.__ModelResolverSidebarToggleOwner = this; + if (window.__ModelResolverSidebarToggleHandlerAttached) return; - window.__modelLinkerSidebarToggleHandlerAttached = true; - window.__modelLinkerSidebarToggleHandler = (event) => { - window.__modelLinkerSidebarToggleOwner?.handleSidebarButtonClick(event); + window.__ModelResolverSidebarToggleHandlerAttached = true; + window.__ModelResolverSidebarToggleHandler = (event) => { + window.__ModelResolverSidebarToggleOwner?.handleSidebarButtonClick(event); }; - document.addEventListener('click', window.__modelLinkerSidebarToggleHandler, true); + document.addEventListener('click', window.__ModelResolverSidebarToggleHandler, true); } handleSidebarButtonClick(event) { @@ -127,11 +127,11 @@ export class ModelLinker { renderSidebarPanel(element) { element.style.height = "100%"; - element.classList.add("ml-sidebar-dock-panel"); + element.classList.add("mr-sidebar-dock-panel"); if (!this.dialog) { - this.dialog = new LinkerManagerDialog(); - window.modelLinkerDialog = this.dialog; + this.dialog = new ResolverManagerDialog(); + window.ModelResolverDialog = this.dialog; } if (this.dialog.shouldOpenFromSidebarFloating()) { @@ -141,7 +141,7 @@ export class ModelLinker { return; } - this.openLinkerManager({ + this.openResolverManager({ forceFloating: true, closeSidebarContainer: element, }); @@ -149,7 +149,7 @@ export class ModelLinker { } element.replaceChildren(); - this.openLinkerManager({ dockContainer: element }); + this.openResolverManager({ dockContainer: element }); } async registerTopbarButton() { @@ -159,24 +159,24 @@ export class ModelLinker { const { ComfyButtonGroup } = await import("../../../../scripts/ui/components/buttonGroup.js"); const { ComfyButton } = await import("../../../../scripts/ui/components/button.js"); - // Create button group with Model Linker button - const modelLinkerButton = new ComfyButton({ + // Create button group with Model Resolver button + const ModelResolverButton = new ComfyButton({ icon: "link-variant", - action: () => this.openLinkerManager(), - content: "Model Linker", + action: () => this.openResolverManager(), + content: "Model Resolver", classList: "comfyui-button comfyui-menu-mobile-collapse" }).element; - modelLinkerButton.id = this.buttonId; - this.dialog.setTooltip(modelLinkerButton, this.openTooltip); + ModelResolverButton.id = this.buttonId; + this.dialog.setTooltip(ModelResolverButton, this.openTooltip); this.buttonGroup = new ComfyButtonGroup( - modelLinkerButton + ModelResolverButton ); // Insert before settings group in the menu app.menu?.settingsGroup.element.before(this.buttonGroup.element); } catch (e) { // Fallback for older ComfyUI versions without the new button system - console.log('Model Linker: New button system not available, using floating button fallback.'); + console.log('Model Resolver: New button system not available, using floating button fallback.'); this.createFloatingButton(); } } @@ -188,56 +188,56 @@ export class ModelLinker { // Watch for ComfyUI's Missing Models popup and inject our button this.setupMissingModelsPopupObserver(); - console.log('Model Linker: Missing models popup button injection enabled'); + console.log('Model Resolver: Missing models popup button injection enabled'); } setupActiveWorkflowChangeListeners() { - if (window.__modelLinkerWorkflowChangeHandlers) { - for (const { target, event, handler } of window.__modelLinkerWorkflowChangeHandlers) { + if (window.__ModelResolverWorkflowChangeHandlers) { + for (const { target, event, handler } of window.__ModelResolverWorkflowChangeHandlers) { target?.removeEventListener?.(event, handler); } } - if (!window.__modelLinkerHistoryPatched) { + if (!window.__ModelResolverHistoryPatched) { const originalPushState = history.pushState; const originalReplaceState = history.replaceState; history.pushState = function(...args) { const result = originalPushState.apply(this, args); - window.dispatchEvent(new Event('model-linker-locationchange')); + window.dispatchEvent(new Event('model-resolver-locationchange')); return result; }; history.replaceState = function(...args) { const result = originalReplaceState.apply(this, args); - window.dispatchEvent(new Event('model-linker-locationchange')); + window.dispatchEvent(new Event('model-resolver-locationchange')); return result; }; - window.__modelLinkerHistoryPatched = true; + window.__ModelResolverHistoryPatched = true; } - window.__modelLinkerWorkflowChangeOwner = this; + window.__ModelResolverWorkflowChangeOwner = this; const routeHandler = () => { - window.__modelLinkerWorkflowChangeOwner?.handleActiveWorkflowRouteChange('route-change'); + window.__ModelResolverWorkflowChangeOwner?.handleActiveWorkflowRouteChange('route-change'); }; const focusHandler = () => { - window.__modelLinkerWorkflowChangeOwner?.handleActiveWorkflowRouteChange('window-focus'); + window.__ModelResolverWorkflowChangeOwner?.handleActiveWorkflowRouteChange('window-focus'); }; const visibilityHandler = () => { if (document.visibilityState === 'visible') { - window.__modelLinkerWorkflowChangeOwner?.handleActiveWorkflowRouteChange('visibility-change'); + window.__ModelResolverWorkflowChangeOwner?.handleActiveWorkflowRouteChange('visibility-change'); } }; window.addEventListener('hashchange', routeHandler); window.addEventListener('popstate', routeHandler); - window.addEventListener('model-linker-locationchange', routeHandler); + window.addEventListener('model-resolver-locationchange', routeHandler); window.addEventListener('focus', focusHandler); document.addEventListener('visibilitychange', visibilityHandler); - window.__modelLinkerWorkflowChangeHandlers = [ + window.__ModelResolverWorkflowChangeHandlers = [ { target: window, event: 'hashchange', handler: routeHandler }, { target: window, event: 'popstate', handler: routeHandler }, - { target: window, event: 'model-linker-locationchange', handler: routeHandler }, + { target: window, event: 'model-resolver-locationchange', handler: routeHandler }, { target: window, event: 'focus', handler: focusHandler }, { target: document, event: 'visibilitychange', handler: visibilityHandler } ]; @@ -294,16 +294,16 @@ export class ModelLinker { if (!dialog) return; // Check if we already injected buttons - if (dialog.querySelector('#model-linker-btn-container')) return; + if (dialog.querySelector('#model-resolver-btn-container')) return; // Find a suitable place to inject the button const injectButtons = () => { // Auto-resolve button (green) const autoResolveBtn = document.createElement('button'); - autoResolveBtn.id = 'model-linker-btn-container'; // Use this ID to prevent duplicate injection - autoResolveBtn.className = 'ml-popup-auto-resolve-btn'; + autoResolveBtn.id = 'model-resolver-btn-container'; // Use this ID to prevent duplicate injection + autoResolveBtn.className = 'mr-popup-auto-resolve-btn'; autoResolveBtn.textContent = '🔗 Auto-resolve 100%'; - this.dialog?.setTooltip(autoResolveBtn, 'Link every missing model that already has an exact local match, then open Model Linker for the rest.'); + this.dialog?.setTooltip(autoResolveBtn, 'Link every missing model that already has an exact local match, then open Model Resolver for the rest.'); autoResolveBtn.addEventListener('click', async () => { await this.handleAutoResolveInPopup(dialog, autoResolveBtn); }); @@ -314,7 +314,7 @@ export class ModelLinker { const checkboxRow = checkbox.closest('label') || checkbox.parentElement; if (checkboxRow && checkboxRow.parentElement) { // Make the parent a flex container to align checkbox and button - checkboxRow.parentElement.classList.add('ml-popup-inline-actions'); + checkboxRow.parentElement.classList.add('mr-popup-inline-actions'); // Insert button at the beginning (left side) checkboxRow.parentElement.insertBefore(autoResolveBtn, checkboxRow); return; @@ -329,7 +329,7 @@ export class ModelLinker { if (modelList) { // Create a wrapper and insert before the model list const wrapper = document.createElement('div'); - wrapper.className = 'ml-popup-actions-wrap'; + wrapper.className = 'mr-popup-actions-wrap'; wrapper.appendChild(autoResolveBtn); modelList.parentElement?.insertBefore(wrapper, modelList); } else { @@ -344,7 +344,7 @@ export class ModelLinker { } } - console.log('Model Linker: Injected buttons into Missing Models popup'); + console.log('Model Resolver: Injected buttons into Missing Models popup'); }; // Small delay to ensure popup is fully rendered @@ -352,7 +352,7 @@ export class ModelLinker { } /** - * Handle auto-resolve in the popup - resolve 100% matches and open Model Linker for remaining + * Handle auto-resolve in the popup - resolve 100% matches and open Model Resolver for remaining */ async handleAutoResolveInPopup(dialog, button) { button.textContent = '⏳ Resolving...'; @@ -373,14 +373,14 @@ export class ModelLinker { // Create dialog if needed if (!this.dialog) { - this.dialog = new LinkerManagerDialog(); - window.modelLinkerDialog = this.dialog; + this.dialog = new ResolverManagerDialog(); + window.ModelResolverDialog = this.dialog; } // Run auto-resolve for 100% matches - returns the updated workflow const updatedWorkflow = await this.dialog.autoResolve100Percent(); - // Always open Model Linker to show remaining unresolved models + // Always open Model Resolver to show remaining unresolved models // Pass the updated workflow if available to avoid race condition this.dialog.show(updatedWorkflow || null); } @@ -389,7 +389,7 @@ export class ModelLinker { * Mark resolved model items in the popup as linked (green) and hide download buttons */ removeResolvedFromPopup(dialog, resolvedFilenames) { - console.log('Model Linker: Looking for resolved filenames:', resolvedFilenames); + console.log('Model Resolver: Looking for resolved filenames:', resolvedFilenames); // Strategy: For each filename, find text nodes containing it, // then find the nearest Download button and mark that row @@ -413,10 +413,10 @@ export class ModelLinker { // Look for Download button at this level const downloadBtn = Array.from(parent.querySelectorAll('button')) .find(btn => btn.textContent?.includes('Download') && - !btn.id?.includes('model-linker')); + !btn.id?.includes('model-resolver')); if (downloadBtn) { - console.log('Model Linker: Found entry for', filename); + console.log('Model Resolver: Found entry for', filename); this.markEntryAsResolved(parent, downloadBtn); break; } @@ -440,16 +440,16 @@ export class ModelLinker { if (container.dataset.resolved === 'true') return; container.dataset.resolved = 'true'; - console.log('Model Linker: Marking entry as resolved', container); + console.log('Model Resolver: Marking entry as resolved', container); // Add green background/styling to the container - container.classList.add('ml-resolved-entry'); + container.classList.add('mr-resolved-entry'); // Hide the Download button and replace with badge if (downloadBtn) { // Create badge const badge = document.createElement('span'); - badge.className = 'ml-resolved-badge'; + badge.className = 'mr-resolved-badge'; badge.textContent = '✓ Linked'; // Replace download button with badge @@ -474,7 +474,7 @@ export class ModelLinker { const downloadButtons = dialog.querySelectorAll('button'); let count = 0; for (const btn of downloadButtons) { - if (btn.textContent?.includes('Download') && !btn.id?.includes('model-linker')) { + if (btn.textContent?.includes('Download') && !btn.id?.includes('model-resolver')) { count++; } } @@ -487,7 +487,7 @@ export class ModelLinker { */ updateNodesDirectly(resolutions) { if (!app?.graph) { - console.warn('Model Linker: Cannot update nodes - graph not available'); + console.warn('Model Resolver: Cannot update nodes - graph not available'); return; } @@ -499,7 +499,7 @@ export class ModelLinker { // Find the node in the graph const node = app.graph.getNodeById(nodeId); if (!node) { - console.warn(`Model Linker: Node ${nodeId} not found in graph`); + console.warn(`Model Resolver: Node ${nodeId} not found in graph`); continue; } @@ -513,11 +513,11 @@ export class ModelLinker { widget.callback(resolvedPath, app.graph, node, null, null); } - console.log(`Model Linker: Updated node ${nodeId} widget ${widgetIndex} to ${resolvedPath}`); + console.log(`Model Resolver: Updated node ${nodeId} widget ${widgetIndex} to ${resolvedPath}`); } else if (node.widgets_values) { // Fallback: update widgets_values array directly node.widgets_values[widgetIndex] = resolvedPath; - console.log(`Model Linker: Updated node ${nodeId} widgets_values[${widgetIndex}] to ${resolvedPath}`); + console.log(`Model Resolver: Updated node ${nodeId} widgets_values[${widgetIndex}] to ${resolvedPath}`); } // Mark node as dirty to trigger redraw @@ -536,14 +536,14 @@ export class ModelLinker { * Check if auto-open is enabled in user settings */ isAutoOpenEnabled() { - return localStorage.getItem('modelLinker.autoOpenOnMissing') !== 'false'; + return localStorage.getItem('ModelResolver.autoOpenOnMissing') !== 'false'; } /** * Set auto-open preference */ setAutoOpenEnabled(enabled) { - localStorage.setItem('modelLinker.autoOpenOnMissing', enabled ? 'true' : 'false'); + localStorage.setItem('ModelResolver.autoOpenOnMissing', enabled ? 'true' : 'false'); } /** @@ -582,14 +582,14 @@ export class ModelLinker { this.lastCheckedWorkflow = workflowHash; // Call analyze endpoint to check for missing models - const response = await api.fetchApi('/model_linker/analyze', { + const response = await api.fetchApi('/model_resolver/analyze', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workflow }) }); if (!response.ok) { - console.warn('Model Linker: Failed to analyze workflow for missing models'); + console.warn('Model Resolver: Failed to analyze workflow for missing models'); return; } @@ -597,12 +597,12 @@ export class ModelLinker { // Auto-open dialog if there are missing models if (data.total_missing > 0) { - console.log(`Model Linker: Found ${data.total_missing} missing model(s), opening dialog...`); - this.openLinkerManager(); + console.log(`Model Resolver: Found ${data.total_missing} missing model(s), opening dialog...`); + this.openResolverManager(); } } catch (error) { - console.error('Model Linker: Error checking for missing models:', error); + console.error('Model Resolver: Error checking for missing models:', error); } finally { this.isCheckingMissing = false; } @@ -617,7 +617,7 @@ export class ModelLinker { document.querySelectorAll('.comfyui-button-group button.comfyui-button').forEach((button) => { const label = button.querySelector('span')?.textContent?.trim() || button.textContent?.trim(); - if (label === 'Model Linker') { + if (label === 'Model Resolver') { button.closest('.comfyui-button-group')?.remove(); } }); @@ -629,32 +629,32 @@ export class ModelLinker { } // Also remove the stored reference if it exists - if (this.linkerButton && this.linkerButton.parentNode) { - this.linkerButton.remove(); - this.linkerButton = null; + if (this.resolverButton && this.resolverButton.parentNode) { + this.resolverButton.remove(); + this.resolverButton = null; } } createFloatingButton() { // Create a floating button as fallback for legacy ComfyUI versions - this.linkerButton = $el("button", { + this.resolverButton = $el("button", { id: this.buttonId, - textContent: "🔗 Model Linker", + textContent: "🔗 Model Resolver", onclick: () => { - this.openLinkerManager(); + this.openResolverManager(); }, - className: "model-linker-floating-button" + className: "model-resolver-floating-button" }); - document.body.appendChild(this.linkerButton); - this.dialog?.setTooltip(this.linkerButton, "Open Model Linker to find or download missing workflow models. Shortcut: Ctrl+Shift+L."); + document.body.appendChild(this.resolverButton); + this.dialog?.setTooltip(this.resolverButton, "Open Model Resolver to find or download missing workflow models. Shortcut: Ctrl+Shift+L."); } - async openLinkerManager(options = {}) { + async openResolverManager(options = {}) { try { if (!this.dialog) { - this.dialog = new LinkerManagerDialog(); - window.modelLinkerDialog = this.dialog; + this.dialog = new ResolverManagerDialog(); + window.ModelResolverDialog = this.dialog; } if (options.dockContainer && !options.forceFloating) { await this.dialog.showDocked(options.dockContainer, options.workflow || null); @@ -670,16 +670,16 @@ export class ModelLinker { await showPromise; } catch (error) { - console.error("🔗 Model Linker: Error creating/showing dialog:", error); - alert("Error opening Model Linker: " + error.message); + console.error("🔗 Model Resolver: Error creating/showing dialog:", error); + alert("Error opening Model Resolver: " + error.message); } } static switchFilter(filter) { - document.querySelectorAll('.ml-btn-filter').forEach(b => b.classList.remove('active')); + document.querySelectorAll('.mr-btn-filter').forEach(b => b.classList.remove('active')); document.getElementById('filter-' + filter).classList.add('active'); - document.querySelectorAll('.ml-model-section').forEach(s => { + document.querySelectorAll('.mr-model-section').forEach(s => { const hasActive = s.dataset.mlActive === 'true'; const hasInactive = s.dataset.mlInactive === 'true'; @@ -692,7 +692,7 @@ export class ModelLinker { } }); - const copySection = document.querySelector('[id^="ml-copy-"]'); + const copySection = document.querySelector('[id^="mr-copy-"]'); if (copySection) { const codeEl = copySection.querySelector('code'); const labelEl = copySection.querySelector('div'); diff --git a/web/linker/linker_dialog.js b/web/resolver/resolver_dialog.js similarity index 83% rename from web/linker/linker_dialog.js rename to web/resolver/resolver_dialog.js index 7bf9570..5ab15e3 100644 --- a/web/linker/linker_dialog.js +++ b/web/resolver/resolver_dialog.js @@ -1,4 +1,4 @@ -import { $el, ComfyDialog } from "../../../../scripts/ui.js"; +import { $el, ComfyDialog } from "../../../../scripts/ui.js"; import { dialogShellMethods } from "./shell/dialog_shell_methods.js"; import { lifecycleGraphMethods } from "./shell/lifecycle_graph_methods.js"; import { workflowStateMethods } from "./shell/workflow_state_methods.js"; @@ -13,7 +13,7 @@ import { queueMethods } from "./actions/queue_methods.js"; import { resolveDownloadMethods } from "./actions/resolve_download_methods.js"; import { selectionMethods } from "./actions/selection_methods.js"; import { renderFormatMethods } from "./utils/render_format_methods.js"; -export class LinkerManagerDialog extends ComfyDialog { +export class ResolverManagerDialog extends ComfyDialog { constructor() { super(); this.currentWorkflow = null; @@ -39,7 +39,7 @@ export class LinkerManagerDialog extends ComfyDialog { this.activeFooterMenu = null; this.batchSearchRunning = false; this.boundHandleOutsideClick = this.handleOutsideClick.bind(this); - this.activeTabStorageKey = 'model_linker_active_tab'; + this.activeTabStorageKey = 'model_resolver_active_tab'; this.activeTab = this.restoreActiveTab(); // Default tab this.fullscreen = false; this.returnToDockedAfterFullscreen = false; @@ -47,9 +47,9 @@ export class LinkerManagerDialog extends ComfyDialog { this.dockContainer = null; this.lastDockContainer = null; this.pendingDockToSidebar = false; - this.sidebarTabId = "comfyui-model-linker"; - this.sidebarOpenModeStorageKey = "model_linker_sidebar_open_mode"; - this.missingBrowserSplitStorageKey = "model_linker_missing_browser_detail_w"; + this.sidebarTabId = "comfyui-model-resolver"; + this.sidebarOpenModeStorageKey = "model_resolver_sidebar_open_mode"; + this.missingBrowserSplitStorageKey = "model_resolver_missing_browser_detail_w"; this.dockButton = null; this.undockButton = null; this._floatingRectBeforeDock = null; @@ -66,44 +66,44 @@ export class LinkerManagerDialog extends ComfyDialog { this._boundHandleViewportResize = () => this.scheduleModalViewportClamp(true); // Create backdrop overlay for click-outside-to-close - this.backdrop = $el("div.model-linker-backdrop", { + this.backdrop = $el("div.model-resolver-backdrop", { parent: document.body }); // Create context menu for model chips - this.contextMenu = $el("div.ml-context-menu", { + this.contextMenu = $el("div.mr-context-menu", { parent: document.body }, [ - $el("div.ml-context-menu-item", { + $el("div.mr-context-menu-item", { onclick: () => this.handleContextMenuAction('showInfo') }, [ - $el("span.ml-context-menu-item-icon", { textContent: "ℹ" }), + $el("span.mr-context-menu-item-icon", { textContent: "ℹ" }), $el("span", { textContent: "Show Info" }) ]), - $el("div.ml-context-menu-divider"), - $el("div.ml-context-menu-item", { + $el("div.mr-context-menu-divider"), + $el("div.mr-context-menu-item", { onclick: () => this.handleContextMenuAction('civitai') }, [ - $el("span.ml-context-menu-item-icon", { textContent: "🌐" }), + $el("span.mr-context-menu-item-icon", { textContent: "🌐" }), $el("span", { textContent: "Open in CivitAI" }) ]), - $el("div.ml-context-menu-divider"), - $el("div.ml-context-menu-item", { + $el("div.mr-context-menu-divider"), + $el("div.mr-context-menu-item", { onclick: () => this.handleContextMenuAction('openFolder') }, [ - $el("span.ml-context-menu-item-icon", { textContent: "📁" }), + $el("span.mr-context-menu-item-icon", { textContent: "📁" }), $el("span", { textContent: "Open Containing Folder" }) ]) ]); - this.tooltipElement = $el("div.ml-global-tooltip", { parent: document.body }); + this.tooltipElement = $el("div.mr-global-tooltip", { parent: document.body }); // Selected model for context menu this._contextMenuModel = null; // Create dialog element using $el - this.element = $el("div.comfy-modal.model-linker-modal", { - id: "model-linker-modal", + this.element = $el("div.comfy-modal.model-resolver-modal", { + id: "model-resolver-modal", parent: document.body }, [ this.createHeader(), @@ -140,7 +140,7 @@ function applyDialogMethods(...sources) { for (const key of Reflect.ownKeys(source)) { const descriptor = Object.getOwnPropertyDescriptor(source, key); descriptor.enumerable = false; - Object.defineProperty(LinkerManagerDialog.prototype, key, descriptor); + Object.defineProperty(ResolverManagerDialog.prototype, key, descriptor); } } } diff --git a/web/linker/search/download_target_methods.js b/web/resolver/search/download_target_methods.js similarity index 87% rename from web/linker/search/download_target_methods.js rename to web/resolver/search/download_target_methods.js index 8d68b4a..2ad6ed2 100644 --- a/web/linker/search/download_target_methods.js +++ b/web/resolver/search/download_target_methods.js @@ -1,4 +1,4 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; @@ -9,7 +9,7 @@ export const downloadTargetMethods = { async ensureAllModelsLoaded() { if (this.allModels && this.allModels.length) return; try { - const resp = await api.fetchApi('/model_linker/models'); + const resp = await api.fetchApi('/model_resolver/models'); if (!resp.ok) throw new Error(`HTTP ${resp.status}`); const models = await resp.json(); const list = Array.isArray(models) ? models : []; @@ -19,7 +19,7 @@ export const downloadTargetMethods = { __label: `${m.category ? m.category + ': ' : ''}${m.relative_path || m.filename || ''}` })).sort((a, b) => (a.__label || '').localeCompare(b.__label || '')); } catch (e) { - console.warn('Model Linker: could not load all models', e); + console.warn('Model Resolver: could not load all models', e); this.allModels = []; } }, @@ -27,12 +27,12 @@ export const downloadTargetMethods = { async ensureDownloadDirectoriesLoaded() { if (this.downloadDirectories) return; try { - const resp = await api.fetchApi('/model_linker/directories'); + const resp = await api.fetchApi('/model_resolver/directories'); if (!resp.ok) throw new Error(`HTTP ${resp.status}`); const directories = await resp.json(); this.downloadDirectories = directories && typeof directories === 'object' ? directories : {}; } catch (e) { - console.warn('Model Linker: could not load download directories', e); + console.warn('Model Resolver: could not load download directories', e); this.downloadDirectories = {}; } }, @@ -40,12 +40,12 @@ export const downloadTargetMethods = { async ensureCapabilitiesLoaded() { if (this.capabilities) return; try { - const resp = await api.fetchApi('/model_linker/capabilities'); + const resp = await api.fetchApi('/model_resolver/capabilities'); if (!resp.ok) throw new Error(`HTTP ${resp.status}`); const data = await resp.json(); this.capabilities = data && typeof data === 'object' ? data : { sources: {} }; } catch (e) { - console.warn('Model Linker: could not load capabilities', e); + console.warn('Model Resolver: could not load capabilities', e); this.capabilities = { sources: {} }; } }, @@ -141,7 +141,7 @@ export const downloadTargetMethods = { guider: 'guider', guiders: 'guider' }; - return `ml-type-chip ml-type-chip--${colorNames[token] || 'generic'}`; + return `mr-type-chip mr-type-chip--${colorNames[token] || 'generic'}`; }, getCategoryTokenName(category = '') { @@ -282,14 +282,14 @@ export const downloadTargetMethods = { } try { - const resp = await api.fetchApi(`/model_linker/subfolders/${encodeURIComponent(key)}`); + const resp = await api.fetchApi(`/model_resolver/subfolders/${encodeURIComponent(key)}`); if (!resp.ok) throw new Error(`HTTP ${resp.status}`); const subfolders = await resp.json(); const list = Array.isArray(subfolders) ? subfolders : []; this.downloadSubfolders.set(key, list); return list; } catch (e) { - console.warn(`Model Linker: could not load subfolders for ${key}`, e); + console.warn(`Model Resolver: could not load subfolders for ${key}`, e); this.downloadSubfolders.set(key, []); return []; } @@ -302,17 +302,17 @@ export const downloadTargetMethods = { const subfolderListId = `download-subfolder-list-${missing.node_id}-${missing.widget_index}`; const selectedCategory = defaultCategory || 'checkpoints'; - let html = `
`; - html += `
`; - html += ``; - html += ``; - html += `
`; - html += ``; - html += `
`; + let html = `
`; + html += `
`; + html += ``; + html += ``; + html += `
`; + html += ``; + html += `
`; html += `
`; - html += `
`; - html += ``; - html += `
`; + html += `
`; + html += ``; + html += `
`; html += `
`; html += `
`; html += `
`; @@ -384,13 +384,13 @@ export const downloadTargetMethods = { .map(option => { const value = String(option.value || ''); const label = String(option.label || value); - return `
${this.escapeHtml(label)}
`; + return `
${this.escapeHtml(label)}
`; }) .join(''); targetEl.style.display = 'block'; - targetEl.querySelectorAll('.ml-download-target-option').forEach(option => { + targetEl.querySelectorAll('.mr-download-target-option').forEach(option => { option.addEventListener('mousedown', (event) => { event.preventDefault(); const value = decodeURIComponent(option.dataset.value || ''); @@ -463,22 +463,22 @@ export const downloadTargetMethods = { }, getStoredTokens() { - const civitaiCandidateLimitRaw = parseInt(localStorage.getItem('modelLinker.civitaiCandidateLimit') || '5', 10); + const civitaiCandidateLimitRaw = parseInt(localStorage.getItem('ModelResolver.civitaiCandidateLimit') || '5', 10); const civitai_candidate_limit = Number.isFinite(civitaiCandidateLimitRaw) ? Math.min(20, Math.max(1, civitaiCandidateLimitRaw)) : 5; const search_source_enabled = this.getSearchSourceEnabledMap(); return { - civitai_key: localStorage.getItem('modelLinker.civitaiApiKey') || '', - civitai_session_token: localStorage.getItem('modelLinker.civitaiSessionToken') || '', - hf_token: localStorage.getItem('modelLinker.huggingFaceToken') || '', - brave_search_api_key: localStorage.getItem('modelLinker.braveSearchApiKey') || '', - civitai_use_trpc_search: localStorage.getItem('modelLinker.civitaiUseTrpcSearch') !== 'false', - civitai_use_html_fallback: localStorage.getItem('modelLinker.civitaiUseHtmlFallback') !== 'false', - hf_use_api_search: localStorage.getItem('modelLinker.hfUseApiSearch') !== 'false', - hf_use_comfy_org_fallback: localStorage.getItem('modelLinker.hfUseComfyOrgFallback') !== 'false', - hf_use_brave_fallback: localStorage.getItem('modelLinker.hfUseBraveFallback') !== 'false', + civitai_key: localStorage.getItem('ModelResolver.civitaiApiKey') || '', + civitai_session_token: localStorage.getItem('ModelResolver.civitaiSessionToken') || '', + hf_token: localStorage.getItem('ModelResolver.huggingFaceToken') || '', + brave_search_api_key: localStorage.getItem('ModelResolver.braveSearchApiKey') || '', + civitai_use_trpc_search: localStorage.getItem('ModelResolver.civitaiUseTrpcSearch') !== 'false', + civitai_use_html_fallback: localStorage.getItem('ModelResolver.civitaiUseHtmlFallback') !== 'false', + hf_use_api_search: localStorage.getItem('ModelResolver.hfUseApiSearch') !== 'false', + hf_use_comfy_org_fallback: localStorage.getItem('ModelResolver.hfUseComfyOrgFallback') !== 'false', + hf_use_brave_fallback: localStorage.getItem('ModelResolver.hfUseBraveFallback') !== 'false', civitai_candidate_limit, search_source_enabled }; @@ -495,14 +495,14 @@ export const downloadTargetMethods = { this.workflowSearchResultCaches.delete(key); } try { - const response = await api.fetchApi('/model_linker/clear-search-cache', { + const response = await api.fetchApi('/model_resolver/clear-search-cache', { method: 'POST' }); if (!response.ok) { throw new Error('Failed to clear backend search cache'); } } catch (error) { - console.error('Model Linker: Clear search cache error:', error); + console.error('Model Resolver: Clear search cache error:', error); } } }; diff --git a/web/linker/search/search_panel.js b/web/resolver/search/search_panel.js similarity index 88% rename from web/linker/search/search_panel.js rename to web/resolver/search/search_panel.js index 504d0e2..dfd652d 100644 --- a/web/linker/search/search_panel.js +++ b/web/resolver/search/search_panel.js @@ -1,4 +1,4 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; @@ -57,11 +57,11 @@ export const searchPanelMethods = { }, getSearchIconHtml() { - return ``; + return ``; }, getLocateIconHtml() { - return ``; + return ``; }, showTooltip(target) { @@ -107,7 +107,7 @@ export const searchPanelMethods = { if (target.hasAttribute('title')) { target.removeAttribute('title'); } - if (target.classList?.contains('ml-tooltip-badge') && !target.hasAttribute('tabindex')) { + if (target.classList?.contains('mr-tooltip-badge') && !target.hasAttribute('tabindex')) { target.setAttribute('tabindex', '0'); } }, @@ -153,7 +153,7 @@ export const searchPanelMethods = { try { return this.getValidTab(localStorage.getItem(this.activeTabStorageKey)); } catch (error) { - console.warn('Model Linker: Failed to restore active tab:', error); + console.warn('Model Resolver: Failed to restore active tab:', error); return 'missing'; } }, @@ -162,7 +162,7 @@ export const searchPanelMethods = { try { localStorage.setItem(this.activeTabStorageKey, this.getValidTab(tab)); } catch (error) { - console.warn('Model Linker: Failed to persist active tab:', error); + console.warn('Model Resolver: Failed to persist active tab:', error); } }, @@ -192,27 +192,27 @@ export const searchPanelMethods = { return [ { source: 'local', - storageKey: 'modelLinker.searchSource.localEnabled', + storageKey: 'ModelResolver.searchSource.localEnabled', tooltip: 'Searches bundled known-model data before online providers.' }, { source: 'huggingface', - storageKey: 'modelLinker.searchSource.huggingFaceEnabled', + storageKey: 'ModelResolver.searchSource.huggingFaceEnabled', tooltip: 'Searches Hugging Face when Everything is selected.' }, { source: 'civitai', - storageKey: 'modelLinker.searchSource.civitaiEnabled', + storageKey: 'ModelResolver.searchSource.civitaiEnabled', tooltip: 'Searches CivitAI when Everything is selected.' }, { source: 'civarchive', - storageKey: 'modelLinker.searchSource.civArchiveEnabled', + storageKey: 'ModelResolver.searchSource.civArchiveEnabled', tooltip: 'Searches CivArchive when Everything is selected.' }, { source: 'lora_manager_archive', - storageKey: 'modelLinker.searchSource.loraManagerArchiveEnabled', + storageKey: 'ModelResolver.searchSource.loraManagerArchiveEnabled', tooltip: 'Searches the local LoRA Manager archive when Everything is selected.' } ]; @@ -272,11 +272,11 @@ export const searchPanelMethods = { if (!this.contentElement || !missing) return; const key = this.getMissingModelKey(missing); - const rows = this.contentElement.querySelectorAll('.ml-missing-list-row'); + const rows = this.contentElement.querySelectorAll('.mr-missing-list-row'); for (const row of rows) { if (row.getAttribute('data-missing-key') !== key) continue; - const sourcesEl = row.querySelector('.ml-missing-row-sources'); + const sourcesEl = row.querySelector('.mr-missing-row-sources'); if (sourcesEl) { sourcesEl.innerHTML = this.renderMissingSourcesSummary(missing); } @@ -391,7 +391,7 @@ export const searchPanelMethods = { }; if (isCompact) { - let html = '
'; + let html = '
'; for (const [source, progress] of progressEntries) { const status = progress?.status || 'pending'; const statusClass = String(status).replace(/[^a-z0-9_-]/gi, ''); @@ -399,9 +399,9 @@ export const searchPanelMethods = { const statusLabel = progress?.message || statusLabels[status] || status; const title = `${label}: ${statusLabel}`; html += ` -
- ${this.escapeHtml(label)} - ${this.escapeHtml(statusLabel)} +
+ ${this.escapeHtml(label)} + ${this.escapeHtml(statusLabel)}
`; } @@ -409,7 +409,7 @@ export const searchPanelMethods = { return html; } - let html = '
'; + let html = '
'; for (const [source, progress] of progressEntries) { const status = progress?.status || 'pending'; const statusClass = String(status).replace(/[^a-z0-9_-]/gi, ''); @@ -422,13 +422,13 @@ export const searchPanelMethods = { ? `Searching... ${Math.round(safePercent)}%` : (progress?.message || statusLabels[status] || status); html += ` -
-
+
+
${this.escapeHtml(label)} ${this.escapeHtml(statusLabel)}
-
-
+
+
`; @@ -500,7 +500,7 @@ export const searchPanelMethods = { const parts = this.getModelVersionParts(modelName, versionName); const nameHtml = parts.name ? this.escapeHtml(parts.name) : ''; const versionHtml = parts.version - ? `${this.escapeHtml(parts.version)}` + ? `${this.escapeHtml(parts.version)}` : ''; return [nameHtml, versionHtml].filter(Boolean).join(' '); }, @@ -525,9 +525,9 @@ export const searchPanelMethods = { renderSearchSourcePill(sourceKey, sourceLabel) { const iconName = this.getSearchSourceIconName(sourceKey); - const iconHtml = getSvgIcon(iconName, 'currentColor', 'ml-search-source-icon'); + const iconHtml = getSvgIcon(iconName, 'currentColor', 'mr-search-source-icon'); return ` - + ${iconHtml} ${this.escapeHtml(sourceLabel)} @@ -649,7 +649,7 @@ export const searchPanelMethods = { }, renderKnownDownloadPanel(missing, downloadSource) { - let html = `
`; + let html = `
`; html += this.renderSearchControls(missing, { buttonText: 'Search Again' }); html += this.renderDownloadTargetControls( missing, @@ -658,7 +658,7 @@ export const searchPanelMethods = { html += `
`; const downloadSourceRow = this.getDownloadSourceTableRow(missing, downloadSource); - html += `
`; + html += `
`; html += this.renderSearchResultsTable(downloadSourceRow ? [downloadSourceRow] : []); html += `
`; return html; @@ -668,22 +668,22 @@ export const searchPanelMethods = { if (!rows.length) return ''; const layout = this.getSearchResultsTableLayout(rows); const tableStyle = [ - `--ml-source-col:${layout.sourcePx}px`, - `--ml-match-col:${layout.matchPx}px`, - `--ml-size-col:${layout.sizePx}px`, - `--ml-actions-col:${layout.actionsPx}px`, - `--ml-table-min:${layout.tableMinPx}px` + `--mr-source-col:${layout.sourcePx}px`, + `--mr-match-col:${layout.matchPx}px`, + `--mr-size-col:${layout.sizePx}px`, + `--mr-actions-col:${layout.actionsPx}px`, + `--mr-table-min:${layout.tableMinPx}px` ].join(';'); let html = ` -
- +
+
- - - - - + + + + + @@ -719,7 +719,7 @@ export const searchPanelMethods = { let actions = ''; if (downloadUrl) { actions += ` - `; } if (!actions) { - actions = '-'; + actions = '-'; } html += ` - - - + + + `; } @@ -772,15 +772,15 @@ export const searchPanelMethods = { const state = this.getSearchState(missing); const selectedSource = state.selectedSource || 'all'; - let html = `
`; - html += ``; - html += `
`; - html += ``; - html += `
`; - html += ``; - html += `
`; + html += `
`; + html += ``; + html += `
`; + html += ``; + html += `
`; html += `
`; html += `
`; html += `
`; @@ -798,14 +798,14 @@ export const searchPanelMethods = { const safePercent = Math.max(0, Math.min(100, Number(percent) || 0)); const actionAttr = actionDataAttr ? ` ${actionDataAttr}` : ''; return ` -
-
-
-
+
+
+
+
-
+
${leftText} ${rightText}
@@ -853,11 +853,11 @@ export const searchPanelMethods = { const contextModel = this.buildContextMenuModelData(match.model || {}, match.filename || ''); const modelData = encodeURIComponent(JSON.stringify(contextModel)); - html += `
`; + html += `
`; html += this.getConfidenceBadge(match.confidence); - html += `${this.escapeHtml(matchPath)}`; - html += `${match.confidence === 100 ? 'Exact' : 'Partial'}`; - html += ``; html += `
`; @@ -866,33 +866,33 @@ export const searchPanelMethods = { if (perfectMatches.length > 0 && otherMatches.length > 0) { const matchId = `more-matches-${missing.node_id}-${missing.widget_index}`; const altLabel = `Alternatives (${otherMatches.length})`; - html += ``; - html += `
`; + html += `
`; for (let mIdx = 0; mIdx < otherMatches.length; mIdx++) { const match = otherMatches[mIdx]; const altBtnId = `resolve-alt-${missingIndex}-${missing.node_id}-${missing.widget_index}-${mIdx}`; const contextModel = this.buildContextMenuModelData(match.model || {}, match.filename || ''); const modelData = encodeURIComponent(JSON.stringify(contextModel)); const matchPath = match.model?.relative_path || match.model?.path || match.path || match.filename || ''; - html += `
`; + html += `
`; html += this.getConfidenceBadge(match.confidence); - html += `${this.escapeHtml(matchPath)}`; - html += `Partial`; - html += ``; + html += `${this.escapeHtml(matchPath)}`; + html += `Partial`; + html += ``; html += `
`; } html += `
`; } } else if (missing.is_urn && !missing.civitai_info) { - html += `
Waiting for CivitAI filename to search local models...
`; + html += `
Waiting for CivitAI filename to search local models...
`; } else if (allMatches.length > 0 && filteredMatches.length === 0) { - html += `
No matches above 70% confidence
`; + html += `
No matches above 70% confidence
`; } else { - html += `
No local matches found
`; + html += `
No local matches found
`; } return html; @@ -1024,7 +1024,7 @@ export const searchPanelMethods = { civitai_candidate_limit: tokens.civitai_candidate_limit }; - const response = await api.fetchApi('/model_linker/search', { + const response = await api.fetchApi('/model_resolver/search', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) @@ -1049,14 +1049,14 @@ export const searchPanelMethods = { refreshMissingListStats() { if (!this.contentElement) return; - const statsEl = this.contentElement.querySelector('.ml-missing-list-stats'); + const statsEl = this.contentElement.querySelector('.mr-missing-list-stats'); if (!statsEl) return; const stats = this.getMissingModelSummaryStats(this.missingModels || []); statsEl.innerHTML = ` - ${stats.exact} exact - ${stats.partial} partial - ${stats.none} no match + ${stats.exact} exact + ${stats.partial} partial + ${stats.none} no match `; }, @@ -1064,7 +1064,7 @@ export const searchPanelMethods = { if (!this.contentElement) return; const key = this.getMissingModelKey(missing); - const rows = this.contentElement.querySelectorAll('.ml-missing-list-row'); + const rows = this.contentElement.querySelectorAll('.mr-missing-list-row'); for (const row of rows) { if (row.getAttribute('data-missing-key') !== key) continue; @@ -1074,22 +1074,22 @@ export const searchPanelMethods = { const matchDisplay = matchName || 'No local match'; const matchClass = confidence === 100 ? 'exact' : (bestMatch ? 'partial' : 'none'); - const bestEl = row.querySelector('.ml-missing-row-best'); + const bestEl = row.querySelector('.mr-missing-row-best'); if (bestEl) { bestEl.setAttribute('data-tooltip', matchDisplay); bestEl.innerHTML = bestMatch ? this.escapeHtml(matchDisplay) - : '-- No local match'; + : '-- No local match'; } - const matchEl = row.querySelector('.ml-missing-row-match'); + const matchEl = row.querySelector('.mr-missing-row-match'); if (matchEl) { matchEl.classList.remove( - 'ml-missing-row-match-exact', - 'ml-missing-row-match-partial', - 'ml-missing-row-match-none' + 'mr-missing-row-match-exact', + 'mr-missing-row-match-partial', + 'mr-missing-row-match-none' ); - matchEl.classList.add(`ml-missing-row-match-${matchClass}`); + matchEl.classList.add(`mr-missing-row-match-${matchClass}`); const valueEl = matchEl.querySelector('strong'); if (valueEl) { valueEl.textContent = bestMatch @@ -1116,7 +1116,7 @@ export const searchPanelMethods = { } const promise = (async () => { - const response = await api.fetchApi('/model_linker/local-matches', { + const response = await api.fetchApi('/model_resolver/local-matches', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ @@ -1147,7 +1147,7 @@ export const searchPanelMethods = { const bodyId = `local-matches-body-${missing.node_id}-${missing.widget_index}`; const container = this.contentElement.querySelector(`#${bodyId}`); if (container) { - container.innerHTML = `
Searching local matches for "${missing.civitai_info.expected_filename}"...
`; + container.innerHTML = `
Searching local matches for "${missing.civitai_info.expected_filename}"...
`; } try { @@ -1158,9 +1158,9 @@ export const searchPanelMethods = { } this.refreshMissingListRowLocalMatch(missing); } catch (error) { - console.error('Model Linker: URN local match refresh error:', error); + console.error('Model Resolver: URN local match refresh error:', error); if (container) { - container.innerHTML = `
Failed to refresh local matches.
`; + container.innerHTML = `
Failed to refresh local matches.
`; } } }, @@ -1179,7 +1179,7 @@ export const searchPanelMethods = { await this.refreshUrnLocalMatches(missing); } catch (error) { missing.__urnLocalRefreshFailed = true; - console.error('Model Linker: initial URN local match refresh error:', error); + console.error('Model Resolver: initial URN local match refresh error:', error); } })(); refreshTasks.push(task); diff --git a/web/linker/shell/dialog_shell_methods.js b/web/resolver/shell/dialog_shell_methods.js similarity index 88% rename from web/linker/shell/dialog_shell_methods.js rename to web/resolver/shell/dialog_shell_methods.js index 553d01b..f4e78bf 100644 --- a/web/linker/shell/dialog_shell_methods.js +++ b/web/resolver/shell/dialog_shell_methods.js @@ -1,27 +1,27 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; export const dialogShellMethods = { createHeader() { // Create tabs - this.missingTab = $el("button.ml-tab.ml-tab-active", { + this.missingTab = $el("button.mr-tab.mr-tab-active", { onclick: () => this.switchTab('missing') - }, [$el("span.ml-tab-label", { textContent: "Missing Models" })]); + }, [$el("span.mr-tab-label", { textContent: "Missing Models" })]); - this.loadedTab = $el("button.ml-tab", { + this.loadedTab = $el("button.mr-tab", { onclick: () => this.switchTab('loaded') - }, [$el("span.ml-tab-label", { textContent: "Loaded Models" })]); + }, [$el("span.mr-tab-label", { textContent: "Loaded Models" })]); - this.optionsTab = $el("button.ml-tab", { + this.optionsTab = $el("button.mr-tab", { onclick: () => this.switchTab('options') - }, [$el("span.ml-tab-label", { textContent: "Options" })]); + }, [$el("span.mr-tab-label", { textContent: "Options" })]); if (this.activeTab === 'missing') { this.updateTabButtonStates(); } const dragHandle = $el("div", { - id: "model-linker-drag-handle", + id: "model-resolver-drag-handle", ondragstart: (e) => e.preventDefault() }, [ $el("span", { textContent: "⠿" }) @@ -29,50 +29,50 @@ export const dialogShellMethods = { this.setTooltip(dragHandle, "Drag window"); const fullscreenButton = $el("button", { - id: "model-linker-fullscreen-toggle", - className: "ml-window-btn ml-window-btn--fullscreen", - innerHTML: getSvgIcon('windowMaximize', 'currentColor', 'ml-window-btn-icon'), + id: "model-resolver-fullscreen-toggle", + className: "mr-window-btn mr-window-btn--fullscreen", + innerHTML: getSvgIcon('windowMaximize', 'currentColor', 'mr-window-btn-icon'), ariaLabel: "Toggle full screen", onclick: () => this.toggleFullScreen() }); this.setTooltip(fullscreenButton, "Toggle full screen"); this.dockButton = $el("button", { - id: "model-linker-dock-toggle", - className: "ml-window-btn ml-window-btn--dock", - innerHTML: getSvgIcon('internalLink', 'currentColor', 'ml-window-btn-icon'), - ariaLabel: "Dock Model Linker to sidebar", + id: "model-resolver-dock-toggle", + className: "mr-window-btn mr-window-btn--dock", + innerHTML: getSvgIcon('internalLink', 'currentColor', 'mr-window-btn-icon'), + ariaLabel: "Dock Model Resolver to sidebar", onclick: () => this.dockToSidebar() }); this.setTooltip(this.dockButton, "Dock to sidebar"); this.undockButton = $el("button", { - id: "model-linker-undock-toggle", - className: "ml-window-btn ml-window-btn--undock", - innerHTML: getSvgIcon('externalLink', 'currentColor', 'ml-window-btn-icon'), - ariaLabel: "Undock Model Linker", + id: "model-resolver-undock-toggle", + className: "mr-window-btn mr-window-btn--undock", + innerHTML: getSvgIcon('externalLink', 'currentColor', 'mr-window-btn-icon'), + ariaLabel: "Undock Model Resolver", onclick: () => this.undockToFloating() }); this.setTooltip(this.undockButton, "Undock to floating window"); - return $el("div.ml-dialog-shell", {}, [ - $el("div.ml-dialog-topbar", {}, [ - $el("div.ml-dialog-brand", {}, [ + return $el("div.mr-dialog-shell", {}, [ + $el("div.mr-dialog-topbar", {}, [ + $el("div.mr-dialog-brand", {}, [ dragHandle, - $el("div.ml-tabs", {}, [ + $el("div.mr-tabs", {}, [ this.missingTab, this.loadedTab, this.optionsTab ]) ]), - $el("div.ml-dialog-controls", {}, [ + $el("div.mr-dialog-controls", {}, [ this.dockButton, this.undockButton, fullscreenButton, $el("button", { - className: "ml-window-btn ml-window-btn--close", - innerHTML: getSvgIcon('x', 'currentColor', 'ml-window-btn-icon'), - ariaLabel: "Close Model Linker", + className: "mr-window-btn mr-window-btn--close", + innerHTML: getSvgIcon('x', 'currentColor', 'mr-window-btn-icon'), + ariaLabel: "Close Model Resolver", onclick: () => this.close() }) ]) @@ -142,13 +142,13 @@ export const dialogShellMethods = { } try { - const wh = JSON.parse(localStorage.getItem('model_linker_modal_size_before_fs') || 'null'); + const wh = JSON.parse(localStorage.getItem('model_resolver_modal_size_before_fs') || 'null'); if (wh?.w && wh?.h) { el.style.width = `${wh.w}px`; el.style.height = `${wh.h}px`; } - const pos = JSON.parse(localStorage.getItem('model_linker_modal_pos') || 'null'); + const pos = JSON.parse(localStorage.getItem('model_resolver_modal_pos') || 'null'); if (pos && Number.isFinite(pos.top) && Number.isFinite(pos.left)) { el.style.top = `${pos.top}px`; el.style.left = `${pos.left}px`; @@ -200,8 +200,8 @@ export const dialogShellMethods = { this.pendingDockToSidebar = false; this.rememberSidebarOpenMode('docked'); this.backdrop.style.display = 'none'; - container.classList.add('ml-sidebar-dock-panel'); - this.element.classList.add('ml-is-docked'); + container.classList.add('mr-sidebar-dock-panel'); + this.element.classList.add('mr-is-docked'); this.clearModalPlacementStyles(); this.element.style.display = 'flex'; @@ -311,7 +311,7 @@ export const dialogShellMethods = { const dockContainer = this.dockContainer; this.docked = false; this.dockContainer = null; - this.element.classList.remove('ml-is-docked'); + this.element.classList.remove('mr-is-docked'); this.clearModalPlacementStyles(); if (this.element.parentNode !== document.body) { @@ -412,12 +412,12 @@ export const dialogShellMethods = { this.fullscreen = !!enable; const el = this.element; if (!el) return; - const btn = document.getElementById('model-linker-fullscreen-toggle'); + const btn = document.getElementById('model-resolver-fullscreen-toggle'); if (enable) { // Save current size try { const rect = el.getBoundingClientRect(); - localStorage.setItem('model_linker_modal_size_before_fs', JSON.stringify({ w: Math.round(rect.width), h: Math.round(rect.height) })); + localStorage.setItem('model_resolver_modal_size_before_fs', JSON.stringify({ w: Math.round(rect.width), h: Math.round(rect.height) })); } catch (e) {} el.style.top = '0'; el.style.left = '0'; @@ -429,11 +429,11 @@ export const dialogShellMethods = { el.style.borderRadius = '0'; el.style.resize = 'none'; if (btn) { - btn.innerHTML = getSvgIcon('windowRestore', 'currentColor', 'ml-window-btn-icon'); + btn.innerHTML = getSvgIcon('windowRestore', 'currentColor', 'mr-window-btn-icon'); btn.setAttribute('aria-label', 'Exit full screen'); this.setTooltip(btn, 'Exit full screen'); } - try { localStorage.setItem('model_linker_modal_fullscreen', '1'); } catch (e) {} + try { localStorage.setItem('model_resolver_modal_fullscreen', '1'); } catch (e) {} } else { this.returnToDockedAfterFullscreen = false; // Restore centered sizing @@ -443,7 +443,7 @@ export const dialogShellMethods = { el.style.resize = 'both'; // Restore saved pre-FS size if available let wh = null; - try { wh = JSON.parse(localStorage.getItem('model_linker_modal_size_before_fs') || 'null'); } catch (e) {} + try { wh = JSON.parse(localStorage.getItem('model_resolver_modal_size_before_fs') || 'null'); } catch (e) {} if (wh && wh.w && wh.h) { el.style.width = `${wh.w}px`; el.style.height = `${wh.h}px`; @@ -453,7 +453,7 @@ export const dialogShellMethods = { } // Restore last known position if available, else center try { - const pos = JSON.parse(localStorage.getItem('model_linker_modal_pos') || 'null'); + const pos = JSON.parse(localStorage.getItem('model_resolver_modal_pos') || 'null'); if (pos && Number.isFinite(pos.top) && Number.isFinite(pos.left)) { el.style.top = `${pos.top}px`; el.style.left = `${pos.left}px`; @@ -469,12 +469,12 @@ export const dialogShellMethods = { el.style.transform = 'translate(-50%, -50%)'; } if (btn) { - btn.innerHTML = getSvgIcon('windowMaximize', 'currentColor', 'ml-window-btn-icon'); + btn.innerHTML = getSvgIcon('windowMaximize', 'currentColor', 'mr-window-btn-icon'); btn.setAttribute('aria-label', 'Enter full screen'); this.setTooltip(btn, 'Enter full screen'); } this.ensureModalHandleInViewport({ persist: true }); - try { localStorage.setItem('model_linker_modal_fullscreen', '0'); } catch (e) {} + try { localStorage.setItem('model_resolver_modal_fullscreen', '0'); } catch (e) {} if (shouldReturnToDocked) { this.dockToSidebar(); @@ -489,7 +489,7 @@ export const dialogShellMethods = { const vw = window.innerWidth || document.documentElement.clientWidth || 0; const vh = window.innerHeight || document.documentElement.clientHeight || 0; const pad = 4; - const handle = document.getElementById('model-linker-drag-handle'); + const handle = document.getElementById('model-resolver-drag-handle'); if (handle) { const elRect = el.getBoundingClientRect(); @@ -522,7 +522,7 @@ export const dialogShellMethods = { const el = this.element; if (!el) return; const rect = el.getBoundingClientRect(); - localStorage.setItem('model_linker_modal_pos', JSON.stringify({ top: Math.round(rect.top), left: Math.round(rect.left) })); + localStorage.setItem('model_resolver_modal_pos', JSON.stringify({ top: Math.round(rect.top), left: Math.round(rect.left) })); } catch (e) { /* ignore */ } }, diff --git a/web/linker/shell/lifecycle_graph_methods.js b/web/resolver/shell/lifecycle_graph_methods.js similarity index 93% rename from web/linker/shell/lifecycle_graph_methods.js rename to web/resolver/shell/lifecycle_graph_methods.js index 78fdc48..a367689 100644 --- a/web/linker/shell/lifecycle_graph_methods.js +++ b/web/resolver/shell/lifecycle_graph_methods.js @@ -1,4 +1,4 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; @@ -30,7 +30,7 @@ export const lifecycleGraphMethods = { // Restore fullscreen state if enabled try { - const fs = localStorage.getItem('model_linker_modal_fullscreen'); + const fs = localStorage.getItem('model_resolver_modal_fullscreen'); if (!this.docked && restoreFullscreen && fs === '1') this.setFullScreen(true); } catch (e) { } @@ -55,17 +55,17 @@ export const lifecycleGraphMethods = { attachDragHandleIfNeeded() { if (this._dragHandleAttached) return; - const handle = document.getElementById('model-linker-drag-handle'); - const topbar = this.element?.querySelector('.ml-dialog-topbar'); + const handle = document.getElementById('model-resolver-drag-handle'); + const topbar = this.element?.querySelector('.mr-dialog-topbar'); if (!handle || !topbar) return; const onMouseDown = (e) => { if (this.fullscreen || this.docked) return; // no drag in fullscreen or docked mode if (e.button !== 0 || this.isTopbarDragExcluded(e.target)) return; - topbar.classList.add('ml-is-dragging'); + topbar.classList.add('mr-is-dragging'); this.startDrag(e); }; - const onMouseUp = () => { topbar.classList.remove('ml-is-dragging'); }; + const onMouseUp = () => { topbar.classList.remove('mr-is-dragging'); }; topbar.addEventListener('mousedown', onMouseDown); document.addEventListener('mouseup', onMouseUp); @@ -76,8 +76,8 @@ export const lifecycleGraphMethods = { isTopbarDragExcluded(target) { if (!(target instanceof Element)) return false; return !!target.closest([ - '.ml-tabs', - '.ml-dialog-controls', + '.mr-tabs', + '.mr-dialog-controls', 'button', 'a', 'input', @@ -144,7 +144,7 @@ export const lifecycleGraphMethods = { // Call analyze endpoint const progressPromise = this.pollAnalysisProgress(analysisId, analysisId); - const response = await api.fetchApi('/model_linker/analyze', { + const response = await api.fetchApi('/model_resolver/analyze', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workflow, analysis_id: analysisId }) @@ -166,9 +166,9 @@ export const lifecycleGraphMethods = { } catch (error) { this._analysisProgressToken = null; - console.error('Model Linker: Error loading workflow data:', error); + console.error('Model Resolver: Error loading workflow data:', error); if (this.contentElement) { - this.contentElement.innerHTML = `

Error: ${error.message}

`; + this.contentElement.innerHTML = `

Error: ${error.message}

`; } } }, @@ -184,7 +184,7 @@ export const lifecycleGraphMethods = { const workflow = app.graph.serialize(); return workflow; } catch (e) { - console.warn('Model Linker: Could not serialize workflow from graph:', e); + console.warn('Model Resolver: Could not serialize workflow from graph:', e); } } return null; @@ -243,7 +243,7 @@ export const lifecycleGraphMethods = { this.showNotification(`Focused on Node #${nodeId} (${node.type})`, 'info'); } catch (e) { - console.error('Model Linker: Error locating node:', e); + console.error('Model Resolver: Error locating node:', e); this.showNotification('Error locating node: ' + e.message, 'error'); } }, @@ -417,13 +417,13 @@ export const lifecycleGraphMethods = { info.downloadBtn = newDownloadBtn; // Show that download is in progress - newProgressDiv.classList.remove('ml-is-hidden'); - newProgressDiv.classList.add('ml-is-visible'); + newProgressDiv.classList.remove('mr-is-hidden'); + newProgressDiv.classList.add('mr-is-visible'); newProgressDiv.innerHTML = this.renderProgressWithAction({ percent: 0, - leftText: 'Downloading...', + leftText: 'Downloading...', rightText: '', - actionClass: 'cancel-download-btn ml-btn ml-btn-danger ml-btn-sm', + actionClass: 'cancel-download-btn mr-btn mr-btn-danger mr-btn-sm', actionText: 'Cancel', actionDataAttr: `data-download-id="${downloadId}"` }); diff --git a/web/linker/shell/workflow_state_methods.js b/web/resolver/shell/workflow_state_methods.js similarity index 95% rename from web/linker/shell/workflow_state_methods.js rename to web/resolver/shell/workflow_state_methods.js index 2bf9aab..72a4c2b 100644 --- a/web/linker/shell/workflow_state_methods.js +++ b/web/resolver/shell/workflow_state_methods.js @@ -1,4 +1,4 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; @@ -8,7 +8,7 @@ export const workflowStateMethods = { try { return JSON.stringify(workflow); } catch (error) { - console.warn('Model Linker: workflow signature generation failed', error); + console.warn('Model Resolver: workflow signature generation failed', error); return null; } }, @@ -35,7 +35,7 @@ export const workflowStateMethods = { try { return JSON.parse(JSON.stringify(Array.isArray(list) ? list : [])); } catch (error) { - console.warn('Model Linker: failed to clone queued selections', error); + console.warn('Model Resolver: failed to clone queued selections', error); return Array.isArray(list) ? list.map(item => ({ ...item })) : []; } }, @@ -67,7 +67,7 @@ export const workflowStateMethods = { try { clone = JSON.parse(JSON.stringify(state || {})); } catch (error) { - console.warn('Model Linker: failed to clone search state', error); + console.warn('Model Resolver: failed to clone search state', error); clone = { ...state }; } @@ -231,7 +231,7 @@ export const workflowStateMethods = { if (!routeChanged && !signatureChanged) return; - console.log('Model Linker: active workflow changed, refreshing current tab', { + console.log('Model Resolver: active workflow changed, refreshing current tab', { reason, route: currentRoute, tab: this.activeTab diff --git a/web/linker/shell/workflow_update_methods.js b/web/resolver/shell/workflow_update_methods.js similarity index 91% rename from web/linker/shell/workflow_update_methods.js rename to web/resolver/shell/workflow_update_methods.js index 0e7e6f2..bb895cf 100644 --- a/web/linker/shell/workflow_update_methods.js +++ b/web/resolver/shell/workflow_update_methods.js @@ -1,4 +1,4 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; @@ -49,7 +49,7 @@ export const workflowUpdateMethods = { */ async updateWorkflowInComfyUI(workflow) { if (!app || !app.graph) { - console.warn('Model Linker: Could not update workflow - app or app.graph not available'); + console.warn('Model Resolver: Could not update workflow - app or app.graph not available'); return; } @@ -78,9 +78,9 @@ export const workflowUpdateMethods = { return; } - console.warn('Model Linker: No method available to update workflow'); + console.warn('Model Resolver: No method available to update workflow'); } catch (error) { - console.error('Model Linker: Error updating workflow in ComfyUI:', error); + console.error('Model Resolver: Error updating workflow in ComfyUI:', error); // Don't throw - allow the workflow update to continue even if UI update fails // The backend has already updated the workflow data } diff --git a/web/linker/utils/render_format_methods.js b/web/resolver/utils/render_format_methods.js similarity index 84% rename from web/linker/utils/render_format_methods.js rename to web/resolver/utils/render_format_methods.js index 23926e3..ee5251b 100644 --- a/web/linker/utils/render_format_methods.js +++ b/web/resolver/utils/render_format_methods.js @@ -1,4 +1,4 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; @@ -11,17 +11,17 @@ export const renderFormatMethods = { getConfidenceBadge(confidence) { let badgeClass; if (confidence >= 95) { - badgeClass = 'ml-badge-high'; + badgeClass = 'mr-badge-high'; } else if (confidence >= 70) { - badgeClass = 'ml-badge-medium'; + badgeClass = 'mr-badge-medium'; } else { - badgeClass = 'ml-badge-low'; + badgeClass = 'mr-badge-low'; } - return `${confidence}%`; + return `${confidence}%`; }, getStatusBadge(label, variant = 'neutral') { - return `${label}`; + return `${label}`; }, /** @@ -110,8 +110,8 @@ export const renderFormatMethods = { const icon = icons[type] || icons.info; return ` -
- ${icon} +
+ ${icon} ${message}
`; @@ -126,11 +126,11 @@ export const renderFormatMethods = { */ renderProgressBar(percent, leftText = '', rightText = '') { return ` -
-
-
+
+
+
-
+
${leftText} ${rightText}
@@ -147,13 +147,13 @@ export const renderFormatMethods = { const detail = total > 0 ? `${current} / ${total}` : 'Preparing...'; return ` -
-
+
+
${this.getStatusBadge('Analyzing', 'info')} - ${message} + ${message}
${this.renderProgressBar(percent, detail, `${percent}%`)} - ${modelName ? `
${modelName}
` : ''} + ${modelName ? `
${modelName}
` : ''}
`; }, @@ -161,7 +161,7 @@ export const renderFormatMethods = { async pollAnalysisProgress(analysisId, token) { while (this._analysisProgressToken === token) { try { - const response = await api.fetchApi(`/model_linker/analyze-progress/${analysisId}`); + const response = await api.fetchApi(`/model_resolver/analyze-progress/${analysisId}`); if (response.ok && this.contentElement && this._analysisProgressToken === token) { const progress = await response.json(); this.contentElement.innerHTML = this.renderAnalysisProgress(progress); @@ -170,7 +170,7 @@ export const renderFormatMethods = { } } } catch (error) { - console.warn('Model Linker: analysis progress polling failed', error); + console.warn('Model Resolver: analysis progress polling failed', error); } await new Promise(resolve => setTimeout(resolve, 250)); diff --git a/web/linker/views/missing_browser_methods.js b/web/resolver/views/missing_browser_methods.js similarity index 86% rename from web/linker/views/missing_browser_methods.js rename to web/resolver/views/missing_browser_methods.js index c67fdaa..16eec15 100644 --- a/web/linker/views/missing_browser_methods.js +++ b/web/resolver/views/missing_browser_methods.js @@ -1,4 +1,4 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; @@ -152,8 +152,8 @@ export const missingBrowserMethods = { }; const title = `${label}: ${statusLabels[status] || status}`; const iconName = this.getSearchSourceIconName(item.source); - const iconHtml = getSvgIcon(iconName, 'currentColor', 'ml-missing-source-icon'); - return `${iconHtml}`; + const iconHtml = getSvgIcon(iconName, 'currentColor', 'mr-missing-source-icon'); + return `${iconHtml}`; }).join(''); }, @@ -203,27 +203,27 @@ export const missingBrowserMethods = { savedDetailWidth = parseInt(localStorage.getItem(this.missingBrowserSplitStorageKey) || '', 10); } catch (e) {} const splitStyle = Number.isFinite(savedDetailWidth) && savedDetailWidth > 0 - ? `--ml-missing-detail-track:${savedDetailWidth}px;` + ? `--mr-missing-detail-track:${savedDetailWidth}px;` : ''; - const listStyle = `--ml-missing-model-col:${listLayout.modelPx}px;--ml-missing-type-col:${listLayout.typePx}px;`; + const listStyle = `--mr-missing-model-col:${listLayout.modelPx}px;--mr-missing-type-col:${listLayout.typePx}px;`; let html = ` -
-
-
+
+
+
-
${totalMissing} missing model${totalMissing === 1 ? '' : 's'}
-
${this.escapeHtml(activeHint)}
+
${totalMissing} missing model${totalMissing === 1 ? '' : 's'}
+
${this.escapeHtml(activeHint)}
-
- ${stats.exact} exact - ${stats.partial} partial - ${stats.none} no match +
+ ${stats.exact} exact + ${stats.partial} partial + ${stats.none} no match
-
- - +
+ + # Missing Model @@ -232,7 +232,7 @@ export const missingBrowserMethods = { Match Sources
-
+
`; missingModels.forEach((missing, index) => { @@ -251,29 +251,29 @@ export const missingBrowserMethods = { const nodeDisplay = this.getMissingNodeDisplay(missing); const nodeId = missing.node_id ?? ''; const rowNodeHtml = nodeDisplay.canLocate - ? `` - : `${this.escapeHtml(nodeDisplay.text)}`; + ? `` + : `${this.escapeHtml(nodeDisplay.text)}`; html += `
- - + + - ${index + 1} - - ${this.escapeHtml(formattedFilename.display)} + ${index + 1} + + ${this.escapeHtml(formattedFilename.display)} ${rowNodeHtml} - ${this.escapeHtml(typeLabel)} - - ${bestMatch ? this.escapeHtml(matchDisplay) : '-- No local match'} + ${this.escapeHtml(typeLabel)} + + ${bestMatch ? this.escapeHtml(matchDisplay) : '-- No local match'} - + ${bestMatch ? `${confidence.toFixed(confidence % 1 ? 1 : 0)}%` : '--'} - ${this.renderMissingSourcesSummary(missing)} + ${this.renderMissingSourcesSummary(missing)}
`; }); @@ -281,8 +281,8 @@ export const missingBrowserMethods = { html += `
- -
+ +
${detailMissing ? this.renderMissingModel(detailMissing, detailIndex) : this.renderStatusMessage('Select a missing model to inspect details.', 'info')}
@@ -300,7 +300,7 @@ export const missingBrowserMethods = { this.displayMissingModels(container, data); }; - const selectAllCheckbox = container.querySelector('.ml-missing-select-all-check'); + const selectAllCheckbox = container.querySelector('.mr-missing-select-all-check'); if (selectAllCheckbox) { this.updateBatchSelectAllCheckbox(); selectAllCheckbox.addEventListener('click', (event) => { @@ -317,8 +317,8 @@ export const missingBrowserMethods = { }); } - container.querySelectorAll('.ml-missing-list-row').forEach(row => { - const checkbox = row.querySelector('.ml-missing-row-check'); + container.querySelectorAll('.mr-missing-list-row').forEach(row => { + const checkbox = row.querySelector('.mr-missing-row-check'); if (checkbox) { checkbox.addEventListener('click', (event) => { event.stopPropagation(); @@ -348,7 +348,7 @@ export const missingBrowserMethods = { } row.addEventListener('click', (event) => { - const clickedLocate = event.target instanceof Element && event.target.closest('.ml-missing-row-locate'); + const clickedLocate = event.target instanceof Element && event.target.closest('.mr-missing-row-locate'); if (clickedLocate) return; selectRow(row); }); @@ -360,7 +360,7 @@ export const missingBrowserMethods = { }); }); - container.querySelectorAll('.ml-missing-row-locate').forEach(button => { + container.querySelectorAll('.mr-missing-row-locate').forEach(button => { button.addEventListener('click', (event) => { event.preventDefault(); event.stopPropagation(); @@ -378,8 +378,8 @@ export const missingBrowserMethods = { }, wireMissingBrowserSplitter(container) { - const browser = container.querySelector('.ml-missing-browser'); - const splitter = browser?.querySelector('.ml-missing-browser-splitter'); + const browser = container.querySelector('.mr-missing-browser'); + const splitter = browser?.querySelector('.mr-missing-browser-splitter'); if (!(browser instanceof HTMLElement) || !(splitter instanceof HTMLElement)) return; this.restoreMissingBrowserSplitWidth(browser); @@ -390,7 +390,7 @@ export const missingBrowserMethods = { }); splitter.addEventListener('dblclick', () => { - browser.querySelector('.ml-missing-detail-pane')?.style.removeProperty('--ml-missing-detail-track'); + browser.querySelector('.mr-missing-detail-pane')?.style.removeProperty('--mr-missing-detail-track'); try { localStorage.removeItem(this.missingBrowserSplitStorageKey); } catch (e) {} @@ -425,7 +425,7 @@ export const missingBrowserMethods = { startMissingBrowserSplitDrag(event, browser) { if (!(browser instanceof HTMLElement)) return; - const detailPane = browser.querySelector('.ml-missing-detail-pane'); + const detailPane = browser.querySelector('.mr-missing-detail-pane'); if (!(detailPane instanceof HTMLElement)) return; event.preventDefault(); @@ -463,7 +463,7 @@ export const missingBrowserMethods = { this._missingBrowserSplitFrame = requestAnimationFrame(() => { this._missingBrowserSplitFrame = null; if (!this._missingBrowserSplitDragging || !this._missingBrowserSplitDetailPane || !this._pendingMissingBrowserSplitWidth) return; - this._missingBrowserSplitDetailPane.style.setProperty('--ml-missing-detail-track', `${this._pendingMissingBrowserSplitWidth}px`); + this._missingBrowserSplitDetailPane.style.setProperty('--mr-missing-detail-track', `${this._pendingMissingBrowserSplitWidth}px`); }); }, @@ -477,7 +477,7 @@ export const missingBrowserMethods = { this._missingBrowserSplitFrame = null; } if (this._missingBrowserSplitDetailPane && this._pendingMissingBrowserSplitWidth) { - this._missingBrowserSplitDetailPane.style.setProperty('--ml-missing-detail-track', `${this._pendingMissingBrowserSplitWidth}px`); + this._missingBrowserSplitDetailPane.style.setProperty('--mr-missing-detail-track', `${this._pendingMissingBrowserSplitWidth}px`); try { localStorage.setItem(this.missingBrowserSplitStorageKey, String(this._pendingMissingBrowserSplitWidth)); } catch (e) {} @@ -495,7 +495,7 @@ export const missingBrowserMethods = { }, resizeMissingBrowserDetailBy(browser, delta) { - const detailPane = browser.querySelector('.ml-missing-detail-pane'); + const detailPane = browser.querySelector('.mr-missing-detail-pane'); if (!(detailPane instanceof HTMLElement)) return; this.setMissingBrowserDetailWidth(browser, detailPane.getBoundingClientRect().width + delta); @@ -504,9 +504,9 @@ export const missingBrowserMethods = { setMissingBrowserDetailWidth(browser, width, { persist = true } = {}) { const bounds = this.getMissingBrowserSplitBounds(browser); const nextWidth = Math.round(Math.max(bounds.min, Math.min(bounds.max, width))); - const detailPane = browser.querySelector('.ml-missing-detail-pane'); + const detailPane = browser.querySelector('.mr-missing-detail-pane'); const target = detailPane instanceof HTMLElement ? detailPane : browser; - target.style.setProperty('--ml-missing-detail-track', `${nextWidth}px`); + target.style.setProperty('--mr-missing-detail-track', `${nextWidth}px`); if (persist) { try { @@ -517,7 +517,7 @@ export const missingBrowserMethods = { getMissingBrowserSplitBounds(browser) { const browserRect = browser.getBoundingClientRect(); - const splitter = browser.querySelector('.ml-missing-browser-splitter'); + const splitter = browser.querySelector('.mr-missing-browser-splitter'); const splitterWidth = splitter instanceof HTMLElement ? splitter.getBoundingClientRect().width : 10; @@ -569,12 +569,12 @@ export const missingBrowserMethods = { const folder = getFolder(m); const isHighlighted = i === highlightIdx; const folderDisplay = folder ? folder.replace(/\\/g, '/').replace(/:/, '') : ''; - html += `
`; - html += `
`; + html += `
`; + html += `
`; html += `${this.escapeHtml(label)}`; html += `
`; if (folderDisplay) { - html += `
Folder ${this.escapeHtml(folderDisplay)}
`; + html += `
Folder ${this.escapeHtml(folderDisplay)}
`; } html += `
`; } @@ -604,16 +604,16 @@ export const missingBrowserMethods = { comboInput.addEventListener('input', debouncedFilter); comboInput.addEventListener('focus', () => { if (comboList) { - comboList.classList.remove('ml-is-hidden'); - comboList.classList.add('ml-is-visible'); + comboList.classList.remove('mr-is-hidden'); + comboList.classList.add('mr-is-visible'); } populateComboOptions(comboInput.value); }); comboInput.addEventListener('blur', () => { setTimeout(() => { if (comboList) { - comboList.classList.remove('ml-is-visible'); - comboList.classList.add('ml-is-hidden'); + comboList.classList.remove('mr-is-visible'); + comboList.classList.add('mr-is-hidden'); } }, 200); }); @@ -630,8 +630,8 @@ export const missingBrowserMethods = { const state = this.searchResultCache.get(this.getMissingSearchKey(missing)); const searchResultsDiv = container.querySelector(`#search-results-${missing.node_id}-${missing.widget_index}`); if (state && searchResultsDiv && this.hasRenderableSearchState(state)) { - searchResultsDiv.classList.remove('ml-is-hidden'); - searchResultsDiv.classList.add('ml-is-visible'); + searchResultsDiv.classList.remove('mr-is-hidden'); + searchResultsDiv.classList.add('mr-is-visible'); this.displaySearchResults(missing, state, searchResultsDiv); } }, @@ -753,14 +753,14 @@ export const missingBrowserMethods = { const nodeChipText = this.escapeHtml(nodeDisplay.text); // Start card - let html = `
`; + let html = `
`; // Card Header: Filename as headline + node chip - html += `
`; - html += `
`; + html += `
`; + html += `
`; const titleMetaParts = []; - let titlePrimaryHtml = `${missingFilename.display}`; + let titlePrimaryHtml = `${missingFilename.display}`; let titleSecondaryHtml = ''; const modelId = missing.urn_model_id || missing.urn?.model_id; @@ -769,40 +769,40 @@ export const missingBrowserMethods = { const urnLoadingId = `urn-loading-${missing.node_id}-${missing.widget_index}`; if (missing.is_urn) { - titleMetaParts.push(`${missingFilename.display}`); + titleMetaParts.push(`${missingFilename.display}`); } if (missing.is_urn && !missing.civitai_info) { // URN without info - show Loading and fetch async in background - titlePrimaryHtml = `Resolving CivitAI model...`; + titlePrimaryHtml = `Resolving CivitAI model...`; setTimeout(() => this.resolveUrnAsync(modelId, versionId, urnLoadingId, modelUrl), 10); } else if (missing.is_urn && missing.civitai_info) { // URN with resolved info - show model name/version const civitaiInfo = missing.civitai_info; const civitaiLabelHtml = this.renderVersionedModelNameHtml(civitaiInfo.model_name, civitaiInfo.version_name); if (civitaiLabelHtml) { - const linkHtml = modelUrl ? `${civitaiLabelHtml}` : `${civitaiLabelHtml}`; - titlePrimaryHtml = `${linkHtml}`; + const linkHtml = modelUrl ? `${civitaiLabelHtml}` : `${civitaiLabelHtml}`; + titlePrimaryHtml = `${linkHtml}`; } if (civitaiInfo.expected_filename) { - titleSecondaryHtml = `Expected file: ${civitaiInfo.expected_filename}`; + titleSecondaryHtml = `Expected file: ${civitaiInfo.expected_filename}`; } } - html += `
`; + html += `
`; html += titleMetaParts.join(''); - html += `

${titlePrimaryHtml}

`; + html += `

${titlePrimaryHtml}

`; if (titleSecondaryHtml) { html += titleSecondaryHtml; } html += `
`; const locateId = `locate-${missing.node_id}-${missing.widget_index}`; - const nodeChipClasses = missing.is_top_level !== false ? 'ml-node-chip is-locatable' : 'ml-node-chip'; + const nodeChipClasses = missing.is_top_level !== false ? 'mr-node-chip is-locatable' : 'mr-node-chip'; const nodeChipTitle = missing.is_top_level !== false ? 'Center this node in the ComfyUI graph.' : ''; - html += `
`; + html += `
`; if (missing.category) { - html += `${this.getCategoryDisplayName(missing.category)}`; + html += `${this.getCategoryDisplayName(missing.category)}`; } html += ``; if (missing.is_top_level !== false) { @@ -815,34 +815,34 @@ export const missingBrowserMethods = { // Selected bar - shows if this slot has a queued selection (BELOW card header) const selectedBarId = `selected-bar-${missing.node_id}-${missing.widget_index}`; - html += `
`; + html += `
`; // Two-column layout - html += `
`; + html += `
`; // LEFT COLUMN: Local Matches - html += `
`; - html += `
Local Matches
`; + html += `
`; + html += `
Local Matches
`; html += `
`; html += this.renderLocalMatchesContent(missing, missingIndex); html += `
`; // Add all-models search picker - combo-style dropdown const comboId = `combo-${missing.node_id}-${missing.widget_index}`; - html += `
`; - html += `
`; - html += ``; - html += ``; - html += ``; + html += `
`; + html += `
`; + html += ``; + html += ``; + html += ``; html += `
`; - html += `
`; + html += `
`; html += `
`; html += `
`; // End left column // RIGHT COLUMN: Download Option - html += `
`; - html += `
Download
`; + html += `
`; + html += `
Download
`; const filename = missing.original_path?.split('/').pop()?.split('\\').pop() || ''; const downloadSource = missing.download_source; @@ -852,26 +852,26 @@ export const missingBrowserMethods = { html += this.renderKnownDownloadPanel(missing, downloadSource); } else if (perfectMatches.length > 0) { // Has perfect local match - download not needed, but allow online re-check. - html += `
`; + html += `
`; html += this.renderSearchControls(missing, { buttonText: 'Search Online' }); html += this.renderDownloadTargetControls(missing, missing.category || 'checkpoints'); html += `
`; - html += `
`; + html += `
`; } else if (missing.is_urn) { - html += `
`; - html += `
Resolving CivitAI download for this URN...
`; + html += `
`; + html += `
Resolving CivitAI download for this URN...
`; html += `
`; } else { // No known download - offer search - html += `
`; + html += `
`; html += this.renderSearchControls(missing); html += this.renderDownloadTargetControls(missing, missing.category || 'checkpoints'); html += `
`; - html += `
`; + html += `
`; } // Progress container (for downloads) - html += `
`; + html += `
`; html += `
`; // End right column html += `
`; // End columns @@ -890,30 +890,30 @@ export const missingBrowserMethods = { if (type === 'success') { children.push($el("span", { textContent: "✓", - className: "ml-notification-icon" + className: "mr-notification-icon" })); } else if (type === 'error') { children.push($el("span", { textContent: "×", - className: "ml-notification-icon" + className: "mr-notification-icon" })); } else if (type === 'info') { children.push($el("span", { textContent: "ℹ", - className: "ml-notification-icon" + className: "mr-notification-icon" })); } // Create notification banner const notification = $el("div", { - className: `ml-notification ml-notification--${type}` + className: `mr-notification mr-notification--${type}` }, [ ...children, $el("span", { textContent: message }), $el("button", { - className: "ml-notification-close", + className: "mr-notification-close", textContent: "×", onclick: () => { if (notification.parentNode) { diff --git a/web/linker/views/model_info_methods.js b/web/resolver/views/model_info_methods.js similarity index 80% rename from web/linker/views/model_info_methods.js rename to web/resolver/views/model_info_methods.js index 763c4c8..bf842a0 100644 --- a/web/linker/views/model_info_methods.js +++ b/web/resolver/views/model_info_methods.js @@ -1,4 +1,4 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; @@ -74,7 +74,7 @@ export const modelInfoMethods = { } try { - const response = await api.fetchApi('/model_linker/open-containing-folder', { + const response = await api.fetchApi('/model_resolver/open-containing-folder', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path }) @@ -84,7 +84,7 @@ export const modelInfoMethods = { throw new Error(`Open folder failed: ${response.status}`); } } catch (error) { - console.error('Model Linker: Open folder error:', error); + console.error('Model Resolver: Open folder error:', error); this.showNotification('Failed to open containing folder', 'error'); } }, @@ -100,7 +100,7 @@ export const modelInfoMethods = { try { // Search CivitAI for this model using hash (pass resolved_path for hash lookup) - const response = await api.fetchApi('/model_linker/civitai-search', { + const response = await api.fetchApi('/model_resolver/civitai-search', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ @@ -125,7 +125,7 @@ export const modelInfoMethods = { window.open(searchUrl, '_blank'); } } catch (e) { - console.error('Model Linker: Error searching CivitAI:', e); + console.error('Model Resolver: Error searching CivitAI:', e); // Fall back to direct search const searchName = name.replace(/\.(safetensors|ckpt|pt|pth|bin|pkl|sft|onnx|gguf)$/i, ''); const searchUrl = `https://civitai.com/search?q=${encodeURIComponent(searchName)}`; @@ -160,9 +160,9 @@ export const modelInfoMethods = { this.bindInfoDialogResizePersistence(dialog); // Add close handlers - const closeBtn = dialog.querySelector('.ml-info-dialog-close'); - const footerCloseBtn = dialog.querySelector('.ml-info-dialog-close-btn'); - const backdrop = dialog.querySelector('.ml-info-dialog-backdrop'); + const closeBtn = dialog.querySelector('.mr-info-dialog-close'); + const footerCloseBtn = dialog.querySelector('.mr-info-dialog-close-btn'); + const backdrop = dialog.querySelector('.mr-info-dialog-backdrop'); if (closeBtn) { closeBtn.addEventListener('click', () => this.closeInfoDialog(dialog)); @@ -190,80 +190,80 @@ export const modelInfoMethods = { const loraDisplayName = loraName.replace(/\.(safetensors|ckpt|pt|pth|bin|pkl|sft|onnx|gguf)$/i, ''); const dialog = document.createElement('div'); - dialog.className = 'ml-info-dialog-backdrop'; + dialog.className = 'mr-info-dialog-backdrop'; dialog._selectedTrainedWords = new Set(); dialog.innerHTML = ` -
-
-

${loraDisplayName}

- +
+
+

${loraDisplayName}

+
-
-
Loading...
-
-
- - +
+
Loading...
+
+
+ +
-
${sourcePill} -
+
${modelHtml} ${secondary || filename ? `${secondary || filename}` : ''}
${this.escapeHtml(match.label)}${size}
${actions}
${this.escapeHtml(match.label)}${size}
${actions}
+
- - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - - - + + + - - + +
File ?
File ?
Hash (sha256) ?
Hash (sha256) ?
CivitAI ?
CivitAI ?
Name ?
Name ?
Base Model ?
Base Model ?
-
- Trained Words ? - - 0 selected - +
+ Trained Words ? + + 0 selected +
-
Click words to select them.
-
+
Click words to select them.
+
Clip Skip ?
Clip Skip ?
Description ?
Description ? -
-
-
- +
+
+
+
-
+
- `; @@ -400,8 +400,8 @@ export const modelInfoMethods = { updateSelectedTrainedWordsSummary(dialog) { if (!dialog) return; - const countEl = dialog.querySelector('.ml-info-trained-words-count'); - const copyBtn = dialog.querySelector('.ml-info-copy-trained-words'); + const countEl = dialog.querySelector('.mr-info-trained-words-count'); + const copyBtn = dialog.querySelector('.mr-info-copy-trained-words'); const selected = dialog._selectedTrainedWords instanceof Set ? Array.from(dialog._selectedTrainedWords) : []; @@ -420,7 +420,7 @@ export const modelInfoMethods = { dialog.dataset.mlInfoBound = 'true'; dialog.addEventListener('click', async (event) => { - const wordBtn = event.target.closest('.ml-info-trained-word'); + const wordBtn = event.target.closest('.mr-info-trained-word'); if (wordBtn && dialog.contains(wordBtn)) { const word = wordBtn.dataset.word || ''; if (word) { @@ -443,7 +443,7 @@ export const modelInfoMethods = { return; } - const copyBtn = event.target.closest('.ml-info-copy-trained-words'); + const copyBtn = event.target.closest('.mr-info-copy-trained-words'); if (copyBtn && dialog.contains(copyBtn)) { const words = dialog._selectedTrainedWords instanceof Set ? Array.from(dialog._selectedTrainedWords) @@ -455,7 +455,7 @@ export const modelInfoMethods = { await navigator.clipboard.writeText(words.join(', ')); copyBtn.textContent = 'Copied'; } catch (error) { - console.error('Model Linker: Failed to copy trained words:', error); + console.error('Model Resolver: Failed to copy trained words:', error); copyBtn.textContent = 'Failed'; } @@ -467,9 +467,9 @@ export const modelInfoMethods = { return; } - const descToggleBtn = event.target.closest('.ml-info-description-toggle'); + const descToggleBtn = event.target.closest('.mr-info-description-toggle'); if (descToggleBtn && dialog.contains(descToggleBtn)) { - const descEl = dialog.querySelector('.ml-info-description'); + const descEl = dialog.querySelector('.mr-info-description'); if (!descEl) return; const isExpanded = descEl.classList.toggle('is-expanded'); @@ -479,7 +479,7 @@ export const modelInfoMethods = { }, getInfoDialogElement(dialog) { - return dialog?.querySelector?.('.ml-info-dialog') || null; + return dialog?.querySelector?.('.mr-info-dialog') || null; }, restoreInfoDialogSize(dialog) { @@ -487,7 +487,7 @@ export const modelInfoMethods = { if (!panel) return; try { - const saved = JSON.parse(localStorage.getItem('model_linker_info_dialog_size') || 'null'); + const saved = JSON.parse(localStorage.getItem('model_resolver_info_dialog_size') || 'null'); if (!saved || typeof saved !== 'object') return; const width = Number(saved.w); @@ -502,7 +502,7 @@ export const modelInfoMethods = { panel.style.width = `${clampedWidth}px`; panel.style.height = `${clampedHeight}px`; } catch (error) { - console.warn('Model Linker: Failed to restore info dialog size:', error); + console.warn('Model Resolver: Failed to restore info dialog size:', error); } }, @@ -516,9 +516,9 @@ export const modelInfoMethods = { if (!width || !height) return; try { - localStorage.setItem('model_linker_info_dialog_size', JSON.stringify({ w: width, h: height })); + localStorage.setItem('model_resolver_info_dialog_size', JSON.stringify({ w: width, h: height })); } catch (error) { - console.warn('Model Linker: Failed to save info dialog size:', error); + console.warn('Model Resolver: Failed to save info dialog size:', error); } }, @@ -544,7 +544,7 @@ export const modelInfoMethods = { */ async fetchModelInfoForDialog(loraName, modelData, dialog) { try { - const response = await api.fetchApi('/model_linker/civitai-search', { + const response = await api.fetchApi('/model_resolver/civitai-search', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ @@ -561,7 +561,7 @@ export const modelInfoMethods = { this.updateInfoDialogError(dialog, 'Model not found on CivitAI'); } } catch (e) { - console.error('Model Linker: Error fetching model info:', e); + console.error('Model Resolver: Error fetching model info:', e); this.updateInfoDialogError(dialog, 'Error fetching info'); } }, @@ -570,8 +570,8 @@ export const modelInfoMethods = { * Update the info dialog with data */ updateInfoDialogWithData(dialog, data) { - const loadingDiv = dialog.querySelector('.ml-info-dialog-loading'); - const bodyDiv = dialog.querySelector('.ml-info-dialog-body'); + const loadingDiv = dialog.querySelector('.mr-info-dialog-loading'); + const bodyDiv = dialog.querySelector('.mr-info-dialog-body'); this.bindInfoDialogInteractions(dialog); if (loadingDiv) loadingDiv.style.display = 'none'; @@ -583,7 +583,7 @@ export const modelInfoMethods = { } // Update title - const titleEl = dialog.querySelector('.ml-info-dialog-title'); + const titleEl = dialog.querySelector('.mr-info-dialog-title'); if (titleEl) { const modelName = data.model_name || data.modelName || 'Unknown Model'; const versionName = data.version_name || data.versionName || ''; @@ -591,54 +591,54 @@ export const modelInfoMethods = { } // Update type tag - const typeTag = dialog.querySelector('.ml-info-type'); + const typeTag = dialog.querySelector('.mr-info-type'); if (typeTag) { const modelType = data.model_type || data.modelType || ''; typeTag.textContent = modelType.toUpperCase(); - typeTag.className = `ml-info-tag ml-info-type ${this.getModelTypeColorClass(modelType)}`; + typeTag.className = `mr-info-tag mr-info-type ${this.getModelTypeColorClass(modelType)}`; } // Update base model tag - const baseModelTag = dialog.querySelector('.ml-info-basemodel'); + const baseModelTag = dialog.querySelector('.mr-info-basemodel'); if (baseModelTag) { const baseModel = data.base_model || data.baseModel || ''; baseModelTag.textContent = baseModel || ''; if (baseModel) { baseModelTag.style.display = ''; - baseModelTag.className = `ml-info-tag ml-info-basemodel -basemodel-${baseModel.toLowerCase().replace(/\s+/g, '-')}`; + baseModelTag.className = `mr-info-tag mr-info-basemodel -basemodel-${baseModel.toLowerCase().replace(/\s+/g, '-')}`; } else { baseModelTag.style.display = 'none'; } } // Update file - const fileEl = dialog.querySelector('.ml-info-file'); + const fileEl = dialog.querySelector('.mr-info-file'); if (fileEl && data.filename) { fileEl.textContent = data.filename; } // Update hash - const hashEl = dialog.querySelector('.ml-info-hash'); + const hashEl = dialog.querySelector('.mr-info-hash'); if (hashEl) { hashEl.textContent = data.sha256 || data.hash || ''; } // Update CivitAI link - const civitaiLinkEl = dialog.querySelector('.ml-info-civitai-link'); + const civitaiLinkEl = dialog.querySelector('.mr-info-civitai-link'); if (civitaiLinkEl) { if (data.url || data.version_url) { const url = data.version_url || data.url; civitaiLinkEl.innerHTML = ` - - ${getSvgIcon('civitai', 'currentColor', 'ml-info-civitai-logo')} + + ${getSvgIcon('civitai', 'currentColor', 'mr-info-civitai-logo')} View on Civitai `; } else { const searchName = data.model_name || data.modelName || 'Unknown'; civitaiLinkEl.innerHTML = ` - Model not found - + Model not found + ${this.getSearchIconHtml()} Search on CivitAI `; @@ -646,13 +646,13 @@ export const modelInfoMethods = { } // Update name - const nameEl = dialog.querySelector('.ml-info-name'); + const nameEl = dialog.querySelector('.mr-info-name'); if (nameEl) { nameEl.textContent = data.model_name || data.modelName || ''; } // Update base model row - const baseModelRowEl = dialog.querySelector('.ml-info-base-model'); + const baseModelRowEl = dialog.querySelector('.mr-info-base-model'); if (baseModelRowEl) { const baseModel = data.base_model || data.baseModel || ''; baseModelRowEl.textContent = baseModel; @@ -665,15 +665,15 @@ export const modelInfoMethods = { } // Update trained words - const trainedWordsEl = dialog.querySelector('.ml-info-trained-words'); + const trainedWordsEl = dialog.querySelector('.mr-info-trained-words'); if (trainedWordsEl) { const words = this.normalizeTrainedWords(data.trained_words || data.trainedWords || []); if (words.length > 0) { dialog._selectedTrainedWords = new Set(); - trainedWordsEl.innerHTML = `
${words.map(word => ` + trainedWordsEl.innerHTML = `
${words.map(word => ` -
-
-
Providers
-
- -
-
-
Saved only on this machine.
- +
+
Saved only on this machine.
+
-
-
-
-

Download Sources

+
+
+
+

Download Sources

-
-
-
+
+
+
${sourceDefaultsRows}
-