@robot-admin/naive-ui-components 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. package/dist/C_ActionBar.cjs +1 -5
  2. package/dist/C_ActionBar.js +1 -4
  3. package/dist/C_ActionBar.js.map +1 -0
  4. package/dist/C_ActionBar2.js +1 -195
  5. package/dist/C_ActionBar2.js.map +1 -1
  6. package/dist/C_AntV.cjs +1 -8
  7. package/dist/C_AntV.js +1 -4
  8. package/dist/C_AntV.js.map +1 -0
  9. package/dist/C_AntV2.js +4 -3149
  10. package/dist/C_AntV2.js.map +1 -1
  11. package/dist/C_Barcode.cjs +1 -4
  12. package/dist/C_Barcode.js +1 -3
  13. package/dist/C_Barcode.js.map +1 -0
  14. package/dist/C_Barcode2.js +1 -67
  15. package/dist/C_Barcode2.js.map +1 -1
  16. package/dist/C_Captcha.cjs +1 -4
  17. package/dist/C_Captcha.js +1 -3
  18. package/dist/C_Captcha.js.map +1 -0
  19. package/dist/C_Captcha2.js +1 -154
  20. package/dist/C_Captcha2.js.map +1 -1
  21. package/dist/C_Cascade.cjs +1 -4
  22. package/dist/C_Cascade.js +1 -3
  23. package/dist/C_Cascade.js.map +1 -0
  24. package/dist/C_Cascade2.js +1 -102
  25. package/dist/C_Cascade2.js.map +1 -1
  26. package/dist/C_City.cjs +1 -4
  27. package/dist/C_City.js +1 -3
  28. package/dist/C_City.js.map +1 -0
  29. package/dist/C_City2.js +1 -840
  30. package/dist/C_City2.js.map +1 -1
  31. package/dist/C_Code.cjs +1 -5
  32. package/dist/C_Code.js +1 -4
  33. package/dist/C_Code.js.map +1 -0
  34. package/dist/C_Code2.js +1 -346
  35. package/dist/C_Code2.js.map +1 -1
  36. package/dist/C_CollapsePanel.cjs +1 -6
  37. package/dist/C_CollapsePanel.js +1 -4
  38. package/dist/C_CollapsePanel.js.map +1 -0
  39. package/dist/C_CollapsePanel2.js +1 -318
  40. package/dist/C_CollapsePanel2.js.map +1 -1
  41. package/dist/C_Cron.cjs +1 -15
  42. package/dist/C_Cron.js +1 -4
  43. package/dist/C_Cron.js.map +1 -0
  44. package/dist/C_Cron2.js +1 -1209
  45. package/dist/C_Cron2.js.map +1 -1
  46. package/dist/C_Date.cjs +1 -4
  47. package/dist/C_Date.js +1 -3
  48. package/dist/C_Date.js.map +1 -0
  49. package/dist/C_Date2.js +1 -218
  50. package/dist/C_Date2.js.map +1 -1
  51. package/dist/C_Draggable.cjs +1 -5
  52. package/dist/C_Draggable.js +1 -3
  53. package/dist/C_Draggable.js.map +1 -0
  54. package/dist/C_Draggable2.js +1 -294
  55. package/dist/C_Draggable2.js.map +1 -1
  56. package/dist/C_Editor.cjs +1 -4
  57. package/dist/C_Editor.js +1 -3
  58. package/dist/C_Editor.js.map +1 -0
  59. package/dist/C_Editor2.js +1 -159
  60. package/dist/C_Editor2.js.map +1 -1
  61. package/dist/C_FilePreview.cjs +1 -7
  62. package/dist/C_FilePreview.js +1 -4
  63. package/dist/C_FilePreview.js.map +1 -0
  64. package/dist/C_FilePreview2.js +1 -1031
  65. package/dist/C_FilePreview2.js.map +1 -1
  66. package/dist/C_Form.cjs +1 -16
  67. package/dist/C_Form.js +1 -5
  68. package/dist/C_Form.js.map +1 -0
  69. package/dist/C_Form2.js +1 -2569
  70. package/dist/C_Form2.js.map +1 -1
  71. package/dist/C_FormSearch.cjs +1 -6
  72. package/dist/C_FormSearch.js +1 -3
  73. package/dist/C_FormSearch.js.map +1 -0
  74. package/dist/C_FormSearch2.js +1 -355
  75. package/dist/C_FormSearch2.js.map +1 -1
  76. package/dist/C_FormulaEditor.cjs +1 -13
  77. package/dist/C_FormulaEditor.js +1 -4
  78. package/dist/C_FormulaEditor.js.map +1 -0
  79. package/dist/C_FormulaEditor2.js +1 -1432
  80. package/dist/C_FormulaEditor2.js.map +1 -1
  81. package/dist/C_FullCalendar.cjs +1 -9
  82. package/dist/C_FullCalendar.js +1 -3
  83. package/dist/C_FullCalendar.js.map +1 -0
  84. package/dist/C_FullCalendar2.js +1 -376
  85. package/dist/C_FullCalendar2.js.map +1 -1
  86. package/dist/C_GlobalSearch.cjs +1 -5
  87. package/dist/C_GlobalSearch.js +1 -3
  88. package/dist/C_GlobalSearch.js.map +1 -0
  89. package/dist/C_GlobalSearch2.js +1 -335
  90. package/dist/C_GlobalSearch2.js.map +1 -1
  91. package/dist/C_Guide.cjs +1 -5
  92. package/dist/C_Guide.js +1 -4
  93. package/dist/C_Guide.js.map +1 -0
  94. package/dist/C_Guide2.js +1 -60
  95. package/dist/C_Guide2.js.map +1 -1
  96. package/dist/C_Icon.cjs +1 -4
  97. package/dist/C_Icon.js +1 -3
  98. package/dist/C_Icon.js.map +1 -0
  99. package/dist/C_Icon2.js +1 -285
  100. package/dist/C_Icon2.js.map +1 -1
  101. package/dist/C_ImageCropper.cjs +1 -6
  102. package/dist/C_ImageCropper.js +1 -4
  103. package/dist/C_ImageCropper.js.map +1 -0
  104. package/dist/C_ImageCropper2.js +1 -722
  105. package/dist/C_ImageCropper2.js.map +1 -1
  106. package/dist/C_Language.cjs +1 -5
  107. package/dist/C_Language.js +1 -4
  108. package/dist/C_Language.js.map +1 -0
  109. package/dist/C_Language2.js +1 -78
  110. package/dist/C_Language2.js.map +1 -1
  111. package/dist/C_Map.cjs +1 -7
  112. package/dist/C_Map.js +1 -3
  113. package/dist/C_Map.js.map +1 -0
  114. package/dist/C_Map2.js +1 -198
  115. package/dist/C_Map2.js.map +1 -1
  116. package/dist/C_Markdown.cjs +1 -4
  117. package/dist/C_Markdown.js +1 -3
  118. package/dist/C_Markdown.js.map +1 -0
  119. package/dist/C_Markdown2.js +1 -185
  120. package/dist/C_Markdown2.js.map +1 -1
  121. package/dist/C_NotificationCenter.cjs +1 -20
  122. package/dist/C_NotificationCenter.js +1 -4
  123. package/dist/C_NotificationCenter.js.map +1 -0
  124. package/dist/C_NotificationCenter2.js +1 -1383
  125. package/dist/C_NotificationCenter2.js.map +1 -1
  126. package/dist/C_Progress.cjs +1 -4
  127. package/dist/C_Progress.js +1 -3
  128. package/dist/C_Progress.js.map +1 -0
  129. package/dist/C_Progress2.js +1 -102
  130. package/dist/C_Progress2.js.map +1 -1
  131. package/dist/C_QRCode.cjs +1 -5
  132. package/dist/C_QRCode.js +1 -3
  133. package/dist/C_QRCode.js.map +1 -0
  134. package/dist/C_QRCode2.js +1 -217
  135. package/dist/C_QRCode2.js.map +1 -1
  136. package/dist/C_Signature.cjs +1 -8
  137. package/dist/C_Signature.js +1 -4
  138. package/dist/C_Signature.js.map +1 -0
  139. package/dist/C_Signature2.js +1 -617
  140. package/dist/C_Signature2.js.map +1 -1
  141. package/dist/C_SplitPane.cjs +1 -6
  142. package/dist/C_SplitPane.js +1 -4
  143. package/dist/C_SplitPane.js.map +1 -0
  144. package/dist/C_SplitPane2.js +1 -355
  145. package/dist/C_SplitPane2.js.map +1 -1
  146. package/dist/C_Steps.cjs +1 -4
  147. package/dist/C_Steps.js +1 -3
  148. package/dist/C_Steps.js.map +1 -0
  149. package/dist/C_Steps2.js +1 -81
  150. package/dist/C_Steps2.js.map +1 -1
  151. package/dist/C_Table.cjs +1 -20
  152. package/dist/C_Table.js +1 -6
  153. package/dist/C_Table.js.map +1 -0
  154. package/dist/C_Table2.js +1 -3023
  155. package/dist/C_Table2.js.map +1 -1
  156. package/dist/C_Theme.cjs +1 -5
  157. package/dist/C_Theme.js +1 -4
  158. package/dist/C_Theme.js.map +1 -0
  159. package/dist/C_Theme2.js +1 -63
  160. package/dist/C_Theme2.js.map +1 -1
  161. package/dist/C_Time.cjs +1 -5
  162. package/dist/C_Time.js +1 -3
  163. package/dist/C_Time.js.map +1 -0
  164. package/dist/C_Time2.js +1 -198
  165. package/dist/C_Time2.js.map +1 -1
  166. package/dist/C_Tree.cjs +1 -7
  167. package/dist/C_Tree.js +1 -4
  168. package/dist/C_Tree.js.map +1 -0
  169. package/dist/C_Tree2.js +1 -440
  170. package/dist/C_Tree2.js.map +1 -1
  171. package/dist/C_Upload.cjs +1 -12
  172. package/dist/C_Upload.js +1 -4
  173. package/dist/C_Upload.js.map +1 -0
  174. package/dist/C_Upload2.js +2 -1365
  175. package/dist/C_Upload2.js.map +1 -1
  176. package/dist/C_VideoPlayer.cjs +1 -23
  177. package/dist/C_VideoPlayer.js +1 -3
  178. package/dist/C_VideoPlayer.js.map +1 -0
  179. package/dist/C_VideoPlayer2.js +3 -1932
  180. package/dist/C_VideoPlayer2.js.map +1 -1
  181. package/dist/C_VtableGantt.cjs +1 -6
  182. package/dist/C_VtableGantt.js +1 -4
  183. package/dist/C_VtableGantt.js.map +1 -0
  184. package/dist/C_VtableGantt2.js +1 -872
  185. package/dist/C_VtableGantt2.js.map +1 -1
  186. package/dist/C_WaterFall.cjs +1 -13
  187. package/dist/C_WaterFall.js +1 -3
  188. package/dist/C_WaterFall.js.map +1 -0
  189. package/dist/C_WaterFall2.js +1 -364
  190. package/dist/C_WaterFall2.js.map +1 -1
  191. package/dist/C_WorkFlow.cjs +1 -8
  192. package/dist/C_WorkFlow.js +1 -4
  193. package/dist/C_WorkFlow.js.map +1 -0
  194. package/dist/C_WorkFlow2.js +1 -1983
  195. package/dist/C_WorkFlow2.js.map +1 -1
  196. package/dist/chunk.js +1 -18
  197. package/dist/city.js +1 -4816
  198. package/dist/constants.d.ts +2 -2
  199. package/dist/constants2.d.ts +3 -3
  200. package/dist/constants3.d.ts +3 -3
  201. package/dist/constants4.d.ts +5 -5
  202. package/dist/constants5.d.ts +2 -2
  203. package/dist/data.d.ts +1 -1
  204. package/dist/export-helper.js +1 -9
  205. package/dist/index.cjs +2 -413
  206. package/dist/index.cjs.map +1 -0
  207. package/dist/index.d.cts +1 -2
  208. package/dist/index.d.ts +1 -2
  209. package/dist/index.js +1 -231
  210. package/dist/index.js.map +1 -1
  211. package/dist/index.vue.d.ts +2 -2
  212. package/dist/index10.vue.d.ts +5 -5
  213. package/dist/index12.vue.d.ts +3 -3
  214. package/dist/index13.vue.d.ts +3 -3
  215. package/dist/index14.vue.d.ts +3 -3
  216. package/dist/index16.vue.d.ts +3 -3
  217. package/dist/index3.vue.d.ts +3 -3
  218. package/dist/index5.vue.d.ts +1 -1
  219. package/dist/index7.vue.d.ts +4 -4
  220. package/dist/index8.vue.d.ts +2 -2
  221. package/dist/resolver.cjs +2 -89
  222. package/dist/resolver.cjs.map +1 -0
  223. package/dist/resolver.js +1 -86
  224. package/dist/resolver.js.map +1 -1
  225. package/dist/storage.js +1 -30
  226. package/dist/storage.js.map +1 -1
  227. package/dist/useCollapsePanel.d.ts +2 -2
  228. package/dist/useCropperCore.d.ts +8 -8
  229. package/dist/useDraggableLayout.d.ts +4 -4
  230. package/dist/useDynamicFormState.d.ts +7 -7
  231. package/dist/useEdgeInteraction.d.ts +1 -1
  232. package/dist/useFullscreen.d.ts +2 -2
  233. package/dist/useInfiniteScroll.d.ts +1 -1
  234. package/dist/useModalEdit.d.ts +1 -1
  235. package/dist/useQRCode.d.ts +3 -3
  236. package/dist/useSearchState.d.ts +2 -2
  237. package/dist/useSignatureHistory.d.ts +1 -1
  238. package/dist/useSplitResize.d.ts +6 -6
  239. package/dist/useTimeSelection.d.ts +2 -2
  240. package/dist/useTreeOperations.d.ts +6 -6
  241. package/dist/useWorkflowValidation.d.ts +4 -4
  242. package/package.json +1 -2
  243. package/dist/constants.d.ts.map +0 -1
  244. package/dist/constants2.d.ts.map +0 -1
  245. package/dist/constants3.d.ts.map +0 -1
  246. package/dist/constants4.d.ts.map +0 -1
  247. package/dist/constants5.d.ts.map +0 -1
  248. package/dist/data.d.ts.map +0 -1
  249. package/dist/index.d.cts.map +0 -1
  250. package/dist/index.d.ts.map +0 -1
  251. package/dist/index.vue.d.ts.map +0 -1
  252. package/dist/index10.vue.d.ts.map +0 -1
  253. package/dist/index11.vue.d.ts.map +0 -1
  254. package/dist/index12.vue.d.ts.map +0 -1
  255. package/dist/index13.vue.d.ts.map +0 -1
  256. package/dist/index14.vue.d.ts.map +0 -1
  257. package/dist/index15.vue.d.ts.map +0 -1
  258. package/dist/index16.vue.d.ts.map +0 -1
  259. package/dist/index2.vue.d.ts.map +0 -1
  260. package/dist/index3.vue.d.ts.map +0 -1
  261. package/dist/index4.vue.d.ts.map +0 -1
  262. package/dist/index5.vue.d.ts.map +0 -1
  263. package/dist/index6.vue.d.ts.map +0 -1
  264. package/dist/index7.vue.d.ts.map +0 -1
  265. package/dist/index8.vue.d.ts.map +0 -1
  266. package/dist/index9.vue.d.ts.map +0 -1
  267. package/dist/resolver.d.cts.map +0 -1
  268. package/dist/resolver.d.ts.map +0 -1
  269. package/dist/useCalendarEvents.d.ts.map +0 -1
  270. package/dist/useCollapsePanel.d.ts.map +0 -1
  271. package/dist/useCropperCore.d.ts.map +0 -1
  272. package/dist/useDraggableLayout.d.ts.map +0 -1
  273. package/dist/useDynamicFormState.d.ts.map +0 -1
  274. package/dist/useEdgeInteraction.d.ts.map +0 -1
  275. package/dist/useFullscreen.d.ts.map +0 -1
  276. package/dist/useGlobalSearch.d.ts.map +0 -1
  277. package/dist/useInfiniteScroll.d.ts.map +0 -1
  278. package/dist/useModalEdit.d.ts.map +0 -1
  279. package/dist/useQRCode.d.ts.map +0 -1
  280. package/dist/useSearchState.d.ts.map +0 -1
  281. package/dist/useSignatureHistory.d.ts.map +0 -1
  282. package/dist/useSplitResize.d.ts.map +0 -1
  283. package/dist/useTimeSelection.d.ts.map +0 -1
  284. package/dist/useTreeOperations.d.ts.map +0 -1
  285. package/dist/useWorkflowValidation.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"C_City2.js","names":["modelValue","placeholder","showLetters"],"sources":["../src/components/C_City/province.json","../src/components/C_City/index.vue","../src/components/C_City/index.vue","../src/components/C_City/index.vue"],"sourcesContent":["","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-30\r\n * @Description: 城市选择器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NPopover\r\n v-model:show=\"visible\"\r\n placement=\"bottom-start\"\r\n :width=\"430\"\r\n trigger=\"click\"\r\n :show-arrow=\"false\"\r\n >\r\n <template #trigger>\r\n <slot name=\"trigger\" :value=\"modelValue\" :visible=\"visible\">\r\n <div class=\"city-selector-trigger\">\r\n <span class=\"city-selector-trigger__text\">{{\r\n modelValue || placeholder\r\n }}</span>\r\n </div>\r\n </slot>\r\n </template>\r\n\r\n <div class=\"city-selector-content\">\r\n <div class=\"city-selector-header\">\r\n <NRadioGroup v-model:value=\"radioValue\" size=\"small\">\r\n <NRadioButton value=\"city\">按城市</NRadioButton>\r\n <NRadioButton value=\"province\">按省份</NRadioButton>\r\n </NRadioGroup>\r\n <NSelect\r\n v-model:value=\"searchValue\"\r\n class=\"city-selector-search\"\r\n :options=\"searchOptions\"\r\n filterable\r\n clearable\r\n placeholder=\"搜索城市\"\r\n @update:value=\"handleSearchSelect\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"showLetters\" class=\"city-selector-letters\">\r\n <span\r\n v-for=\"letter in letters\"\r\n :key=\"letter\"\r\n class=\"city-selector-letter\"\r\n @click=\"scrollToLetter(letter)\"\r\n >\r\n {{ letter }}\r\n </span>\r\n </div>\r\n\r\n <NScrollbar class=\"city-selector-body\">\r\n <div v-if=\"radioValue === 'city'\" class=\"city-list\">\r\n <div\r\n v-for=\"(cities, letter) in cityDataByLetter\"\r\n :key=\"letter\"\r\n :id=\"`letter-${letter}`\"\r\n class=\"city-group\"\r\n >\r\n <div class=\"city-group__letter\">{{ letter }}:</div>\r\n <div class=\"city-group__cities\">\r\n <span\r\n v-for=\"(city, index) in cities\"\r\n :key=\"`${letter}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city.name }\"\r\n @click=\"handleCitySelect(city.name)\"\r\n >\r\n {{ city.name }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div v-else class=\"province-list\">\r\n <div\r\n v-for=\"province in allProvinces\"\r\n :key=\"province.id\"\r\n :id=\"`letter-${province.id}`\"\r\n class=\"province-group\"\r\n >\r\n <div class=\"province-group__name\">{{ province.name }}:</div>\r\n <div class=\"province-group__cities\">\r\n <span\r\n v-for=\"(city, index) in province.data\"\r\n :key=\"`${province.id}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city }\"\r\n @click=\"handleCitySelect(city)\"\r\n >\r\n {{ city }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </NScrollbar>\r\n </div>\r\n </NPopover>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted } from \"vue\";\r\nimport {\r\n NPopover,\r\n NRadioGroup,\r\n NRadioButton,\r\n NSelect,\r\n NScrollbar,\r\n} from \"naive-ui\";\r\nimport type { SelectOption } from \"naive-ui\";\r\nimport provinceData from \"./province.json\";\r\n\r\ndefineOptions({ name: \"C_City\" });\r\n\r\ninterface CityItem {\r\n id: number;\r\n spell: string;\r\n name: string;\r\n}\r\n\r\n// 城市数据懒加载(83KB JSON 仅在组件挂载时加载)\r\nconst cityData = ref<{ cities: Record<string, CityItem[]> } | null>(null);\r\n\r\nonMounted(async () => {\r\n const mod = await import(\"./city.json\");\r\n cityData.value = mod.default ?? mod;\r\n});\r\n\r\ninterface ProvinceItem {\r\n id?: string;\r\n name: string;\r\n data: string[];\r\n}\r\n\r\ninterface Props {\r\n modelValue?: string;\r\n placeholder?: string;\r\n showLetters?: boolean;\r\n}\r\n\r\ninterface Emits {\r\n (e: \"update:modelValue\", value: string): void;\r\n (e: \"change\", value: string): void;\r\n}\r\n\r\nwithDefaults(defineProps<Props>(), {\r\n placeholder: \"请选择城市\",\r\n showLetters: true,\r\n});\r\n\r\nconst emit = defineEmits<Emits>();\r\n\r\nconst visible = ref(false);\r\nconst radioValue = ref<\"city\" | \"province\">(\"city\");\r\nconst searchValue = ref(\"\");\r\n\r\nconst allProvinces = computed(() => {\r\n const provinces: ProvinceItem[] = [];\r\n Object.values(provinceData).forEach((group) => {\r\n provinces.push(...(group as ProvinceItem[]));\r\n });\r\n return provinces;\r\n});\r\n\r\nconst cityDataByLetter = computed(() => {\r\n if (cityData.value?.cities) {\r\n return cityData.value.cities;\r\n }\r\n // 数据未加载时,从省份数据生成城市索引作为 fallback\r\n const cities: Record<string, CityItem[]> = {};\r\n let cityId = 1;\r\n const citySet = new Set<string>();\r\n allProvinces.value.forEach((province) => {\r\n province.data.forEach((cityName) => {\r\n citySet.add(cityName);\r\n });\r\n });\r\n Array.from(citySet).forEach((cityName) => {\r\n const letter = cityName[0].toUpperCase();\r\n if (!cities[letter]) cities[letter] = [];\r\n cities[letter].push({ id: cityId++, name: cityName, spell: \"\" });\r\n });\r\n const sortedCities: Record<string, CityItem[]> = {};\r\n Object.keys(cities)\r\n .sort()\r\n .forEach((letter) => {\r\n sortedCities[letter] = cities[letter].sort((a, b) =>\r\n a.name.localeCompare(b.name, \"zh-CN\"),\r\n );\r\n });\r\n return sortedCities;\r\n});\r\n\r\nconst letters = computed(() => {\r\n if (radioValue.value === \"city\") {\r\n return Object.keys(cityDataByLetter.value).sort();\r\n } else {\r\n const provinceLetters = new Set<string>();\r\n Object.keys(provinceData).forEach((key) => {\r\n if (key !== \"直辖市\" && key !== \"港澳\") {\r\n provinceLetters.add(key);\r\n }\r\n });\r\n const result = Array.from(provinceLetters).sort();\r\n result.push(\"直辖市\", \"港澳\");\r\n return result;\r\n }\r\n});\r\n\r\nconst searchOptions = computed((): SelectOption[] => {\r\n if (radioValue.value === \"city\") {\r\n const options: SelectOption[] = [];\r\n Object.values(cityDataByLetter.value).forEach((cities) => {\r\n (cities as CityItem[]).forEach((city) => {\r\n options.push({\r\n label: city.name,\r\n value: city.name,\r\n });\r\n });\r\n });\r\n return options;\r\n } else {\r\n return allProvinces.value.flatMap((province) =>\r\n province.data.map((city) => ({\r\n label: `${city} (${province.name})`,\r\n value: city,\r\n })),\r\n );\r\n }\r\n});\r\n\r\nconst handleCitySelect = (cityName: string): void => {\r\n emit(\"update:modelValue\", cityName);\r\n emit(\"change\", cityName);\r\n visible.value = false;\r\n};\r\n\r\nconst handleSearchSelect = (value: string): void => {\r\n if (value) {\r\n handleCitySelect(value);\r\n searchValue.value = \"\";\r\n }\r\n};\r\n\r\nconst scrollToLetter = (letter: string): void => {\r\n const element = document.getElementById(`letter-${letter}`);\r\n if (element) {\r\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-30\r\n * @Description: 城市选择器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NPopover\r\n v-model:show=\"visible\"\r\n placement=\"bottom-start\"\r\n :width=\"430\"\r\n trigger=\"click\"\r\n :show-arrow=\"false\"\r\n >\r\n <template #trigger>\r\n <slot name=\"trigger\" :value=\"modelValue\" :visible=\"visible\">\r\n <div class=\"city-selector-trigger\">\r\n <span class=\"city-selector-trigger__text\">{{\r\n modelValue || placeholder\r\n }}</span>\r\n </div>\r\n </slot>\r\n </template>\r\n\r\n <div class=\"city-selector-content\">\r\n <div class=\"city-selector-header\">\r\n <NRadioGroup v-model:value=\"radioValue\" size=\"small\">\r\n <NRadioButton value=\"city\">按城市</NRadioButton>\r\n <NRadioButton value=\"province\">按省份</NRadioButton>\r\n </NRadioGroup>\r\n <NSelect\r\n v-model:value=\"searchValue\"\r\n class=\"city-selector-search\"\r\n :options=\"searchOptions\"\r\n filterable\r\n clearable\r\n placeholder=\"搜索城市\"\r\n @update:value=\"handleSearchSelect\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"showLetters\" class=\"city-selector-letters\">\r\n <span\r\n v-for=\"letter in letters\"\r\n :key=\"letter\"\r\n class=\"city-selector-letter\"\r\n @click=\"scrollToLetter(letter)\"\r\n >\r\n {{ letter }}\r\n </span>\r\n </div>\r\n\r\n <NScrollbar class=\"city-selector-body\">\r\n <div v-if=\"radioValue === 'city'\" class=\"city-list\">\r\n <div\r\n v-for=\"(cities, letter) in cityDataByLetter\"\r\n :key=\"letter\"\r\n :id=\"`letter-${letter}`\"\r\n class=\"city-group\"\r\n >\r\n <div class=\"city-group__letter\">{{ letter }}:</div>\r\n <div class=\"city-group__cities\">\r\n <span\r\n v-for=\"(city, index) in cities\"\r\n :key=\"`${letter}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city.name }\"\r\n @click=\"handleCitySelect(city.name)\"\r\n >\r\n {{ city.name }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div v-else class=\"province-list\">\r\n <div\r\n v-for=\"province in allProvinces\"\r\n :key=\"province.id\"\r\n :id=\"`letter-${province.id}`\"\r\n class=\"province-group\"\r\n >\r\n <div class=\"province-group__name\">{{ province.name }}:</div>\r\n <div class=\"province-group__cities\">\r\n <span\r\n v-for=\"(city, index) in province.data\"\r\n :key=\"`${province.id}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city }\"\r\n @click=\"handleCitySelect(city)\"\r\n >\r\n {{ city }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </NScrollbar>\r\n </div>\r\n </NPopover>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted } from \"vue\";\r\nimport {\r\n NPopover,\r\n NRadioGroup,\r\n NRadioButton,\r\n NSelect,\r\n NScrollbar,\r\n} from \"naive-ui\";\r\nimport type { SelectOption } from \"naive-ui\";\r\nimport provinceData from \"./province.json\";\r\n\r\ndefineOptions({ name: \"C_City\" });\r\n\r\ninterface CityItem {\r\n id: number;\r\n spell: string;\r\n name: string;\r\n}\r\n\r\n// 城市数据懒加载(83KB JSON 仅在组件挂载时加载)\r\nconst cityData = ref<{ cities: Record<string, CityItem[]> } | null>(null);\r\n\r\nonMounted(async () => {\r\n const mod = await import(\"./city.json\");\r\n cityData.value = mod.default ?? mod;\r\n});\r\n\r\ninterface ProvinceItem {\r\n id?: string;\r\n name: string;\r\n data: string[];\r\n}\r\n\r\ninterface Props {\r\n modelValue?: string;\r\n placeholder?: string;\r\n showLetters?: boolean;\r\n}\r\n\r\ninterface Emits {\r\n (e: \"update:modelValue\", value: string): void;\r\n (e: \"change\", value: string): void;\r\n}\r\n\r\nwithDefaults(defineProps<Props>(), {\r\n placeholder: \"请选择城市\",\r\n showLetters: true,\r\n});\r\n\r\nconst emit = defineEmits<Emits>();\r\n\r\nconst visible = ref(false);\r\nconst radioValue = ref<\"city\" | \"province\">(\"city\");\r\nconst searchValue = ref(\"\");\r\n\r\nconst allProvinces = computed(() => {\r\n const provinces: ProvinceItem[] = [];\r\n Object.values(provinceData).forEach((group) => {\r\n provinces.push(...(group as ProvinceItem[]));\r\n });\r\n return provinces;\r\n});\r\n\r\nconst cityDataByLetter = computed(() => {\r\n if (cityData.value?.cities) {\r\n return cityData.value.cities;\r\n }\r\n // 数据未加载时,从省份数据生成城市索引作为 fallback\r\n const cities: Record<string, CityItem[]> = {};\r\n let cityId = 1;\r\n const citySet = new Set<string>();\r\n allProvinces.value.forEach((province) => {\r\n province.data.forEach((cityName) => {\r\n citySet.add(cityName);\r\n });\r\n });\r\n Array.from(citySet).forEach((cityName) => {\r\n const letter = cityName[0].toUpperCase();\r\n if (!cities[letter]) cities[letter] = [];\r\n cities[letter].push({ id: cityId++, name: cityName, spell: \"\" });\r\n });\r\n const sortedCities: Record<string, CityItem[]> = {};\r\n Object.keys(cities)\r\n .sort()\r\n .forEach((letter) => {\r\n sortedCities[letter] = cities[letter].sort((a, b) =>\r\n a.name.localeCompare(b.name, \"zh-CN\"),\r\n );\r\n });\r\n return sortedCities;\r\n});\r\n\r\nconst letters = computed(() => {\r\n if (radioValue.value === \"city\") {\r\n return Object.keys(cityDataByLetter.value).sort();\r\n } else {\r\n const provinceLetters = new Set<string>();\r\n Object.keys(provinceData).forEach((key) => {\r\n if (key !== \"直辖市\" && key !== \"港澳\") {\r\n provinceLetters.add(key);\r\n }\r\n });\r\n const result = Array.from(provinceLetters).sort();\r\n result.push(\"直辖市\", \"港澳\");\r\n return result;\r\n }\r\n});\r\n\r\nconst searchOptions = computed((): SelectOption[] => {\r\n if (radioValue.value === \"city\") {\r\n const options: SelectOption[] = [];\r\n Object.values(cityDataByLetter.value).forEach((cities) => {\r\n (cities as CityItem[]).forEach((city) => {\r\n options.push({\r\n label: city.name,\r\n value: city.name,\r\n });\r\n });\r\n });\r\n return options;\r\n } else {\r\n return allProvinces.value.flatMap((province) =>\r\n province.data.map((city) => ({\r\n label: `${city} (${province.name})`,\r\n value: city,\r\n })),\r\n );\r\n }\r\n});\r\n\r\nconst handleCitySelect = (cityName: string): void => {\r\n emit(\"update:modelValue\", cityName);\r\n emit(\"change\", cityName);\r\n visible.value = false;\r\n};\r\n\r\nconst handleSearchSelect = (value: string): void => {\r\n if (value) {\r\n handleCitySelect(value);\r\n searchValue.value = \"\";\r\n }\r\n};\r\n\r\nconst scrollToLetter = (letter: string): void => {\r\n const element = document.getElementById(`letter-${letter}`);\r\n if (element) {\r\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-30\r\n * @Description: 城市选择器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NPopover\r\n v-model:show=\"visible\"\r\n placement=\"bottom-start\"\r\n :width=\"430\"\r\n trigger=\"click\"\r\n :show-arrow=\"false\"\r\n >\r\n <template #trigger>\r\n <slot name=\"trigger\" :value=\"modelValue\" :visible=\"visible\">\r\n <div class=\"city-selector-trigger\">\r\n <span class=\"city-selector-trigger__text\">{{\r\n modelValue || placeholder\r\n }}</span>\r\n </div>\r\n </slot>\r\n </template>\r\n\r\n <div class=\"city-selector-content\">\r\n <div class=\"city-selector-header\">\r\n <NRadioGroup v-model:value=\"radioValue\" size=\"small\">\r\n <NRadioButton value=\"city\">按城市</NRadioButton>\r\n <NRadioButton value=\"province\">按省份</NRadioButton>\r\n </NRadioGroup>\r\n <NSelect\r\n v-model:value=\"searchValue\"\r\n class=\"city-selector-search\"\r\n :options=\"searchOptions\"\r\n filterable\r\n clearable\r\n placeholder=\"搜索城市\"\r\n @update:value=\"handleSearchSelect\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"showLetters\" class=\"city-selector-letters\">\r\n <span\r\n v-for=\"letter in letters\"\r\n :key=\"letter\"\r\n class=\"city-selector-letter\"\r\n @click=\"scrollToLetter(letter)\"\r\n >\r\n {{ letter }}\r\n </span>\r\n </div>\r\n\r\n <NScrollbar class=\"city-selector-body\">\r\n <div v-if=\"radioValue === 'city'\" class=\"city-list\">\r\n <div\r\n v-for=\"(cities, letter) in cityDataByLetter\"\r\n :key=\"letter\"\r\n :id=\"`letter-${letter}`\"\r\n class=\"city-group\"\r\n >\r\n <div class=\"city-group__letter\">{{ letter }}:</div>\r\n <div class=\"city-group__cities\">\r\n <span\r\n v-for=\"(city, index) in cities\"\r\n :key=\"`${letter}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city.name }\"\r\n @click=\"handleCitySelect(city.name)\"\r\n >\r\n {{ city.name }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div v-else class=\"province-list\">\r\n <div\r\n v-for=\"province in allProvinces\"\r\n :key=\"province.id\"\r\n :id=\"`letter-${province.id}`\"\r\n class=\"province-group\"\r\n >\r\n <div class=\"province-group__name\">{{ province.name }}:</div>\r\n <div class=\"province-group__cities\">\r\n <span\r\n v-for=\"(city, index) in province.data\"\r\n :key=\"`${province.id}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city }\"\r\n @click=\"handleCitySelect(city)\"\r\n >\r\n {{ city }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </NScrollbar>\r\n </div>\r\n </NPopover>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted } from \"vue\";\r\nimport {\r\n NPopover,\r\n NRadioGroup,\r\n NRadioButton,\r\n NSelect,\r\n NScrollbar,\r\n} from \"naive-ui\";\r\nimport type { SelectOption } from \"naive-ui\";\r\nimport provinceData from \"./province.json\";\r\n\r\ndefineOptions({ name: \"C_City\" });\r\n\r\ninterface CityItem {\r\n id: number;\r\n spell: string;\r\n name: string;\r\n}\r\n\r\n// 城市数据懒加载(83KB JSON 仅在组件挂载时加载)\r\nconst cityData = ref<{ cities: Record<string, CityItem[]> } | null>(null);\r\n\r\nonMounted(async () => {\r\n const mod = await import(\"./city.json\");\r\n cityData.value = mod.default ?? mod;\r\n});\r\n\r\ninterface ProvinceItem {\r\n id?: string;\r\n name: string;\r\n data: string[];\r\n}\r\n\r\ninterface Props {\r\n modelValue?: string;\r\n placeholder?: string;\r\n showLetters?: boolean;\r\n}\r\n\r\ninterface Emits {\r\n (e: \"update:modelValue\", value: string): void;\r\n (e: \"change\", value: string): void;\r\n}\r\n\r\nwithDefaults(defineProps<Props>(), {\r\n placeholder: \"请选择城市\",\r\n showLetters: true,\r\n});\r\n\r\nconst emit = defineEmits<Emits>();\r\n\r\nconst visible = ref(false);\r\nconst radioValue = ref<\"city\" | \"province\">(\"city\");\r\nconst searchValue = ref(\"\");\r\n\r\nconst allProvinces = computed(() => {\r\n const provinces: ProvinceItem[] = [];\r\n Object.values(provinceData).forEach((group) => {\r\n provinces.push(...(group as ProvinceItem[]));\r\n });\r\n return provinces;\r\n});\r\n\r\nconst cityDataByLetter = computed(() => {\r\n if (cityData.value?.cities) {\r\n return cityData.value.cities;\r\n }\r\n // 数据未加载时,从省份数据生成城市索引作为 fallback\r\n const cities: Record<string, CityItem[]> = {};\r\n let cityId = 1;\r\n const citySet = new Set<string>();\r\n allProvinces.value.forEach((province) => {\r\n province.data.forEach((cityName) => {\r\n citySet.add(cityName);\r\n });\r\n });\r\n Array.from(citySet).forEach((cityName) => {\r\n const letter = cityName[0].toUpperCase();\r\n if (!cities[letter]) cities[letter] = [];\r\n cities[letter].push({ id: cityId++, name: cityName, spell: \"\" });\r\n });\r\n const sortedCities: Record<string, CityItem[]> = {};\r\n Object.keys(cities)\r\n .sort()\r\n .forEach((letter) => {\r\n sortedCities[letter] = cities[letter].sort((a, b) =>\r\n a.name.localeCompare(b.name, \"zh-CN\"),\r\n );\r\n });\r\n return sortedCities;\r\n});\r\n\r\nconst letters = computed(() => {\r\n if (radioValue.value === \"city\") {\r\n return Object.keys(cityDataByLetter.value).sort();\r\n } else {\r\n const provinceLetters = new Set<string>();\r\n Object.keys(provinceData).forEach((key) => {\r\n if (key !== \"直辖市\" && key !== \"港澳\") {\r\n provinceLetters.add(key);\r\n }\r\n });\r\n const result = Array.from(provinceLetters).sort();\r\n result.push(\"直辖市\", \"港澳\");\r\n return result;\r\n }\r\n});\r\n\r\nconst searchOptions = computed((): SelectOption[] => {\r\n if (radioValue.value === \"city\") {\r\n const options: SelectOption[] = [];\r\n Object.values(cityDataByLetter.value).forEach((cities) => {\r\n (cities as CityItem[]).forEach((city) => {\r\n options.push({\r\n label: city.name,\r\n value: city.name,\r\n });\r\n });\r\n });\r\n return options;\r\n } else {\r\n return allProvinces.value.flatMap((province) =>\r\n province.data.map((city) => ({\r\n label: `${city} (${province.name})`,\r\n value: city,\r\n })),\r\n );\r\n }\r\n});\r\n\r\nconst handleCitySelect = (cityName: string): void => {\r\n emit(\"update:modelValue\", cityName);\r\n emit(\"change\", cityName);\r\n visible.value = false;\r\n};\r\n\r\nconst handleSearchSelect = (value: string): void => {\r\n if (value) {\r\n handleCitySelect(value);\r\n searchValue.value = \"\";\r\n }\r\n};\r\n\r\nconst scrollToLetter = (letter: string): void => {\r\n const element = document.getElementById(`letter-${letter}`);\r\n if (element) {\r\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"C_City2.js","names":["modelValue","placeholder","showLetters"],"sources":["../src/components/C_City/province.json","../src/components/C_City/index.vue","../src/components/C_City/index.vue","../src/components/C_City/index.vue"],"sourcesContent":["","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-30\r\n * @Description: 城市选择器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NPopover\r\n v-model:show=\"visible\"\r\n placement=\"bottom-start\"\r\n :width=\"430\"\r\n trigger=\"click\"\r\n :show-arrow=\"false\"\r\n >\r\n <template #trigger>\r\n <slot name=\"trigger\" :value=\"modelValue\" :visible=\"visible\">\r\n <div class=\"city-selector-trigger\">\r\n <span class=\"city-selector-trigger__text\">{{\r\n modelValue || placeholder\r\n }}</span>\r\n </div>\r\n </slot>\r\n </template>\r\n\r\n <div class=\"city-selector-content\">\r\n <div class=\"city-selector-header\">\r\n <NRadioGroup v-model:value=\"radioValue\" size=\"small\">\r\n <NRadioButton value=\"city\">按城市</NRadioButton>\r\n <NRadioButton value=\"province\">按省份</NRadioButton>\r\n </NRadioGroup>\r\n <NSelect\r\n v-model:value=\"searchValue\"\r\n class=\"city-selector-search\"\r\n :options=\"searchOptions\"\r\n filterable\r\n clearable\r\n placeholder=\"搜索城市\"\r\n @update:value=\"handleSearchSelect\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"showLetters\" class=\"city-selector-letters\">\r\n <span\r\n v-for=\"letter in letters\"\r\n :key=\"letter\"\r\n class=\"city-selector-letter\"\r\n @click=\"scrollToLetter(letter)\"\r\n >\r\n {{ letter }}\r\n </span>\r\n </div>\r\n\r\n <NScrollbar class=\"city-selector-body\">\r\n <div v-if=\"radioValue === 'city'\" class=\"city-list\">\r\n <div\r\n v-for=\"(cities, letter) in cityDataByLetter\"\r\n :key=\"letter\"\r\n :id=\"`letter-${letter}`\"\r\n class=\"city-group\"\r\n >\r\n <div class=\"city-group__letter\">{{ letter }}:</div>\r\n <div class=\"city-group__cities\">\r\n <span\r\n v-for=\"(city, index) in cities\"\r\n :key=\"`${letter}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city.name }\"\r\n @click=\"handleCitySelect(city.name)\"\r\n >\r\n {{ city.name }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div v-else class=\"province-list\">\r\n <div\r\n v-for=\"province in allProvinces\"\r\n :key=\"province.id\"\r\n :id=\"`letter-${province.id}`\"\r\n class=\"province-group\"\r\n >\r\n <div class=\"province-group__name\">{{ province.name }}:</div>\r\n <div class=\"province-group__cities\">\r\n <span\r\n v-for=\"(city, index) in province.data\"\r\n :key=\"`${province.id}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city }\"\r\n @click=\"handleCitySelect(city)\"\r\n >\r\n {{ city }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </NScrollbar>\r\n </div>\r\n </NPopover>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted } from \"vue\";\r\nimport {\r\n NPopover,\r\n NRadioGroup,\r\n NRadioButton,\r\n NSelect,\r\n NScrollbar,\r\n} from \"naive-ui\";\r\nimport type { SelectOption } from \"naive-ui\";\r\nimport provinceData from \"./province.json\";\r\n\r\ndefineOptions({ name: \"C_City\" });\r\n\r\ninterface CityItem {\r\n id: number;\r\n spell: string;\r\n name: string;\r\n}\r\n\r\n// 城市数据懒加载(83KB JSON 仅在组件挂载时加载)\r\nconst cityData = ref<{ cities: Record<string, CityItem[]> } | null>(null);\r\n\r\nonMounted(async () => {\r\n const mod = await import(\"./city.json\");\r\n cityData.value = mod.default ?? mod;\r\n});\r\n\r\ninterface ProvinceItem {\r\n id?: string;\r\n name: string;\r\n data: string[];\r\n}\r\n\r\ninterface Props {\r\n modelValue?: string;\r\n placeholder?: string;\r\n showLetters?: boolean;\r\n}\r\n\r\ninterface Emits {\r\n (e: \"update:modelValue\", value: string): void;\r\n (e: \"change\", value: string): void;\r\n}\r\n\r\nwithDefaults(defineProps<Props>(), {\r\n placeholder: \"请选择城市\",\r\n showLetters: true,\r\n});\r\n\r\nconst emit = defineEmits<Emits>();\r\n\r\nconst visible = ref(false);\r\nconst radioValue = ref<\"city\" | \"province\">(\"city\");\r\nconst searchValue = ref(\"\");\r\n\r\nconst allProvinces = computed(() => {\r\n const provinces: ProvinceItem[] = [];\r\n Object.values(provinceData).forEach((group) => {\r\n provinces.push(...(group as ProvinceItem[]));\r\n });\r\n return provinces;\r\n});\r\n\r\nconst cityDataByLetter = computed(() => {\r\n if (cityData.value?.cities) {\r\n return cityData.value.cities;\r\n }\r\n // 数据未加载时,从省份数据生成城市索引作为 fallback\r\n const cities: Record<string, CityItem[]> = {};\r\n let cityId = 1;\r\n const citySet = new Set<string>();\r\n allProvinces.value.forEach((province) => {\r\n province.data.forEach((cityName) => {\r\n citySet.add(cityName);\r\n });\r\n });\r\n Array.from(citySet).forEach((cityName) => {\r\n const letter = cityName[0].toUpperCase();\r\n if (!cities[letter]) cities[letter] = [];\r\n cities[letter].push({ id: cityId++, name: cityName, spell: \"\" });\r\n });\r\n const sortedCities: Record<string, CityItem[]> = {};\r\n Object.keys(cities)\r\n .sort()\r\n .forEach((letter) => {\r\n sortedCities[letter] = cities[letter].sort((a, b) =>\r\n a.name.localeCompare(b.name, \"zh-CN\"),\r\n );\r\n });\r\n return sortedCities;\r\n});\r\n\r\nconst letters = computed(() => {\r\n if (radioValue.value === \"city\") {\r\n return Object.keys(cityDataByLetter.value).sort();\r\n } else {\r\n const provinceLetters = new Set<string>();\r\n Object.keys(provinceData).forEach((key) => {\r\n if (key !== \"直辖市\" && key !== \"港澳\") {\r\n provinceLetters.add(key);\r\n }\r\n });\r\n const result = Array.from(provinceLetters).sort();\r\n result.push(\"直辖市\", \"港澳\");\r\n return result;\r\n }\r\n});\r\n\r\nconst searchOptions = computed((): SelectOption[] => {\r\n if (radioValue.value === \"city\") {\r\n const options: SelectOption[] = [];\r\n Object.values(cityDataByLetter.value).forEach((cities) => {\r\n (cities as CityItem[]).forEach((city) => {\r\n options.push({\r\n label: city.name,\r\n value: city.name,\r\n });\r\n });\r\n });\r\n return options;\r\n } else {\r\n return allProvinces.value.flatMap((province) =>\r\n province.data.map((city) => ({\r\n label: `${city} (${province.name})`,\r\n value: city,\r\n })),\r\n );\r\n }\r\n});\r\n\r\nconst handleCitySelect = (cityName: string): void => {\r\n emit(\"update:modelValue\", cityName);\r\n emit(\"change\", cityName);\r\n visible.value = false;\r\n};\r\n\r\nconst handleSearchSelect = (value: string): void => {\r\n if (value) {\r\n handleCitySelect(value);\r\n searchValue.value = \"\";\r\n }\r\n};\r\n\r\nconst scrollToLetter = (letter: string): void => {\r\n const element = document.getElementById(`letter-${letter}`);\r\n if (element) {\r\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-30\r\n * @Description: 城市选择器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NPopover\r\n v-model:show=\"visible\"\r\n placement=\"bottom-start\"\r\n :width=\"430\"\r\n trigger=\"click\"\r\n :show-arrow=\"false\"\r\n >\r\n <template #trigger>\r\n <slot name=\"trigger\" :value=\"modelValue\" :visible=\"visible\">\r\n <div class=\"city-selector-trigger\">\r\n <span class=\"city-selector-trigger__text\">{{\r\n modelValue || placeholder\r\n }}</span>\r\n </div>\r\n </slot>\r\n </template>\r\n\r\n <div class=\"city-selector-content\">\r\n <div class=\"city-selector-header\">\r\n <NRadioGroup v-model:value=\"radioValue\" size=\"small\">\r\n <NRadioButton value=\"city\">按城市</NRadioButton>\r\n <NRadioButton value=\"province\">按省份</NRadioButton>\r\n </NRadioGroup>\r\n <NSelect\r\n v-model:value=\"searchValue\"\r\n class=\"city-selector-search\"\r\n :options=\"searchOptions\"\r\n filterable\r\n clearable\r\n placeholder=\"搜索城市\"\r\n @update:value=\"handleSearchSelect\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"showLetters\" class=\"city-selector-letters\">\r\n <span\r\n v-for=\"letter in letters\"\r\n :key=\"letter\"\r\n class=\"city-selector-letter\"\r\n @click=\"scrollToLetter(letter)\"\r\n >\r\n {{ letter }}\r\n </span>\r\n </div>\r\n\r\n <NScrollbar class=\"city-selector-body\">\r\n <div v-if=\"radioValue === 'city'\" class=\"city-list\">\r\n <div\r\n v-for=\"(cities, letter) in cityDataByLetter\"\r\n :key=\"letter\"\r\n :id=\"`letter-${letter}`\"\r\n class=\"city-group\"\r\n >\r\n <div class=\"city-group__letter\">{{ letter }}:</div>\r\n <div class=\"city-group__cities\">\r\n <span\r\n v-for=\"(city, index) in cities\"\r\n :key=\"`${letter}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city.name }\"\r\n @click=\"handleCitySelect(city.name)\"\r\n >\r\n {{ city.name }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div v-else class=\"province-list\">\r\n <div\r\n v-for=\"province in allProvinces\"\r\n :key=\"province.id\"\r\n :id=\"`letter-${province.id}`\"\r\n class=\"province-group\"\r\n >\r\n <div class=\"province-group__name\">{{ province.name }}:</div>\r\n <div class=\"province-group__cities\">\r\n <span\r\n v-for=\"(city, index) in province.data\"\r\n :key=\"`${province.id}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city }\"\r\n @click=\"handleCitySelect(city)\"\r\n >\r\n {{ city }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </NScrollbar>\r\n </div>\r\n </NPopover>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted } from \"vue\";\r\nimport {\r\n NPopover,\r\n NRadioGroup,\r\n NRadioButton,\r\n NSelect,\r\n NScrollbar,\r\n} from \"naive-ui\";\r\nimport type { SelectOption } from \"naive-ui\";\r\nimport provinceData from \"./province.json\";\r\n\r\ndefineOptions({ name: \"C_City\" });\r\n\r\ninterface CityItem {\r\n id: number;\r\n spell: string;\r\n name: string;\r\n}\r\n\r\n// 城市数据懒加载(83KB JSON 仅在组件挂载时加载)\r\nconst cityData = ref<{ cities: Record<string, CityItem[]> } | null>(null);\r\n\r\nonMounted(async () => {\r\n const mod = await import(\"./city.json\");\r\n cityData.value = mod.default ?? mod;\r\n});\r\n\r\ninterface ProvinceItem {\r\n id?: string;\r\n name: string;\r\n data: string[];\r\n}\r\n\r\ninterface Props {\r\n modelValue?: string;\r\n placeholder?: string;\r\n showLetters?: boolean;\r\n}\r\n\r\ninterface Emits {\r\n (e: \"update:modelValue\", value: string): void;\r\n (e: \"change\", value: string): void;\r\n}\r\n\r\nwithDefaults(defineProps<Props>(), {\r\n placeholder: \"请选择城市\",\r\n showLetters: true,\r\n});\r\n\r\nconst emit = defineEmits<Emits>();\r\n\r\nconst visible = ref(false);\r\nconst radioValue = ref<\"city\" | \"province\">(\"city\");\r\nconst searchValue = ref(\"\");\r\n\r\nconst allProvinces = computed(() => {\r\n const provinces: ProvinceItem[] = [];\r\n Object.values(provinceData).forEach((group) => {\r\n provinces.push(...(group as ProvinceItem[]));\r\n });\r\n return provinces;\r\n});\r\n\r\nconst cityDataByLetter = computed(() => {\r\n if (cityData.value?.cities) {\r\n return cityData.value.cities;\r\n }\r\n // 数据未加载时,从省份数据生成城市索引作为 fallback\r\n const cities: Record<string, CityItem[]> = {};\r\n let cityId = 1;\r\n const citySet = new Set<string>();\r\n allProvinces.value.forEach((province) => {\r\n province.data.forEach((cityName) => {\r\n citySet.add(cityName);\r\n });\r\n });\r\n Array.from(citySet).forEach((cityName) => {\r\n const letter = cityName[0].toUpperCase();\r\n if (!cities[letter]) cities[letter] = [];\r\n cities[letter].push({ id: cityId++, name: cityName, spell: \"\" });\r\n });\r\n const sortedCities: Record<string, CityItem[]> = {};\r\n Object.keys(cities)\r\n .sort()\r\n .forEach((letter) => {\r\n sortedCities[letter] = cities[letter].sort((a, b) =>\r\n a.name.localeCompare(b.name, \"zh-CN\"),\r\n );\r\n });\r\n return sortedCities;\r\n});\r\n\r\nconst letters = computed(() => {\r\n if (radioValue.value === \"city\") {\r\n return Object.keys(cityDataByLetter.value).sort();\r\n } else {\r\n const provinceLetters = new Set<string>();\r\n Object.keys(provinceData).forEach((key) => {\r\n if (key !== \"直辖市\" && key !== \"港澳\") {\r\n provinceLetters.add(key);\r\n }\r\n });\r\n const result = Array.from(provinceLetters).sort();\r\n result.push(\"直辖市\", \"港澳\");\r\n return result;\r\n }\r\n});\r\n\r\nconst searchOptions = computed((): SelectOption[] => {\r\n if (radioValue.value === \"city\") {\r\n const options: SelectOption[] = [];\r\n Object.values(cityDataByLetter.value).forEach((cities) => {\r\n (cities as CityItem[]).forEach((city) => {\r\n options.push({\r\n label: city.name,\r\n value: city.name,\r\n });\r\n });\r\n });\r\n return options;\r\n } else {\r\n return allProvinces.value.flatMap((province) =>\r\n province.data.map((city) => ({\r\n label: `${city} (${province.name})`,\r\n value: city,\r\n })),\r\n );\r\n }\r\n});\r\n\r\nconst handleCitySelect = (cityName: string): void => {\r\n emit(\"update:modelValue\", cityName);\r\n emit(\"change\", cityName);\r\n visible.value = false;\r\n};\r\n\r\nconst handleSearchSelect = (value: string): void => {\r\n if (value) {\r\n handleCitySelect(value);\r\n searchValue.value = \"\";\r\n }\r\n};\r\n\r\nconst scrollToLetter = (letter: string): void => {\r\n const element = document.getElementById(`letter-${letter}`);\r\n if (element) {\r\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-05-30\r\n * @Description: 城市选择器组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <NPopover\r\n v-model:show=\"visible\"\r\n placement=\"bottom-start\"\r\n :width=\"430\"\r\n trigger=\"click\"\r\n :show-arrow=\"false\"\r\n >\r\n <template #trigger>\r\n <slot name=\"trigger\" :value=\"modelValue\" :visible=\"visible\">\r\n <div class=\"city-selector-trigger\">\r\n <span class=\"city-selector-trigger__text\">{{\r\n modelValue || placeholder\r\n }}</span>\r\n </div>\r\n </slot>\r\n </template>\r\n\r\n <div class=\"city-selector-content\">\r\n <div class=\"city-selector-header\">\r\n <NRadioGroup v-model:value=\"radioValue\" size=\"small\">\r\n <NRadioButton value=\"city\">按城市</NRadioButton>\r\n <NRadioButton value=\"province\">按省份</NRadioButton>\r\n </NRadioGroup>\r\n <NSelect\r\n v-model:value=\"searchValue\"\r\n class=\"city-selector-search\"\r\n :options=\"searchOptions\"\r\n filterable\r\n clearable\r\n placeholder=\"搜索城市\"\r\n @update:value=\"handleSearchSelect\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"showLetters\" class=\"city-selector-letters\">\r\n <span\r\n v-for=\"letter in letters\"\r\n :key=\"letter\"\r\n class=\"city-selector-letter\"\r\n @click=\"scrollToLetter(letter)\"\r\n >\r\n {{ letter }}\r\n </span>\r\n </div>\r\n\r\n <NScrollbar class=\"city-selector-body\">\r\n <div v-if=\"radioValue === 'city'\" class=\"city-list\">\r\n <div\r\n v-for=\"(cities, letter) in cityDataByLetter\"\r\n :key=\"letter\"\r\n :id=\"`letter-${letter}`\"\r\n class=\"city-group\"\r\n >\r\n <div class=\"city-group__letter\">{{ letter }}:</div>\r\n <div class=\"city-group__cities\">\r\n <span\r\n v-for=\"(city, index) in cities\"\r\n :key=\"`${letter}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city.name }\"\r\n @click=\"handleCitySelect(city.name)\"\r\n >\r\n {{ city.name }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div v-else class=\"province-list\">\r\n <div\r\n v-for=\"province in allProvinces\"\r\n :key=\"province.id\"\r\n :id=\"`letter-${province.id}`\"\r\n class=\"province-group\"\r\n >\r\n <div class=\"province-group__name\">{{ province.name }}:</div>\r\n <div class=\"province-group__cities\">\r\n <span\r\n v-for=\"(city, index) in province.data\"\r\n :key=\"`${province.id}-${index}`\"\r\n class=\"city-item\"\r\n :class=\"{ 'is-active': modelValue === city }\"\r\n @click=\"handleCitySelect(city)\"\r\n >\r\n {{ city }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </NScrollbar>\r\n </div>\r\n </NPopover>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, onMounted } from \"vue\";\r\nimport {\r\n NPopover,\r\n NRadioGroup,\r\n NRadioButton,\r\n NSelect,\r\n NScrollbar,\r\n} from \"naive-ui\";\r\nimport type { SelectOption } from \"naive-ui\";\r\nimport provinceData from \"./province.json\";\r\n\r\ndefineOptions({ name: \"C_City\" });\r\n\r\ninterface CityItem {\r\n id: number;\r\n spell: string;\r\n name: string;\r\n}\r\n\r\n// 城市数据懒加载(83KB JSON 仅在组件挂载时加载)\r\nconst cityData = ref<{ cities: Record<string, CityItem[]> } | null>(null);\r\n\r\nonMounted(async () => {\r\n const mod = await import(\"./city.json\");\r\n cityData.value = mod.default ?? mod;\r\n});\r\n\r\ninterface ProvinceItem {\r\n id?: string;\r\n name: string;\r\n data: string[];\r\n}\r\n\r\ninterface Props {\r\n modelValue?: string;\r\n placeholder?: string;\r\n showLetters?: boolean;\r\n}\r\n\r\ninterface Emits {\r\n (e: \"update:modelValue\", value: string): void;\r\n (e: \"change\", value: string): void;\r\n}\r\n\r\nwithDefaults(defineProps<Props>(), {\r\n placeholder: \"请选择城市\",\r\n showLetters: true,\r\n});\r\n\r\nconst emit = defineEmits<Emits>();\r\n\r\nconst visible = ref(false);\r\nconst radioValue = ref<\"city\" | \"province\">(\"city\");\r\nconst searchValue = ref(\"\");\r\n\r\nconst allProvinces = computed(() => {\r\n const provinces: ProvinceItem[] = [];\r\n Object.values(provinceData).forEach((group) => {\r\n provinces.push(...(group as ProvinceItem[]));\r\n });\r\n return provinces;\r\n});\r\n\r\nconst cityDataByLetter = computed(() => {\r\n if (cityData.value?.cities) {\r\n return cityData.value.cities;\r\n }\r\n // 数据未加载时,从省份数据生成城市索引作为 fallback\r\n const cities: Record<string, CityItem[]> = {};\r\n let cityId = 1;\r\n const citySet = new Set<string>();\r\n allProvinces.value.forEach((province) => {\r\n province.data.forEach((cityName) => {\r\n citySet.add(cityName);\r\n });\r\n });\r\n Array.from(citySet).forEach((cityName) => {\r\n const letter = cityName[0].toUpperCase();\r\n if (!cities[letter]) cities[letter] = [];\r\n cities[letter].push({ id: cityId++, name: cityName, spell: \"\" });\r\n });\r\n const sortedCities: Record<string, CityItem[]> = {};\r\n Object.keys(cities)\r\n .sort()\r\n .forEach((letter) => {\r\n sortedCities[letter] = cities[letter].sort((a, b) =>\r\n a.name.localeCompare(b.name, \"zh-CN\"),\r\n );\r\n });\r\n return sortedCities;\r\n});\r\n\r\nconst letters = computed(() => {\r\n if (radioValue.value === \"city\") {\r\n return Object.keys(cityDataByLetter.value).sort();\r\n } else {\r\n const provinceLetters = new Set<string>();\r\n Object.keys(provinceData).forEach((key) => {\r\n if (key !== \"直辖市\" && key !== \"港澳\") {\r\n provinceLetters.add(key);\r\n }\r\n });\r\n const result = Array.from(provinceLetters).sort();\r\n result.push(\"直辖市\", \"港澳\");\r\n return result;\r\n }\r\n});\r\n\r\nconst searchOptions = computed((): SelectOption[] => {\r\n if (radioValue.value === \"city\") {\r\n const options: SelectOption[] = [];\r\n Object.values(cityDataByLetter.value).forEach((cities) => {\r\n (cities as CityItem[]).forEach((city) => {\r\n options.push({\r\n label: city.name,\r\n value: city.name,\r\n });\r\n });\r\n });\r\n return options;\r\n } else {\r\n return allProvinces.value.flatMap((province) =>\r\n province.data.map((city) => ({\r\n label: `${city} (${province.name})`,\r\n value: city,\r\n })),\r\n );\r\n }\r\n});\r\n\r\nconst handleCitySelect = (cityName: string): void => {\r\n emit(\"update:modelValue\", cityName);\r\n emit(\"change\", cityName);\r\n visible.value = false;\r\n};\r\n\r\nconst handleSearchSelect = (value: string): void => {\r\n if (value) {\r\n handleCitySelect(value);\r\n searchValue.value = \"\";\r\n }\r\n};\r\n\r\nconst scrollToLetter = (letter: string): void => {\r\n const element = document.getElementById(`letter-${letter}`);\r\n if (element) {\r\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n }\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":"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"}
