display_icons.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. """Icon management for consistent CLI display."""
  2. from __future__ import annotations
  3. from pathlib import Path
  4. from typing import ClassVar
  5. class IconManager:
  6. """Centralized icon management system for consistent CLI display.
  7. This class provides standardized icons for file types, status indicators,
  8. and UI elements. Icons use Nerd Font glyphs for consistent display.
  9. Categories:
  10. - File types: .yaml, .j2, .json, .md, etc.
  11. - Status: success, warning, error, info, skipped
  12. - UI elements: folders, config, locks, etc.
  13. """
  14. # File Type Icons
  15. FILE_FOLDER = "\uf07b"
  16. FILE_DEFAULT = "\uf15b"
  17. FILE_YAML = "\uf15c"
  18. FILE_JSON = "\ue60b"
  19. FILE_MARKDOWN = "\uf48a"
  20. FILE_JINJA2 = "\ue235"
  21. FILE_DOCKER = "\uf308"
  22. FILE_COMPOSE = "\uf308"
  23. FILE_SHELL = "\uf489"
  24. FILE_PYTHON = "\ue73c"
  25. FILE_TEXT = "\uf15c"
  26. # Status Indicators
  27. STATUS_SUCCESS = "\uf00c" # (check)
  28. STATUS_ERROR = "\uf00d" # (times/x)
  29. STATUS_WARNING = "\uf071" # (exclamation-triangle)
  30. STATUS_INFO = "\uf05a" # (info-circle)
  31. STATUS_SKIPPED = "\uf05e" # (ban/circle-slash)
  32. # UI Elements
  33. UI_CONFIG = "\ue5fc"
  34. UI_LOCK = "\uf084"
  35. UI_SETTINGS = "\uf013"
  36. UI_ARROW_RIGHT = "\uf061" # (arrow-right)
  37. UI_BULLET = "\uf111" # (circle)
  38. UI_LIBRARY_GIT = "\uf418" # (git icon)
  39. UI_LIBRARY_STATIC = "\uf07c" # (folder icon)
  40. # Shortcode Mappings (emoji-style codes to Nerd Font icons)
  41. # Format: ":code:" -> "\uf000"
  42. #
  43. # Usage:
  44. # 1. In regular text: ":mycode: Some text" - icon replaces shortcode inline
  45. # 2. In markdown lists: "- :mycode: List item" - icon replaces bullet with color
  46. #
  47. # To add new shortcodes:
  48. # 1. Add entry to this dict: ":mycode:": "\uf000"
  49. # 2. Use in template descriptions or markdown content
  50. # 3. Shortcodes are automatically replaced when markdown is rendered
  51. # 4. List items starting with shortcodes get colored icons instead of bullets
  52. #
  53. # Find Nerd Font codes at: https://www.nerdfonts.com/cheat-sheet
  54. SHORTCODES: ClassVar[dict[str, str]] = {
  55. ":warning:": "\uf071", # (exclamation-triangle)
  56. ":info:": "\uf05a", # (info-circle)
  57. ":check:": "\uf00c", # (check)
  58. ":error:": "\uf00d", # (times/x)
  59. ":lock:": "\uf084", # (lock)
  60. ":folder:": "\uf07b", # (folder)
  61. ":file:": "\uf15b", # (file)
  62. ":gear:": "\uf013", # (settings/gear)
  63. ":rocket:": "\uf135", # (rocket)
  64. ":star:": "\uf005", # (star)
  65. ":lightning:": "\uf0e7", # (bolt/lightning)
  66. ":cloud:": "\uf0c2", # (cloud)
  67. ":database:": "\uf1c0", # (database)
  68. ":network:": "\uf6ff", # (network)
  69. ":docker:": "\uf308", # (docker)
  70. ":kubernetes:": "\ue287", # (kubernetes/helm)
  71. }
  72. @classmethod
  73. def get_file_icon(cls, file_path: str | Path) -> str:
  74. """Get the appropriate icon for a file based on its extension or name.
  75. Args:
  76. file_path: Path to the file (can be string or Path object)
  77. Returns:
  78. Unicode icon character for the file type
  79. Examples:
  80. >>> IconManager.get_file_icon("config.yaml")
  81. '\uf15c'
  82. >>> IconManager.get_file_icon("template.j2")
  83. '\ue235'
  84. """
  85. if isinstance(file_path, str):
  86. file_path = Path(file_path)
  87. file_name = file_path.name.lower()
  88. suffix = file_path.suffix.lower()
  89. # Check for Docker Compose files
  90. compose_names = {
  91. "docker-compose.yml",
  92. "docker-compose.yaml",
  93. "compose.yml",
  94. "compose.yaml",
  95. }
  96. if file_name in compose_names or file_name.startswith("docker-compose"):
  97. return cls.FILE_DOCKER
  98. # Check by extension
  99. extension_map = {
  100. ".yaml": cls.FILE_YAML,
  101. ".yml": cls.FILE_YAML,
  102. ".json": cls.FILE_JSON,
  103. ".md": cls.FILE_MARKDOWN,
  104. ".j2": cls.FILE_JINJA2,
  105. ".sh": cls.FILE_SHELL,
  106. ".py": cls.FILE_PYTHON,
  107. ".txt": cls.FILE_TEXT,
  108. }
  109. return extension_map.get(suffix, cls.FILE_DEFAULT)
  110. @classmethod
  111. def get_status_icon(cls, status: str) -> str:
  112. """Get the appropriate icon for a status indicator.
  113. Args:
  114. status: Status type (success, error, warning, info, skipped)
  115. Returns:
  116. Unicode icon character for the status
  117. Examples:
  118. >>> IconManager.get_status_icon("success")
  119. '✓'
  120. >>> IconManager.get_status_icon("warning")
  121. '⚠'
  122. """
  123. status_map = {
  124. "success": cls.STATUS_SUCCESS,
  125. "error": cls.STATUS_ERROR,
  126. "warning": cls.STATUS_WARNING,
  127. "info": cls.STATUS_INFO,
  128. "skipped": cls.STATUS_SKIPPED,
  129. }
  130. return status_map.get(status.lower(), cls.STATUS_INFO)
  131. @classmethod
  132. def folder(cls) -> str:
  133. """Get the folder icon."""
  134. return cls.FILE_FOLDER
  135. @classmethod
  136. def config(cls) -> str:
  137. """Get the config icon."""
  138. return cls.UI_CONFIG
  139. @classmethod
  140. def lock(cls) -> str:
  141. """Get the lock icon (for sensitive variables)."""
  142. return cls.UI_LOCK
  143. @classmethod
  144. def arrow_right(cls) -> str:
  145. """Get the right arrow icon (for showing transitions/changes)."""
  146. return cls.UI_ARROW_RIGHT
  147. @classmethod
  148. def replace_shortcodes(cls, text: str) -> str:
  149. """Replace emoji-style shortcodes with Nerd Font icons.
  150. Args:
  151. text: Text containing shortcodes like :warning:, :info:, etc.
  152. Returns:
  153. Text with shortcodes replaced by Nerd Font icons
  154. Examples:
  155. >>> IconManager.replace_shortcodes(":warning: This is a warning")
  156. ' This is a warning'
  157. >>> IconManager.replace_shortcodes(":docker: :kubernetes: Stack")
  158. ' Stack'
  159. """
  160. result = text
  161. for shortcode, icon in cls.SHORTCODES.items():
  162. result = result.replace(shortcode, icon)
  163. return result