vp-demo.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <script setup lang="ts">
  2. import { computed, getCurrentInstance, toRef } from 'vue'
  3. import { isClient, useClipboard, useToggle } from '@vueuse/core'
  4. import { CaretTop } from '@element-plus/icons-vue'
  5. import { useLang } from '../composables/lang'
  6. import { useSourceCode } from '../composables/source-code'
  7. import { usePlayground } from '../composables/use-playground'
  8. import demoBlockLocale from '../../i18n/component/demo-block.json'
  9. import Example from './demo/vp-example.vue'
  10. import SourceCode from './demo/vp-source-code.vue'
  11. const props = defineProps<{
  12. demos: object
  13. source: string
  14. path: string
  15. rawSource: string
  16. description?: string
  17. }>()
  18. const vm = getCurrentInstance()!
  19. const { copy, isSupported } = useClipboard({
  20. source: decodeURIComponent(props.rawSource),
  21. read: false,
  22. })
  23. const [sourceVisible, toggleSourceVisible] = useToggle()
  24. const lang = useLang()
  25. const demoSourceUrl = useSourceCode(toRef(props, 'path'))
  26. const formatPathDemos = computed(() => {
  27. const demos = {}
  28. Object.keys(props.demos).forEach((key) => {
  29. demos[key.replace('../../examples/', '').replace('.vue', '')] =
  30. props.demos[key].default
  31. })
  32. return demos
  33. })
  34. const locale = computed(() => demoBlockLocale[lang.value])
  35. const decodedDescription = computed(() =>
  36. decodeURIComponent(props.description!)
  37. )
  38. const onPlaygroundClick = () => {
  39. const { link } = usePlayground(props.rawSource)
  40. if (!isClient) return
  41. window.open(link)
  42. }
  43. const copyCode = async () => {
  44. const { $message } = vm.appContext.config.globalProperties
  45. if (!isSupported) {
  46. $message.error(locale.value['copy-error'])
  47. }
  48. try {
  49. await copy()
  50. $message.success(locale.value['copy-success'])
  51. } catch (e: any) {
  52. $message.error(e.message)
  53. }
  54. }
  55. </script>
  56. <template>
  57. <ClientOnly>
  58. <!-- danger here DO NOT USE INLINE SCRIPT TAG -->
  59. <p text="sm" v-html="decodedDescription" />
  60. <div class="example">
  61. <Example :file="path" :demo="formatPathDemos[path]" />
  62. <ElDivider class="m-0" />
  63. <div class="op-btns">
  64. <ElTooltip :content="locale['edit-in-editor']" :show-arrow="false">
  65. <ElIcon :size="16" class="op-btn">
  66. <i-ri-flask-line @click="onPlaygroundClick" />
  67. </ElIcon>
  68. </ElTooltip>
  69. <ElTooltip :content="locale['edit-on-github']" :show-arrow="false">
  70. <ElIcon
  71. :size="16"
  72. class="op-btn github"
  73. style="color: var(--text-color-light)"
  74. >
  75. <a :href="demoSourceUrl" rel="noreferrer noopener" target="_blank">
  76. <i-ri-github-line />
  77. </a>
  78. </ElIcon>
  79. </ElTooltip>
  80. <ElTooltip :content="locale['copy-code']" :show-arrow="false">
  81. <ElIcon :size="16" class="op-btn" @click="copyCode">
  82. <i-ri-file-copy-line />
  83. </ElIcon>
  84. </ElTooltip>
  85. <ElTooltip :content="locale['view-source']" :show-arrow="false">
  86. <ElIcon :size="16" class="op-btn" @click="toggleSourceVisible()">
  87. <i-ri-code-line />
  88. </ElIcon>
  89. </ElTooltip>
  90. </div>
  91. <ElCollapseTransition>
  92. <SourceCode v-show="sourceVisible" :source="source" />
  93. </ElCollapseTransition>
  94. <Transition name="el-fade-in-linear">
  95. <div
  96. v-show="sourceVisible"
  97. class="example-float-control"
  98. @click="toggleSourceVisible(false)"
  99. >
  100. <ElIcon :size="16">
  101. <CaretTop />
  102. </ElIcon>
  103. <span>{{ locale['hide-source'] }}</span>
  104. </div>
  105. </Transition>
  106. </div>
  107. </ClientOnly>
  108. </template>
  109. <style scoped lang="scss">
  110. .example {
  111. border: 1px solid var(--border-color);
  112. border-radius: var(--el-border-radius-base);
  113. .op-btns {
  114. padding: 0.5rem;
  115. display: flex;
  116. align-items: center;
  117. justify-content: flex-end;
  118. height: 2.5rem;
  119. .el-icon {
  120. &:hover {
  121. color: var(--text-color);
  122. }
  123. }
  124. .op-btn {
  125. margin: 0 0.5rem;
  126. cursor: pointer;
  127. color: var(--text-color-lighter);
  128. transition: 0.2s;
  129. &.github a {
  130. transition: 0.2s;
  131. color: var(--text-color-lighter);
  132. &:hover {
  133. color: var(--text-color);
  134. }
  135. }
  136. }
  137. }
  138. &-float-control {
  139. display: flex;
  140. align-items: center;
  141. justify-content: center;
  142. border-top: 1px solid var(--border-color);
  143. height: 44px;
  144. box-sizing: border-box;
  145. background-color: var(--bg-color, #fff);
  146. border-bottom-left-radius: 4px;
  147. border-bottom-right-radius: 4px;
  148. margin-top: -1px;
  149. color: var(--el-text-color-secondary);
  150. cursor: pointer;
  151. position: sticky;
  152. left: 0;
  153. right: 0;
  154. bottom: 0;
  155. z-index: 10;
  156. span {
  157. font-size: 14px;
  158. margin-left: 10px;
  159. }
  160. &:hover {
  161. color: var(--el-color-primary);
  162. }
  163. }
  164. }
  165. </style>