CodeModal.vue 4.9 KB
Newer Older
L
LeoKu 已提交
1
<template>
L
LeoKu 已提交
2 3 4 5
  <ModalWrapper :visible="props.visible" @close="emit('close')">
    <div class="code-box">
      <div class="code-header">
        <div class="title">{{ t('text.codeModalTitle') }}</div>
L
LeoKu 已提交
6

L
LeoKu 已提交
7 8
        <div class="close-btn" @click="emit('close')">
          <img :src="IconClose" class="icon-close" :alt="t('action.close')" />
L
LeoKu 已提交
9 10
        </div>
      </div>
L
LeoKu 已提交
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

      <div class="code-content-box">
        <PerfectScrollbar
          class="code-scroll-wrapper"
          :options="{ suppressScrollX: false }"
        >
          <pre><code class="code-content" v-html="highlightedCode"></code></pre>
        </PerfectScrollbar>

        <button
          id="copy-code-btn"
          class="copy-btn"
          :class="{ copied: copied }"
          :data-clipboard-text="codeJSON"
        >
          {{ copied ? t('action.copied') : t('action.copyCode') }}
        </button>
      </div>
L
LeoKu 已提交
29
    </div>
L
LeoKu 已提交
30
  </ModalWrapper>
L
LeoKu 已提交
31 32 33
</template>

<script lang="ts" setup>
L
Update  
LeoKu 已提交
34
import type ClipboardJS from 'clipboard'
L
LeoKu 已提交
35 36 37 38 39 40 41 42
import { computed, onMounted, onUnmounted, ref, watchEffect } from 'vue'
import { useI18n } from 'vue-i18n'

import IconClose from '@/assets/icons/icon-close.svg'
import PerfectScrollbar from '@/components/PerfectScrollbar.vue'
import { useAvatarOption } from '@/hooks'
import { highlightJSON } from '@/utils'

L
LeoKu 已提交
43 44
import ModalWrapper from './ModalWrapper.vue'

L
LeoKu 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
const props = defineProps<{ visible?: boolean }>()

const emit = defineEmits<{
  (e: 'close'): void
}>()

const { t } = useI18n()

const [avatarOption] = useAvatarOption()

const codeJSON = computed(() => JSON.stringify(avatarOption.value, null, 4))

const highlightedCode = ref('')

watchEffect(() => {
  if (codeJSON.value) {
    highlightedCode.value = highlightJSON(codeJSON.value)
  }
})

const copied = ref(false)

let clipboard: ClipboardJS

L
Update  
LeoKu 已提交
69 70
onMounted(async () => {
  const { default: ClipboardJS } = await import('clipboard')
L
LeoKu 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
  clipboard = new ClipboardJS('#copy-code-btn')

  clipboard.on('success', (e) => {
    copied.value = true

    setTimeout(() => {
      copied.value = false
    }, 800)

    e.clearSelection()
  })
})

onUnmounted(() => {
  clipboard.destroy()
})
</script>

<style lang="scss" scoped>
90 91
@use 'src/styles/var';

L
LeoKu 已提交
92 93
.code-box {
  $code-header-height: 4rem;
L
LeoKu 已提交
94 95
  $code-box-side-padding-normal: 2rem;
  $code-box-side-padding-small: 1rem;
L
LeoKu 已提交
96 97 98
  position: absolute;
  top: 50%;
  left: 50%;
L
LeoKu 已提交
99 100
  width: 75%;
  max-width: 800px;
L
Update  
LeoKu 已提交
101
  height: min(90vh, 1000px);
L
LeoKu 已提交
102
  margin: 0 auto;
L
LeoKu 已提交
103 104
  padding: $code-header-height $code-box-side-padding-normal 2.5rem
    $code-box-side-padding-normal;
L
LeoKu 已提交
105
  overflow: hidden;
106
  background-color: lighten(var.$color-dark, 3);
L
LeoKu 已提交
107
  border-radius: 1rem;
L
LeoKu 已提交
108
  transform: translate(-50%, -50%);
L
LeoKu 已提交
109 110 111 112 113 114
  transition: width 0.2s;

  @media screen and (max-width: 1200px) {
    width: 75%;
  }

115
  @media screen and (max-width: var.$screen-md) {
L
LeoKu 已提交
116 117 118
    width: 80%;
  }

119
  @media screen and (max-width: var.$screen-sm) {
L
LeoKu 已提交
120
    width: 90%;
L
LeoKu 已提交
121 122 123 124 125 126
    padding: $code-header-height $code-box-side-padding-small 2.5rem
      $code-box-side-padding-small;

    .code-header {
      padding: 0 $code-box-side-padding-small;
    }
L
LeoKu 已提交
127 128 129 130 131 132 133 134 135 136
  }

  .code-header {
    position: absolute;
    top: 0;
    left: 0;
    display: flex;
    align-items: center;
    width: 100%;
    height: $code-header-height;
L
LeoKu 已提交
137
    padding: 0 $code-box-side-padding-normal;
L
LeoKu 已提交
138 139 140 141 142 143 144 145 146 147 148 149

    .title {
      font-weight: bold;
    }

    .close-btn {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 2rem;
      height: 2rem;
      margin-left: auto;
150
      background-color: lighten(var.$color-dark, 8);
L
LeoKu 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
      border-radius: 50%;
      cursor: pointer;

      .icon-close {
        width: 45%;
        opacity: 0.6;
        transition: opacity 0.2s;
      }

      &:hover {
        .icon-close {
          opacity: 1;
        }
      }
    }
  }

  .code-content-box {
    position: relative;
    height: 20rem;
    height: 100%;
    padding: 1rem 0;
173
    background: darken(var.$color-dark, 1);
L
LeoKu 已提交
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
    border-radius: 0.8rem;

    .code-scroll-wrapper {
      height: 100%;
    }

    .copy-btn {
      position: absolute;
      top: 100%;
      left: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      width: 5rem;
      height: 2rem;
      color: #fff;
190
      background-color: var.$color-accent;
L
LeoKu 已提交
191 192 193 194 195 196
      border-radius: 0.4rem;
      transform: translate(-50%, -45%);
      cursor: pointer;
      transition: color 0.15s, background-color 0.15s;

      &.copied {
197 198
        color: var.$color-dark;
        background-color: var.$color-secondary;
L
LeoKu 已提交
199 200 201 202 203 204 205
      }
    }
  }
}
</style>

<style lang="scss">
206 207
@use 'src/styles/var';

L
LeoKu 已提交
208 209 210 211 212 213 214 215 216
.code-content {
  display: block;
  padding: 0 1.5rem;
  color: #c0c5ce;
  color: #81cfef;
  font-size: 1.25rem;
  font-family: 'Ubuntu Mono', Fallback;
  line-height: 1.4;

217
  @media screen and (max-width: var.$screen-sm) {
L
LeoKu 已提交
218 219 220 221
    padding: 0 1rem;
    font-size: 1rem;
  }

L
LeoKu 已提交
222 223 224 225 226 227 228 229 230 231 232 233
  & > .token {
    &.key {
      color: #ffcb6b;
    }

    &.string,
    &.number {
      color: #c3e88d;
    }
  }
}
</style>