package/dist/C_Code.cjs CHANGED
@@ -1,5 +1 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- require('./C_Icon.js');
3
- const require_C_Code = require('./C_Code.js');
4
-
5
- exports.C_Code = require_C_Code.C_Code_default;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./C_Icon.js`);const e=require(`./C_Code.js`);exports.C_Code=e.t;
package/dist/C_Code.js CHANGED
@@ -1,4 +1 @@
1
- import "./C_Icon2.js";
2
- import { t as C_Code_default } from "./C_Code2.js";
3
-
4
- export { C_Code_default as C_Code };
1
+ import"./C_Icon2.js";import{t as e}from"./C_Code2.js";export{e as C_Code};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"C_Code.js","names":["showHeader","title","language","showFullscreen","code","showLineNumbers","wordWrap","trim"],"sources":["../src/components/C_Code/index.vue","../src/components/C_Code/index.vue","../src/components/C_Code/index.vue"],"sourcesContent":["/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-19\r\n * @Description: 全局代码高亮组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-code-wrapper\">\r\n <!-- 代码标题栏 -->\r\n <div v-if=\"showHeader\" class=\"c-code-header\">\r\n <div class=\"c-code-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <div class=\"c-code-actions\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"tiny\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n\r\n <NTooltip v-if=\"showFullscreen\" trigger=\"hover\">\r\n <template #trigger>\r\n <NButton size=\"tiny\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon\r\n :name=\"\r\n isFullscreen ? 'mdi:fullscreen-exit' : 'mdi:fullscreen'\r\n \"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n {{ isFullscreen ? \"退出全屏\" : \"全屏查看\" }}\r\n </NTooltip>\r\n </div>\r\n </div>\r\n\r\n <!-- 代码内容区域 -->\r\n <div class=\"c-code-content\">\r\n <div\r\n class=\"code-wrapper\"\r\n @mouseenter=\"showFloatingCopy = true\"\r\n @mouseleave=\"showFloatingCopy = false\"\r\n >\r\n <NCode\r\n :key=\"`code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n :style=\"codeStyle\"\r\n @click=\"emit('click', $event)\"\r\n />\r\n\r\n <!-- 悬浮复制按钮 -->\r\n <Transition name=\"fade\">\r\n <div v-if=\"showFloatingCopy && !showHeader\" class=\"floating-copy-btn\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n class=\"copy-floating\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n </div>\r\n </Transition>\r\n </div>\r\n\r\n <!-- 语言加载状态 -->\r\n <div v-if=\"languageLoading\" class=\"c-code-loading\">\r\n <NSpin size=\"small\" />\r\n <span class=\"ml-2\">正在加载 {{ language }} 语言包...</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 全屏模态框 -->\r\n <NModal\r\n v-model:show=\"isFullscreen\"\r\n :mask-closable=\"false\"\r\n :show-icon=\"false\"\r\n :bordered=\"false\"\r\n style=\"width: 100vw; height: 100vh; margin: 0; padding: 0\"\r\n >\r\n <div class=\"fullscreen-content\">\r\n <div class=\"fullscreen-header\">\r\n <div class=\"fullscreen-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <NButton size=\"small\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:close\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n <div class=\"fullscreen-body\">\r\n <NCode\r\n :key=\"`fullscreen-code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n />\r\n </div>\r\n </div>\r\n </NModal>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport {\r\n ref,\r\n computed,\r\n watch,\r\n onMounted,\r\n onUnmounted,\r\n nextTick,\r\n inject,\r\n} from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\n\r\n// 直接在组件内定义 HighlightManager 接口,避免导入错误\r\ninterface HighlightManager {\r\n getHljs?: () => any;\r\n loadLanguage?: (language: string) => Promise<void>;\r\n getLoadedLanguages?: () => string[];\r\n}\r\n\r\n// 组件名称定义\r\ndefineOptions({\r\n name: \"CCode\",\r\n});\r\n\r\ninterface Props {\r\n code: string;\r\n language?: string;\r\n title?: string;\r\n showHeader?: boolean;\r\n showLineNumbers?: boolean;\r\n wordWrap?: boolean;\r\n trim?: boolean;\r\n showFullscreen?: boolean;\r\n maxHeight?: string | number;\r\n autoLoadLanguage?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n code: \"\",\r\n language: \"text\",\r\n showHeader: true,\r\n showLineNumbers: true,\r\n wordWrap: false,\r\n trim: true,\r\n showFullscreen: false,\r\n autoLoadLanguage: true,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n copy: [code: string];\r\n click: [event: MouseEvent];\r\n fullscreen: [isFullscreen: boolean];\r\n}>();\r\n\r\n// 尝试获取 highlight 实例(如果用户安装了插件)\r\nconst highlightManager = inject<HighlightManager | null>(\r\n \"highlightManager\",\r\n null,\r\n);\r\n\r\nconst copying = ref(false);\r\nconst isFullscreen = ref(false);\r\nconst languageLoading = ref(false);\r\nconst showFloatingCopy = ref(false);\r\n\r\n// 安全地获取 hljs 实例\r\nconst hljs = computed(() => {\r\n try {\r\n return highlightManager?.getHljs?.() || null;\r\n } catch (error) {\r\n console.warn(\"Highlight.js not available:\", error);\r\n return null;\r\n }\r\n});\r\n\r\n// 语言图标映射(使用标准的 MDI 图标名称)\r\nconst languageIcon = computed(() => {\r\n const iconMap: Record<string, string> = {\r\n javascript: \"mdi:language-javascript\",\r\n typescript: \"mdi:language-typescript\",\r\n python: \"mdi:language-python\",\r\n html: \"mdi:language-html5\",\r\n css: \"mdi:language-css3\",\r\n vue: \"mdi:vuejs\",\r\n react: \"mdi:react\",\r\n json: \"mdi:code-json\",\r\n java: \"mdi:language-java\",\r\n cpp: \"mdi:language-cpp\",\r\n go: \"mdi:language-go\",\r\n rust: \"mdi:language-rust\",\r\n php: \"mdi:language-php\",\r\n csharp: \"mdi:language-csharp\",\r\n sql: \"mdi:database\",\r\n yaml: \"mdi:file-code\",\r\n xml: \"mdi:xml\",\r\n markdown: \"mdi:language-markdown\",\r\n bash: \"mdi:bash\",\r\n shell: \"mdi:console\",\r\n powershell: \"mdi:powershell\",\r\n swift: \"mdi:language-swift\",\r\n kotlin: \"mdi:language-kotlin\",\r\n ruby: \"mdi:language-ruby\",\r\n };\r\n return iconMap[props.language.toLowerCase()] || \"mdi:code-braces\";\r\n});\r\n\r\n// 代码样式\r\nconst codeStyle = computed(() => {\r\n if (!props.maxHeight) return {};\r\n return {\r\n maxHeight:\r\n typeof props.maxHeight === \"number\"\r\n ? `${props.maxHeight}px`\r\n : props.maxHeight,\r\n };\r\n});\r\n\r\n// 自动加载语言包\r\nwatch(\r\n () => props.language,\r\n async (newLanguage) => {\r\n if (!props.autoLoadLanguage || newLanguage === \"text\" || !highlightManager)\r\n return;\r\n\r\n const loadedLanguages = highlightManager.getLoadedLanguages?.() || [];\r\n if (loadedLanguages.includes(newLanguage)) return;\r\n\r\n languageLoading.value = true;\r\n try {\r\n await highlightManager.loadLanguage?.(newLanguage);\r\n await nextTick();\r\n } catch (error) {\r\n console.warn(`Failed to load language: ${newLanguage}`, error);\r\n } finally {\r\n languageLoading.value = false;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\n/**\r\n * 复制代码到剪贴板\r\n */\r\nasync function copyCode() {\r\n if (copying.value) return;\r\n copying.value = true;\r\n\r\n try {\r\n await navigator.clipboard.writeText(props.code);\r\n emit(\"copy\", props.code);\r\n } catch (error) {\r\n console.error(\"Copy failed:\", error);\r\n } finally {\r\n copying.value = false;\r\n }\r\n}\r\n\r\n/**\r\n * 切换全屏显示状态\r\n */\r\nfunction toggleFullscreen() {\r\n isFullscreen.value = !isFullscreen.value;\r\n emit(\"fullscreen\", isFullscreen.value);\r\n}\r\n\r\n/**\r\n * 获取编程语言的显示标题\r\n */\r\nfunction getLanguageTitle(lang: string): string {\r\n const titleMap: Record<string, string> = {\r\n javascript: \"JavaScript\",\r\n typescript: \"TypeScript\",\r\n python: \"Python\",\r\n java: \"Java\",\r\n cpp: \"C++\",\r\n csharp: \"C#\",\r\n php: \"PHP\",\r\n go: \"Go\",\r\n rust: \"Rust\",\r\n html: \"HTML\",\r\n css: \"CSS\",\r\n json: \"JSON\",\r\n bash: \"Bash\",\r\n shell: \"Shell\",\r\n yaml: \"YAML\",\r\n xml: \"XML\",\r\n markdown: \"Markdown\",\r\n sql: \"SQL\",\r\n powershell: \"PowerShell\",\r\n swift: \"Swift\",\r\n kotlin: \"Kotlin\",\r\n ruby: \"Ruby\",\r\n vue: \"Vue\",\r\n react: \"React\",\r\n };\r\n return titleMap[lang.toLowerCase()] || lang.toUpperCase();\r\n}\r\n\r\n/**\r\n * 处理ESC键退出全屏\r\n */\r\nfunction handleEscapeKey(event: KeyboardEvent) {\r\n if (event.key === \"Escape\" && isFullscreen.value) {\r\n toggleFullscreen();\r\n }\r\n}\r\n\r\nonMounted(() => {\r\n document.addEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\nonUnmounted(() => {\r\n document.removeEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\ndefineExpose({\r\n copyCode,\r\n toggleFullscreen,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.mr-2 {\r\n margin-right: 0.5rem;\r\n}\r\n\r\n.ml-2 {\r\n margin-left: 0.5rem;\r\n}\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-19\r\n * @Description: 全局代码高亮组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-code-wrapper\">\r\n <!-- 代码标题栏 -->\r\n <div v-if=\"showHeader\" class=\"c-code-header\">\r\n <div class=\"c-code-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <div class=\"c-code-actions\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"tiny\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n\r\n <NTooltip v-if=\"showFullscreen\" trigger=\"hover\">\r\n <template #trigger>\r\n <NButton size=\"tiny\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon\r\n :name=\"\r\n isFullscreen ? 'mdi:fullscreen-exit' : 'mdi:fullscreen'\r\n \"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n {{ isFullscreen ? \"退出全屏\" : \"全屏查看\" }}\r\n </NTooltip>\r\n </div>\r\n </div>\r\n\r\n <!-- 代码内容区域 -->\r\n <div class=\"c-code-content\">\r\n <div\r\n class=\"code-wrapper\"\r\n @mouseenter=\"showFloatingCopy = true\"\r\n @mouseleave=\"showFloatingCopy = false\"\r\n >\r\n <NCode\r\n :key=\"`code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n :style=\"codeStyle\"\r\n @click=\"emit('click', $event)\"\r\n />\r\n\r\n <!-- 悬浮复制按钮 -->\r\n <Transition name=\"fade\">\r\n <div v-if=\"showFloatingCopy && !showHeader\" class=\"floating-copy-btn\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n class=\"copy-floating\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n </div>\r\n </Transition>\r\n </div>\r\n\r\n <!-- 语言加载状态 -->\r\n <div v-if=\"languageLoading\" class=\"c-code-loading\">\r\n <NSpin size=\"small\" />\r\n <span class=\"ml-2\">正在加载 {{ language }} 语言包...</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 全屏模态框 -->\r\n <NModal\r\n v-model:show=\"isFullscreen\"\r\n :mask-closable=\"false\"\r\n :show-icon=\"false\"\r\n :bordered=\"false\"\r\n style=\"width: 100vw; height: 100vh; margin: 0; padding: 0\"\r\n >\r\n <div class=\"fullscreen-content\">\r\n <div class=\"fullscreen-header\">\r\n <div class=\"fullscreen-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <NButton size=\"small\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:close\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n <div class=\"fullscreen-body\">\r\n <NCode\r\n :key=\"`fullscreen-code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n />\r\n </div>\r\n </div>\r\n </NModal>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport {\r\n ref,\r\n computed,\r\n watch,\r\n onMounted,\r\n onUnmounted,\r\n nextTick,\r\n inject,\r\n} from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\n\r\n// 直接在组件内定义 HighlightManager 接口,避免导入错误\r\ninterface HighlightManager {\r\n getHljs?: () => any;\r\n loadLanguage?: (language: string) => Promise<void>;\r\n getLoadedLanguages?: () => string[];\r\n}\r\n\r\n// 组件名称定义\r\ndefineOptions({\r\n name: \"CCode\",\r\n});\r\n\r\ninterface Props {\r\n code: string;\r\n language?: string;\r\n title?: string;\r\n showHeader?: boolean;\r\n showLineNumbers?: boolean;\r\n wordWrap?: boolean;\r\n trim?: boolean;\r\n showFullscreen?: boolean;\r\n maxHeight?: string | number;\r\n autoLoadLanguage?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n code: \"\",\r\n language: \"text\",\r\n showHeader: true,\r\n showLineNumbers: true,\r\n wordWrap: false,\r\n trim: true,\r\n showFullscreen: false,\r\n autoLoadLanguage: true,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n copy: [code: string];\r\n click: [event: MouseEvent];\r\n fullscreen: [isFullscreen: boolean];\r\n}>();\r\n\r\n// 尝试获取 highlight 实例(如果用户安装了插件)\r\nconst highlightManager = inject<HighlightManager | null>(\r\n \"highlightManager\",\r\n null,\r\n);\r\n\r\nconst copying = ref(false);\r\nconst isFullscreen = ref(false);\r\nconst languageLoading = ref(false);\r\nconst showFloatingCopy = ref(false);\r\n\r\n// 安全地获取 hljs 实例\r\nconst hljs = computed(() => {\r\n try {\r\n return highlightManager?.getHljs?.() || null;\r\n } catch (error) {\r\n console.warn(\"Highlight.js not available:\", error);\r\n return null;\r\n }\r\n});\r\n\r\n// 语言图标映射(使用标准的 MDI 图标名称)\r\nconst languageIcon = computed(() => {\r\n const iconMap: Record<string, string> = {\r\n javascript: \"mdi:language-javascript\",\r\n typescript: \"mdi:language-typescript\",\r\n python: \"mdi:language-python\",\r\n html: \"mdi:language-html5\",\r\n css: \"mdi:language-css3\",\r\n vue: \"mdi:vuejs\",\r\n react: \"mdi:react\",\r\n json: \"mdi:code-json\",\r\n java: \"mdi:language-java\",\r\n cpp: \"mdi:language-cpp\",\r\n go: \"mdi:language-go\",\r\n rust: \"mdi:language-rust\",\r\n php: \"mdi:language-php\",\r\n csharp: \"mdi:language-csharp\",\r\n sql: \"mdi:database\",\r\n yaml: \"mdi:file-code\",\r\n xml: \"mdi:xml\",\r\n markdown: \"mdi:language-markdown\",\r\n bash: \"mdi:bash\",\r\n shell: \"mdi:console\",\r\n powershell: \"mdi:powershell\",\r\n swift: \"mdi:language-swift\",\r\n kotlin: \"mdi:language-kotlin\",\r\n ruby: \"mdi:language-ruby\",\r\n };\r\n return iconMap[props.language.toLowerCase()] || \"mdi:code-braces\";\r\n});\r\n\r\n// 代码样式\r\nconst codeStyle = computed(() => {\r\n if (!props.maxHeight) return {};\r\n return {\r\n maxHeight:\r\n typeof props.maxHeight === \"number\"\r\n ? `${props.maxHeight}px`\r\n : props.maxHeight,\r\n };\r\n});\r\n\r\n// 自动加载语言包\r\nwatch(\r\n () => props.language,\r\n async (newLanguage) => {\r\n if (!props.autoLoadLanguage || newLanguage === \"text\" || !highlightManager)\r\n return;\r\n\r\n const loadedLanguages = highlightManager.getLoadedLanguages?.() || [];\r\n if (loadedLanguages.includes(newLanguage)) return;\r\n\r\n languageLoading.value = true;\r\n try {\r\n await highlightManager.loadLanguage?.(newLanguage);\r\n await nextTick();\r\n } catch (error) {\r\n console.warn(`Failed to load language: ${newLanguage}`, error);\r\n } finally {\r\n languageLoading.value = false;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\n/**\r\n * 复制代码到剪贴板\r\n */\r\nasync function copyCode() {\r\n if (copying.value) return;\r\n copying.value = true;\r\n\r\n try {\r\n await navigator.clipboard.writeText(props.code);\r\n emit(\"copy\", props.code);\r\n } catch (error) {\r\n console.error(\"Copy failed:\", error);\r\n } finally {\r\n copying.value = false;\r\n }\r\n}\r\n\r\n/**\r\n * 切换全屏显示状态\r\n */\r\nfunction toggleFullscreen() {\r\n isFullscreen.value = !isFullscreen.value;\r\n emit(\"fullscreen\", isFullscreen.value);\r\n}\r\n\r\n/**\r\n * 获取编程语言的显示标题\r\n */\r\nfunction getLanguageTitle(lang: string): string {\r\n const titleMap: Record<string, string> = {\r\n javascript: \"JavaScript\",\r\n typescript: \"TypeScript\",\r\n python: \"Python\",\r\n java: \"Java\",\r\n cpp: \"C++\",\r\n csharp: \"C#\",\r\n php: \"PHP\",\r\n go: \"Go\",\r\n rust: \"Rust\",\r\n html: \"HTML\",\r\n css: \"CSS\",\r\n json: \"JSON\",\r\n bash: \"Bash\",\r\n shell: \"Shell\",\r\n yaml: \"YAML\",\r\n xml: \"XML\",\r\n markdown: \"Markdown\",\r\n sql: \"SQL\",\r\n powershell: \"PowerShell\",\r\n swift: \"Swift\",\r\n kotlin: \"Kotlin\",\r\n ruby: \"Ruby\",\r\n vue: \"Vue\",\r\n react: \"React\",\r\n };\r\n return titleMap[lang.toLowerCase()] || lang.toUpperCase();\r\n}\r\n\r\n/**\r\n * 处理ESC键退出全屏\r\n */\r\nfunction handleEscapeKey(event: KeyboardEvent) {\r\n if (event.key === \"Escape\" && isFullscreen.value) {\r\n toggleFullscreen();\r\n }\r\n}\r\n\r\nonMounted(() => {\r\n document.addEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\nonUnmounted(() => {\r\n document.removeEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\ndefineExpose({\r\n copyCode,\r\n toggleFullscreen,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.mr-2 {\r\n margin-right: 0.5rem;\r\n}\r\n\r\n.ml-2 {\r\n margin-left: 0.5rem;\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-19\r\n * @Description: 全局代码高亮组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-code-wrapper\">\r\n <!-- 代码标题栏 -->\r\n <div v-if=\"showHeader\" class=\"c-code-header\">\r\n <div class=\"c-code-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <div class=\"c-code-actions\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"tiny\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n\r\n <NTooltip v-if=\"showFullscreen\" trigger=\"hover\">\r\n <template #trigger>\r\n <NButton size=\"tiny\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon\r\n :name=\"\r\n isFullscreen ? 'mdi:fullscreen-exit' : 'mdi:fullscreen'\r\n \"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n {{ isFullscreen ? \"退出全屏\" : \"全屏查看\" }}\r\n </NTooltip>\r\n </div>\r\n </div>\r\n\r\n <!-- 代码内容区域 -->\r\n <div class=\"c-code-content\">\r\n <div\r\n class=\"code-wrapper\"\r\n @mouseenter=\"showFloatingCopy = true\"\r\n @mouseleave=\"showFloatingCopy = false\"\r\n >\r\n <NCode\r\n :key=\"`code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n :style=\"codeStyle\"\r\n @click=\"emit('click', $event)\"\r\n />\r\n\r\n <!-- 悬浮复制按钮 -->\r\n <Transition name=\"fade\">\r\n <div v-if=\"showFloatingCopy && !showHeader\" class=\"floating-copy-btn\">\r\n <NTooltip trigger=\"hover\">\r\n <template #trigger>\r\n <NButton\r\n size=\"small\"\r\n quaternary\r\n @click=\"copyCode\"\r\n :loading=\"copying\"\r\n class=\"copy-floating\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"copying ? 'mdi:loading' : 'mdi:content-copy'\"\r\n :loading=\"copying\"\r\n />\r\n </template>\r\n </NButton>\r\n </template>\r\n 复制代码\r\n </NTooltip>\r\n </div>\r\n </Transition>\r\n </div>\r\n\r\n <!-- 语言加载状态 -->\r\n <div v-if=\"languageLoading\" class=\"c-code-loading\">\r\n <NSpin size=\"small\" />\r\n <span class=\"ml-2\">正在加载 {{ language }} 语言包...</span>\r\n </div>\r\n </div>\r\n\r\n <!-- 全屏模态框 -->\r\n <NModal\r\n v-model:show=\"isFullscreen\"\r\n :mask-closable=\"false\"\r\n :show-icon=\"false\"\r\n :bordered=\"false\"\r\n style=\"width: 100vw; height: 100vh; margin: 0; padding: 0\"\r\n >\r\n <div class=\"fullscreen-content\">\r\n <div class=\"fullscreen-header\">\r\n <div class=\"fullscreen-title\">\r\n <C_Icon\r\n v-if=\"languageIcon\"\r\n :name=\"languageIcon\"\r\n :size=\"16\"\r\n class=\"mr-2\"\r\n />\r\n <span>{{ title || getLanguageTitle(language) }}</span>\r\n </div>\r\n <NButton size=\"small\" quaternary @click=\"toggleFullscreen\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:close\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n <div class=\"fullscreen-body\">\r\n <NCode\r\n :key=\"`fullscreen-code-${language}-${code.length}`\"\r\n :code=\"code\"\r\n :language=\"language\"\r\n :hljs=\"hljs\"\r\n :show-line-numbers=\"showLineNumbers\"\r\n :word-wrap=\"wordWrap\"\r\n :trim=\"trim\"\r\n />\r\n </div>\r\n </div>\r\n </NModal>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport {\r\n ref,\r\n computed,\r\n watch,\r\n onMounted,\r\n onUnmounted,\r\n nextTick,\r\n inject,\r\n} from \"vue\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\n\r\n// 直接在组件内定义 HighlightManager 接口,避免导入错误\r\ninterface HighlightManager {\r\n getHljs?: () => any;\r\n loadLanguage?: (language: string) => Promise<void>;\r\n getLoadedLanguages?: () => string[];\r\n}\r\n\r\n// 组件名称定义\r\ndefineOptions({\r\n name: \"CCode\",\r\n});\r\n\r\ninterface Props {\r\n code: string;\r\n language?: string;\r\n title?: string;\r\n showHeader?: boolean;\r\n showLineNumbers?: boolean;\r\n wordWrap?: boolean;\r\n trim?: boolean;\r\n showFullscreen?: boolean;\r\n maxHeight?: string | number;\r\n autoLoadLanguage?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n code: \"\",\r\n language: \"text\",\r\n showHeader: true,\r\n showLineNumbers: true,\r\n wordWrap: false,\r\n trim: true,\r\n showFullscreen: false,\r\n autoLoadLanguage: true,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n copy: [code: string];\r\n click: [event: MouseEvent];\r\n fullscreen: [isFullscreen: boolean];\r\n}>();\r\n\r\n// 尝试获取 highlight 实例(如果用户安装了插件)\r\nconst highlightManager = inject<HighlightManager | null>(\r\n \"highlightManager\",\r\n null,\r\n);\r\n\r\nconst copying = ref(false);\r\nconst isFullscreen = ref(false);\r\nconst languageLoading = ref(false);\r\nconst showFloatingCopy = ref(false);\r\n\r\n// 安全地获取 hljs 实例\r\nconst hljs = computed(() => {\r\n try {\r\n return highlightManager?.getHljs?.() || null;\r\n } catch (error) {\r\n console.warn(\"Highlight.js not available:\", error);\r\n return null;\r\n }\r\n});\r\n\r\n// 语言图标映射(使用标准的 MDI 图标名称)\r\nconst languageIcon = computed(() => {\r\n const iconMap: Record<string, string> = {\r\n javascript: \"mdi:language-javascript\",\r\n typescript: \"mdi:language-typescript\",\r\n python: \"mdi:language-python\",\r\n html: \"mdi:language-html5\",\r\n css: \"mdi:language-css3\",\r\n vue: \"mdi:vuejs\",\r\n react: \"mdi:react\",\r\n json: \"mdi:code-json\",\r\n java: \"mdi:language-java\",\r\n cpp: \"mdi:language-cpp\",\r\n go: \"mdi:language-go\",\r\n rust: \"mdi:language-rust\",\r\n php: \"mdi:language-php\",\r\n csharp: \"mdi:language-csharp\",\r\n sql: \"mdi:database\",\r\n yaml: \"mdi:file-code\",\r\n xml: \"mdi:xml\",\r\n markdown: \"mdi:language-markdown\",\r\n bash: \"mdi:bash\",\r\n shell: \"mdi:console\",\r\n powershell: \"mdi:powershell\",\r\n swift: \"mdi:language-swift\",\r\n kotlin: \"mdi:language-kotlin\",\r\n ruby: \"mdi:language-ruby\",\r\n };\r\n return iconMap[props.language.toLowerCase()] || \"mdi:code-braces\";\r\n});\r\n\r\n// 代码样式\r\nconst codeStyle = computed(() => {\r\n if (!props.maxHeight) return {};\r\n return {\r\n maxHeight:\r\n typeof props.maxHeight === \"number\"\r\n ? `${props.maxHeight}px`\r\n : props.maxHeight,\r\n };\r\n});\r\n\r\n// 自动加载语言包\r\nwatch(\r\n () => props.language,\r\n async (newLanguage) => {\r\n if (!props.autoLoadLanguage || newLanguage === \"text\" || !highlightManager)\r\n return;\r\n\r\n const loadedLanguages = highlightManager.getLoadedLanguages?.() || [];\r\n if (loadedLanguages.includes(newLanguage)) return;\r\n\r\n languageLoading.value = true;\r\n try {\r\n await highlightManager.loadLanguage?.(newLanguage);\r\n await nextTick();\r\n } catch (error) {\r\n console.warn(`Failed to load language: ${newLanguage}`, error);\r\n } finally {\r\n languageLoading.value = false;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\n/**\r\n * 复制代码到剪贴板\r\n */\r\nasync function copyCode() {\r\n if (copying.value) return;\r\n copying.value = true;\r\n\r\n try {\r\n await navigator.clipboard.writeText(props.code);\r\n emit(\"copy\", props.code);\r\n } catch (error) {\r\n console.error(\"Copy failed:\", error);\r\n } finally {\r\n copying.value = false;\r\n }\r\n}\r\n\r\n/**\r\n * 切换全屏显示状态\r\n */\r\nfunction toggleFullscreen() {\r\n isFullscreen.value = !isFullscreen.value;\r\n emit(\"fullscreen\", isFullscreen.value);\r\n}\r\n\r\n/**\r\n * 获取编程语言的显示标题\r\n */\r\nfunction getLanguageTitle(lang: string): string {\r\n const titleMap: Record<string, string> = {\r\n javascript: \"JavaScript\",\r\n typescript: \"TypeScript\",\r\n python: \"Python\",\r\n java: \"Java\",\r\n cpp: \"C++\",\r\n csharp: \"C#\",\r\n php: \"PHP\",\r\n go: \"Go\",\r\n rust: \"Rust\",\r\n html: \"HTML\",\r\n css: \"CSS\",\r\n json: \"JSON\",\r\n bash: \"Bash\",\r\n shell: \"Shell\",\r\n yaml: \"YAML\",\r\n xml: \"XML\",\r\n markdown: \"Markdown\",\r\n sql: \"SQL\",\r\n powershell: \"PowerShell\",\r\n swift: \"Swift\",\r\n kotlin: \"Kotlin\",\r\n ruby: \"Ruby\",\r\n vue: \"Vue\",\r\n react: \"React\",\r\n };\r\n return titleMap[lang.toLowerCase()] || lang.toUpperCase();\r\n}\r\n\r\n/**\r\n * 处理ESC键退出全屏\r\n */\r\nfunction handleEscapeKey(event: KeyboardEvent) {\r\n if (event.key === \"Escape\" && isFullscreen.value) {\r\n toggleFullscreen();\r\n }\r\n}\r\n\r\nonMounted(() => {\r\n document.addEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\nonUnmounted(() => {\r\n document.removeEventListener(\"keydown\", handleEscapeKey);\r\n});\r\n\r\ndefineExpose({\r\n copyCode,\r\n toggleFullscreen,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.mr-2 {\r\n margin-right: 0.5rem;\r\n}\r\n\r\n.ml-2 {\r\n margin-left: 0.5rem;\r\n}\r\n</style>\r\n"],"mappings":"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"}
package/dist/C_Code2.js CHANGED
@@ -1,347 +1,2 @@
1
- import { t as C_Icon_default } from "./C_Icon2.js";
2
- import { t as export_helper_default } from "./export-helper.js";
3
- import { NButton, NCode, NModal, NSpin, NTooltip } from "naive-ui";
4
- import { Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, nextTick, normalizeStyle, onMounted, onUnmounted, openBlock, ref, toDisplayString, watch, withCtx } from "vue";
5
-
6
- //#region src/components/C_Code/index.vue?vue&type=script&setup=true&lang.ts
7
- const _hoisted_1 = { class: "c-code-wrapper" };
8
- const _hoisted_2 = {
9
- key: 0,
10
- class: "c-code-header"
11
- };
12
- const _hoisted_3 = { class: "c-code-title" };
13
- const _hoisted_4 = { class: "c-code-actions" };
14
- const _hoisted_5 = { class: "c-code-content" };
15
- const _hoisted_6 = {
16
- key: 0,
17
- class: "floating-copy-btn"
18
- };
19
- const _hoisted_7 = {
20
- key: 0,
21
- class: "c-code-loading"
22
- };
23
- const _hoisted_8 = { class: "ml-2" };
24
- const _hoisted_9 = { class: "fullscreen-content" };
25
- const _hoisted_10 = { class: "fullscreen-header" };
26
- const _hoisted_11 = { class: "fullscreen-title" };
27
- const _hoisted_12 = { class: "fullscreen-body" };
28
- var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
29
- name: "CCode",
30
- __name: "index",
31
- props: {
32
- code: { default: "" },
33
- language: { default: "text" },
34
- title: {},
35
- showHeader: {
36
- type: Boolean,
37
- default: true
38
- },
39
- showLineNumbers: {
40
- type: Boolean,
41
- default: true
42
- },
43
- wordWrap: {
44
- type: Boolean,
45
- default: false
46
- },
47
- trim: {
48
- type: Boolean,
49
- default: true
50
- },
51
- showFullscreen: {
52
- type: Boolean,
53
- default: false
54
- },
55
- maxHeight: {},
56
- autoLoadLanguage: {
57
- type: Boolean,
58
- default: true
59
- }
60
- },
61
- emits: [
62
- "copy",
63
- "click",
64
- "fullscreen"
65
- ],
66
- setup(__props, { expose: __expose, emit: __emit }) {
67
- const props = __props;
68
- const emit = __emit;
69
- const highlightManager = inject("highlightManager", null);
70
- const copying = ref(false);
71
- const isFullscreen = ref(false);
72
- const languageLoading = ref(false);
73
- const showFloatingCopy = ref(false);
74
- const hljs = computed(() => {
75
- try {
76
- return highlightManager?.getHljs?.() || null;
77
- } catch (error) {
78
- console.warn("Highlight.js not available:", error);
79
- return null;
80
- }
81
- });
82
- const languageIcon = computed(() => {
83
- return {
84
- javascript: "mdi:language-javascript",
85
- typescript: "mdi:language-typescript",
86
- python: "mdi:language-python",
87
- html: "mdi:language-html5",
88
- css: "mdi:language-css3",
89
- vue: "mdi:vuejs",
90
- react: "mdi:react",
91
- json: "mdi:code-json",
92
- java: "mdi:language-java",
93
- cpp: "mdi:language-cpp",
94
- go: "mdi:language-go",
95
- rust: "mdi:language-rust",
96
- php: "mdi:language-php",
97
- csharp: "mdi:language-csharp",
98
- sql: "mdi:database",
99
- yaml: "mdi:file-code",
100
- xml: "mdi:xml",
101
- markdown: "mdi:language-markdown",
102
- bash: "mdi:bash",
103
- shell: "mdi:console",
104
- powershell: "mdi:powershell",
105
- swift: "mdi:language-swift",
106
- kotlin: "mdi:language-kotlin",
107
- ruby: "mdi:language-ruby"
108
- }[props.language.toLowerCase()] || "mdi:code-braces";
109
- });
110
- const codeStyle = computed(() => {
111
- if (!props.maxHeight) return {};
112
- return { maxHeight: typeof props.maxHeight === "number" ? `${props.maxHeight}px` : props.maxHeight };
113
- });
114
- watch(() => props.language, async (newLanguage) => {
115
- if (!props.autoLoadLanguage || newLanguage === "text" || !highlightManager) return;
116
- if ((highlightManager.getLoadedLanguages?.() || []).includes(newLanguage)) return;
117
- languageLoading.value = true;
118
- try {
119
- await highlightManager.loadLanguage?.(newLanguage);
120
- await nextTick();
121
- } catch (error) {
122
- console.warn(`Failed to load language: ${newLanguage}`, error);
123
- } finally {
124
- languageLoading.value = false;
125
- }
126
- }, { immediate: true });
127
- /**
128
- * 复制代码到剪贴板
129
- */
130
- async function copyCode() {
131
- if (copying.value) return;
132
- copying.value = true;
133
- try {
134
- await navigator.clipboard.writeText(props.code);
135
- emit("copy", props.code);
136
- } catch (error) {
137
- console.error("Copy failed:", error);
138
- } finally {
139
- copying.value = false;
140
- }
141
- }
142
- /**
143
- * 切换全屏显示状态
144
- */
145
- function toggleFullscreen() {
146
- isFullscreen.value = !isFullscreen.value;
147
- emit("fullscreen", isFullscreen.value);
148
- }
149
- /**
150
- * 获取编程语言的显示标题
151
- */
152
- function getLanguageTitle(lang) {
153
- return {
154
- javascript: "JavaScript",
155
- typescript: "TypeScript",
156
- python: "Python",
157
- java: "Java",
158
- cpp: "C++",
159
- csharp: "C#",
160
- php: "PHP",
161
- go: "Go",
162
- rust: "Rust",
163
- html: "HTML",
164
- css: "CSS",
165
- json: "JSON",
166
- bash: "Bash",
167
- shell: "Shell",
168
- yaml: "YAML",
169
- xml: "XML",
170
- markdown: "Markdown",
171
- sql: "SQL",
172
- powershell: "PowerShell",
173
- swift: "Swift",
174
- kotlin: "Kotlin",
175
- ruby: "Ruby",
176
- vue: "Vue",
177
- react: "React"
178
- }[lang.toLowerCase()] || lang.toUpperCase();
179
- }
180
- /**
181
- * 处理ESC键退出全屏
182
- */
183
- function handleEscapeKey(event) {
184
- if (event.key === "Escape" && isFullscreen.value) toggleFullscreen();
185
- }
186
- onMounted(() => {
187
- document.addEventListener("keydown", handleEscapeKey);
188
- });
189
- onUnmounted(() => {
190
- document.removeEventListener("keydown", handleEscapeKey);
191
- });
192
- __expose({
193
- copyCode,
194
- toggleFullscreen
195
- });
196
- return (_ctx, _cache) => {
197
- const _component_NButton = NButton;
198
- const _component_NTooltip = NTooltip;
199
- const _component_NCode = NCode;
200
- const _component_NSpin = NSpin;
201
- const _component_NModal = NModal;
202
- return openBlock(), createElementBlock("div", _hoisted_1, [
203
- createCommentVNode(" 代码标题栏 "),
204
- _ctx.showHeader ? (openBlock(), createElementBlock("div", _hoisted_2, [createElementVNode("div", _hoisted_3, [languageIcon.value ? (openBlock(), createBlock(C_Icon_default, {
205
- key: 0,
206
- name: languageIcon.value,
207
- size: 16,
208
- class: "mr-2"
209
- }, null, 8, ["name"])) : createCommentVNode("v-if", true), createElementVNode("span", null, toDisplayString(_ctx.title || getLanguageTitle(_ctx.language)), 1)]), createElementVNode("div", _hoisted_4, [createVNode(_component_NTooltip, { trigger: "hover" }, {
210
- trigger: withCtx(() => [createVNode(_component_NButton, {
211
- size: "tiny",
212
- quaternary: "",
213
- onClick: copyCode,
214
- loading: copying.value
215
- }, {
216
- icon: withCtx(() => [createVNode(C_Icon_default, {
217
- name: copying.value ? "mdi:loading" : "mdi:content-copy",
218
- loading: copying.value
219
- }, null, 8, ["name", "loading"])]),
220
- _: 1
221
- }, 8, ["loading"])]),
222
- default: withCtx(() => [_cache[4] || (_cache[4] = createTextVNode(" 复制代码 ", -1))]),
223
- _: 1,
224
- __: [4]
225
- }), _ctx.showFullscreen ? (openBlock(), createBlock(_component_NTooltip, {
226
- key: 0,
227
- trigger: "hover"
228
- }, {
229
- trigger: withCtx(() => [createVNode(_component_NButton, {
230
- size: "tiny",
231
- quaternary: "",
232
- onClick: toggleFullscreen
233
- }, {
234
- icon: withCtx(() => [createVNode(C_Icon_default, { name: isFullscreen.value ? "mdi:fullscreen-exit" : "mdi:fullscreen" }, null, 8, ["name"])]),
235
- _: 1
236
- })]),
237
- default: withCtx(() => [createTextVNode(" " + toDisplayString(isFullscreen.value ? "退出全屏" : "全屏查看"), 1)]),
238
- _: 1
239
- })) : createCommentVNode("v-if", true)])])) : createCommentVNode("v-if", true),
240
- createCommentVNode(" 代码内容区域 "),
241
- createElementVNode("div", _hoisted_5, [
242
- createElementVNode("div", {
243
- class: "code-wrapper",
244
- onMouseenter: _cache[1] || (_cache[1] = ($event) => showFloatingCopy.value = true),
245
- onMouseleave: _cache[2] || (_cache[2] = ($event) => showFloatingCopy.value = false)
246
- }, [
247
- (openBlock(), createBlock(_component_NCode, {
248
- key: `code-${_ctx.language}-${_ctx.code.length}`,
249
- code: _ctx.code,
250
- language: _ctx.language,
251
- hljs: hljs.value,
252
- "show-line-numbers": _ctx.showLineNumbers,
253
- "word-wrap": _ctx.wordWrap,
254
- trim: _ctx.trim,
255
- style: normalizeStyle(codeStyle.value),
256
- onClick: _cache[0] || (_cache[0] = ($event) => emit("click", $event))
257
- }, null, 8, [
258
- "code",
259
- "language",
260
- "hljs",
261
- "show-line-numbers",
262
- "word-wrap",
263
- "trim",
264
- "style"
265
- ])),
266
- createCommentVNode(" 悬浮复制按钮 "),
267
- createVNode(Transition, { name: "fade" }, {
268
- default: withCtx(() => [showFloatingCopy.value && !_ctx.showHeader ? (openBlock(), createElementBlock("div", _hoisted_6, [createVNode(_component_NTooltip, { trigger: "hover" }, {
269
- trigger: withCtx(() => [createVNode(_component_NButton, {
270
- size: "small",
271
- quaternary: "",
272
- onClick: copyCode,
273
- loading: copying.value,
274
- class: "copy-floating"
275
- }, {
276
- icon: withCtx(() => [createVNode(C_Icon_default, {
277
- name: copying.value ? "mdi:loading" : "mdi:content-copy",
278
- loading: copying.value
279
- }, null, 8, ["name", "loading"])]),
280
- _: 1
281
- }, 8, ["loading"])]),
282
- default: withCtx(() => [_cache[5] || (_cache[5] = createTextVNode(" 复制代码 ", -1))]),
283
- _: 1,
284
- __: [5]
285
- })])) : createCommentVNode("v-if", true)]),
286
- _: 1
287
- })
288
- ], 32),
289
- createCommentVNode(" 语言加载状态 "),
290
- languageLoading.value ? (openBlock(), createElementBlock("div", _hoisted_7, [createVNode(_component_NSpin, { size: "small" }), createElementVNode("span", _hoisted_8, "正在加载 " + toDisplayString(_ctx.language) + " 语言包...", 1)])) : createCommentVNode("v-if", true)
291
- ]),
292
- createCommentVNode(" 全屏模态框 "),
293
- createVNode(_component_NModal, {
294
- show: isFullscreen.value,
295
- "onUpdate:show": _cache[3] || (_cache[3] = ($event) => isFullscreen.value = $event),
296
- "mask-closable": false,
297
- "show-icon": false,
298
- bordered: false,
299
- style: {
300
- "width": "100vw",
301
- "height": "100vh",
302
- "margin": "0",
303
- "padding": "0"
304
- }
305
- }, {
306
- default: withCtx(() => [createElementVNode("div", _hoisted_9, [createElementVNode("div", _hoisted_10, [createElementVNode("div", _hoisted_11, [languageIcon.value ? (openBlock(), createBlock(C_Icon_default, {
307
- key: 0,
308
- name: languageIcon.value,
309
- size: 16,
310
- class: "mr-2"
311
- }, null, 8, ["name"])) : createCommentVNode("v-if", true), createElementVNode("span", null, toDisplayString(_ctx.title || getLanguageTitle(_ctx.language)), 1)]), createVNode(_component_NButton, {
312
- size: "small",
313
- quaternary: "",
314
- onClick: toggleFullscreen
315
- }, {
316
- icon: withCtx(() => [createVNode(C_Icon_default, { name: "mdi:close" })]),
317
- _: 1
318
- })]), createElementVNode("div", _hoisted_12, [(openBlock(), createBlock(_component_NCode, {
319
- key: `fullscreen-code-${_ctx.language}-${_ctx.code.length}`,
320
- code: _ctx.code,
321
- language: _ctx.language,
322
- hljs: hljs.value,
323
- "show-line-numbers": _ctx.showLineNumbers,
324
- "word-wrap": _ctx.wordWrap,
325
- trim: _ctx.trim
326
- }, null, 8, [
327
- "code",
328
- "language",
329
- "hljs",
330
- "show-line-numbers",
331
- "word-wrap",
332
- "trim"
333
- ]))])])]),
334
- _: 1
335
- }, 8, ["show"])
336
- ]);
337
- };
338
- }
339
- });
340
-
341
- //#endregion
342
- //#region src/components/C_Code/index.vue
343
- var C_Code_default = /* @__PURE__ */ export_helper_default(index_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-2f676c83"]]);
344
-
345
- //#endregion
346
- export { C_Code_default as t };
1
+ import{t as e}from"./C_Icon2.js";import{t}from"./export-helper.js";import{NButton as n,NCode as r,NModal as i,NSpin as a,NTooltip as o}from"naive-ui";import{Transition as s,computed as c,createBlock as l,createCommentVNode as u,createElementBlock as d,createElementVNode as f,createTextVNode as p,createVNode as m,defineComponent as h,inject as g,nextTick as _,normalizeStyle as v,onMounted as y,onUnmounted as b,openBlock as x,ref as S,toDisplayString as C,watch as w,withCtx as T}from"vue";const E={class:`c-code-wrapper`},D={key:0,class:`c-code-header`},O={class:`c-code-title`},k={class:`c-code-actions`},A={class:`c-code-content`},j={key:0,class:`floating-copy-btn`},M={key:0,class:`c-code-loading`},N={class:`ml-2`},P={class:`fullscreen-content`},F={class:`fullscreen-header`},I={class:`fullscreen-title`},L={class:`fullscreen-body`};var R=t(h({name:`CCode`,__name:`index`,props:{code:{default:``},language:{default:`text`},title:{},showHeader:{type:Boolean,default:!0},showLineNumbers:{type:Boolean,default:!0},wordWrap:{type:Boolean,default:!1},trim:{type:Boolean,default:!0},showFullscreen:{type:Boolean,default:!1},maxHeight:{},autoLoadLanguage:{type:Boolean,default:!0}},emits:[`copy`,`click`,`fullscreen`],setup(t,{expose:h,emit:R}){let z=t,B=R,V=g(`highlightManager`,null),H=S(!1),U=S(!1),W=S(!1),G=S(!1),K=c(()=>{try{return V?.getHljs?.()||null}catch(e){return console.warn(`Highlight.js not available:`,e),null}}),q=c(()=>({javascript:`mdi:language-javascript`,typescript:`mdi:language-typescript`,python:`mdi:language-python`,html:`mdi:language-html5`,css:`mdi:language-css3`,vue:`mdi:vuejs`,react:`mdi:react`,json:`mdi:code-json`,java:`mdi:language-java`,cpp:`mdi:language-cpp`,go:`mdi:language-go`,rust:`mdi:language-rust`,php:`mdi:language-php`,csharp:`mdi:language-csharp`,sql:`mdi:database`,yaml:`mdi:file-code`,xml:`mdi:xml`,markdown:`mdi:language-markdown`,bash:`mdi:bash`,shell:`mdi:console`,powershell:`mdi:powershell`,swift:`mdi:language-swift`,kotlin:`mdi:language-kotlin`,ruby:`mdi:language-ruby`})[z.language.toLowerCase()]||`mdi:code-braces`),J=c(()=>z.maxHeight?{maxHeight:typeof z.maxHeight==`number`?`${z.maxHeight}px`:z.maxHeight}:{});w(()=>z.language,async e=>{if(!(!z.autoLoadLanguage||e===`text`||!V)&&!(V.getLoadedLanguages?.()||[]).includes(e)){W.value=!0;try{await V.loadLanguage?.(e),await _()}catch(t){console.warn(`Failed to load language: ${e}`,t)}finally{W.value=!1}}},{immediate:!0});async function Y(){if(!H.value){H.value=!0;try{await navigator.clipboard.writeText(z.code),B(`copy`,z.code)}catch(e){console.error(`Copy failed:`,e)}finally{H.value=!1}}}function X(){U.value=!U.value,B(`fullscreen`,U.value)}function Z(e){return{javascript:`JavaScript`,typescript:`TypeScript`,python:`Python`,java:`Java`,cpp:`C++`,csharp:`C#`,php:`PHP`,go:`Go`,rust:`Rust`,html:`HTML`,css:`CSS`,json:`JSON`,bash:`Bash`,shell:`Shell`,yaml:`YAML`,xml:`XML`,markdown:`Markdown`,sql:`SQL`,powershell:`PowerShell`,swift:`Swift`,kotlin:`Kotlin`,ruby:`Ruby`,vue:`Vue`,react:`React`}[e.toLowerCase()]||e.toUpperCase()}function Q(e){e.key===`Escape`&&U.value&&X()}return y(()=>{document.addEventListener(`keydown`,Q)}),b(()=>{document.removeEventListener(`keydown`,Q)}),h({copyCode:Y,toggleFullscreen:X}),(t,c)=>{let h=n,g=o,_=r,y=a,b=i;return x(),d(`div`,E,[u(` 代码标题栏 `),t.showHeader?(x(),d(`div`,D,[f(`div`,O,[q.value?(x(),l(e,{key:0,name:q.value,size:16,class:`mr-2`},null,8,[`name`])):u(`v-if`,!0),f(`span`,null,C(t.title||Z(t.language)),1)]),f(`div`,k,[m(g,{trigger:`hover`},{trigger:T(()=>[m(h,{size:`tiny`,quaternary:``,onClick:Y,loading:H.value},{icon:T(()=>[m(e,{name:H.value?`mdi:loading`:`mdi:content-copy`,loading:H.value},null,8,[`name`,`loading`])]),_:1},8,[`loading`])]),default:T(()=>[c[4]||=p(` 复制代码 `,-1)]),_:1,__:[4]}),t.showFullscreen?(x(),l(g,{key:0,trigger:`hover`},{trigger:T(()=>[m(h,{size:`tiny`,quaternary:``,onClick:X},{icon:T(()=>[m(e,{name:U.value?`mdi:fullscreen-exit`:`mdi:fullscreen`},null,8,[`name`])]),_:1})]),default:T(()=>[p(` `+C(U.value?`退出全屏`:`全屏查看`),1)]),_:1})):u(`v-if`,!0)])])):u(`v-if`,!0),u(` 代码内容区域 `),f(`div`,A,[f(`div`,{class:`code-wrapper`,onMouseenter:c[1]||=e=>G.value=!0,onMouseleave:c[2]||=e=>G.value=!1},[(x(),l(_,{key:`code-${t.language}-${t.code.length}`,code:t.code,language:t.language,hljs:K.value,"show-line-numbers":t.showLineNumbers,"word-wrap":t.wordWrap,trim:t.trim,style:v(J.value),onClick:c[0]||=e=>B(`click`,e)},null,8,[`code`,`language`,`hljs`,`show-line-numbers`,`word-wrap`,`trim`,`style`])),u(` 悬浮复制按钮 `),m(s,{name:`fade`},{default:T(()=>[G.value&&!t.showHeader?(x(),d(`div`,j,[m(g,{trigger:`hover`},{trigger:T(()=>[m(h,{size:`small`,quaternary:``,onClick:Y,loading:H.value,class:`copy-floating`},{icon:T(()=>[m(e,{name:H.value?`mdi:loading`:`mdi:content-copy`,loading:H.value},null,8,[`name`,`loading`])]),_:1},8,[`loading`])]),default:T(()=>[c[5]||=p(` 复制代码 `,-1)]),_:1,__:[5]})])):u(`v-if`,!0)]),_:1})],32),u(` 语言加载状态 `),W.value?(x(),d(`div`,M,[m(y,{size:`small`}),f(`span`,N,`正在加载 `+C(t.language)+` 语言包...`,1)])):u(`v-if`,!0)]),u(` 全屏模态框 `),m(b,{show:U.value,"onUpdate:show":c[3]||=e=>U.value=e,"mask-closable":!1,"show-icon":!1,bordered:!1,style:{width:`100vw`,height:`100vh`,margin:`0`,padding:`0`}},{default:T(()=>[f(`div`,P,[f(`div`,F,[f(`div`,I,[q.value?(x(),l(e,{key:0,name:q.value,size:16,class:`mr-2`},null,8,[`name`])):u(`v-if`,!0),f(`span`,null,C(t.title||Z(t.language)),1)]),m(h,{size:`small`,quaternary:``,onClick:X},{icon:T(()=>[m(e,{name:`mdi:close`})]),_:1})]),f(`div`,L,[(x(),l(_,{key:`fullscreen-code-${t.language}-${t.code.length}`,code:t.code,language:t.language,hljs:K.value,"show-line-numbers":t.showLineNumbers,"word-wrap":t.wordWrap,trim:t.trim},null,8,[`code`,`language`,`hljs`,`show-line-numbers`,`word-wrap`,`trim`]))])])]),_:1},8,[`show`])])}}}),[[`__scopeId`,`data-v-2f676c83`]]);export{R as t};
347
2
  //# sourceMappingURL=C_Code2.js.map