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}
-