icons.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <script setup lang="ts">
  2. import { computed, ref, shallowRef } from 'vue'
  3. import clipboardCopy from 'clipboard-copy'
  4. import { ElMessage } from 'element-plus'
  5. import * as Icons from '@element-plus/icons-vue'
  6. import { useLang } from '../../composables/lang'
  7. import localeData from '../../../i18n/component/icons.json'
  8. import IconCategories from './icons-categories.json'
  9. import type { DefineComponent } from 'vue'
  10. type CategoriesItem = {
  11. name: string
  12. icons: DefineComponent[]
  13. }
  14. const lang = useLang()
  15. const locale = computed(() => localeData[lang.value])
  16. const copyIcon = ref(true)
  17. const copyContent = async (content) => {
  18. try {
  19. await clipboardCopy(content)
  20. ElMessage({
  21. showClose: true,
  22. message: locale.value['copy-success'],
  23. type: 'success',
  24. })
  25. } catch {
  26. ElMessage({
  27. showClose: true,
  28. message: locale.value['copy-error'],
  29. type: 'error',
  30. })
  31. }
  32. }
  33. const copySvgIcon = async (name, refs) => {
  34. if (copyIcon.value) {
  35. await copyContent(`<el-icon><${name} /></el-icon>`)
  36. } else {
  37. const content = refs[name]?.[0].querySelector('svg')?.outerHTML ?? ''
  38. await copyContent(content)
  39. }
  40. }
  41. const categories = shallowRef<CategoriesItem[]>([])
  42. const iconMap = new Map(Object.entries(Icons))
  43. IconCategories.categories.forEach((o) => {
  44. const result: CategoriesItem = {
  45. name: o.name,
  46. icons: [],
  47. }
  48. o.items.forEach((i) => {
  49. const icon = iconMap.get(i)
  50. if (icon) {
  51. result.icons.push(icon)
  52. iconMap.delete(i)
  53. }
  54. })
  55. categories.value.push(result)
  56. })
  57. categories.value.push({ name: 'Other', icons: Array.from(iconMap.values()) })
  58. </script>
  59. <template>
  60. <div style="text-align: right">
  61. <el-switch
  62. v-model="copyIcon"
  63. active-text="Copy icon code"
  64. inactive-text="Copy SVG content"
  65. />
  66. </div>
  67. <div v-for="item in categories" :key="item.name" class="demo-icon-item">
  68. <div class="demo-icon-title">{{ item.name }}</div>
  69. <ul class="demo-icon-list">
  70. <li
  71. v-for="component in item.icons"
  72. :key="component.name"
  73. :ref="component.name"
  74. class="icon-item"
  75. @click="copySvgIcon(component.name, $refs)"
  76. >
  77. <span class="demo-svg-icon">
  78. <ElIcon :size="20">
  79. <component :is="component" />
  80. </ElIcon>
  81. <span class="icon-name">{{ component.name }}</span>
  82. </span>
  83. </li>
  84. </ul>
  85. </div>
  86. </template>
  87. <style scoped lang="scss">
  88. .demo-icon {
  89. &-item {
  90. margin-top: 24px;
  91. &:first-child {
  92. margin-top: 0;
  93. }
  94. }
  95. &-title {
  96. font-weight: 400;
  97. font-size: 18px;
  98. line-height: 26px;
  99. }
  100. &-list {
  101. overflow: hidden;
  102. list-style: none;
  103. padding: 0 !important;
  104. border-top: 1px solid var(--el-border-color);
  105. border-left: 1px solid var(--el-border-color);
  106. border-radius: 4px;
  107. display: grid;
  108. grid-template-columns: repeat(7, 1fr);
  109. .icon-item {
  110. text-align: center;
  111. color: var(--el-text-color-regular);
  112. height: 90px;
  113. font-size: 13px;
  114. border-right: 1px solid var(--el-border-color);
  115. border-bottom: 1px solid var(--el-border-color);
  116. transition: background-color var(--el-transition-duration);
  117. &:hover {
  118. background-color: var(--el-border-color-extra-light);
  119. .el-icon {
  120. color: var(--brand-color-light);
  121. }
  122. color: var(--brand-color-light);
  123. }
  124. .demo-svg-icon {
  125. display: flex;
  126. flex-direction: column;
  127. align-items: center;
  128. justify-content: center;
  129. height: 100%;
  130. cursor: pointer;
  131. .icon-name {
  132. margin-top: 8px;
  133. }
  134. }
  135. }
  136. }
  137. }
  138. </style>