vp-demo.vue 5.4 KB

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