officialblock 1.0.1 → 1.0.3

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 (40) hide show
  1. package/README.md +25 -1
  2. package/dist/official-block.cjs.js +195 -1
  3. package/dist/official-block.es.js +27230 -72
  4. package/dist/official-block.umd.js +195 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +13 -2
  7. package/src/App.vue +32 -82
  8. package/src/components/ArticleList/article.vue +73 -0
  9. package/src/components/ArticleList/contact.vue +95 -0
  10. package/src/components/ArticleList/index.vue +220 -46
  11. package/src/components/ArticleList/setting.vue +709 -0
  12. package/src/components/Button/index.vue +183 -0
  13. package/src/components/Media/index.vue +327 -0
  14. package/src/components/Operate/index.vue +74 -0
  15. package/src/components/RichTextEditor/RichTextEditor.vue +277 -0
  16. package/src/components/RichTextEditor/index.ts +7 -0
  17. package/src/components/ThemePreview/ThemePreview.vue +462 -0
  18. package/src/components/ThemePreview/index.ts +4 -0
  19. package/src/components/index.ts +3 -0
  20. package/src/composables/useTheme.ts +205 -0
  21. package/src/index.ts +15 -4
  22. package/src/main.ts +16 -1
  23. package/src/router/index.ts +96 -0
  24. package/src/style.css +2 -4
  25. package/src/styles/editor.scss +649 -0
  26. package/src/styles/test.scss +20 -0
  27. package/src/styles/variables.scss +669 -0
  28. package/src/utils/common.ts +13 -0
  29. package/src/utils/theme.ts +335 -0
  30. package/src/views/Layout.vue +250 -0
  31. package/src/views/NotFound.vue +114 -0
  32. package/src/views/components/ArticleListDemo.vue +166 -0
  33. package/src/views/components/DragLimitDemo.vue +573 -0
  34. package/src/views/components/DragSortDemo.vue +610 -0
  35. package/src/views/components/HeroSlideDemo.vue +353 -0
  36. package/src/views/components/RichTextEditorDemo.vue +53 -0
  37. package/src/views/components/ThemeDemo.vue +477 -0
  38. package/src/views/guide/Installation.vue +234 -0
  39. package/src/views/guide/Introduction.vue +174 -0
  40. package/src/views/guide/QuickStart.vue +265 -0
@@ -0,0 +1,183 @@
1
+ <template>
2
+ <div v-if="type === 'button'" class="button-primary flex-inline flex-center" @click="handleButtonClick">
3
+ <span class="button-text">{{ data.text }}</span>
4
+ <span class="button-icon"></span>
5
+ </div>
6
+ <div v-else class="link-button flex-inline flex-center" @click="handleButtonClick">
7
+ <span class="link-text">{{ data.text }}</span>
8
+ <span class="button-icon link-icon"></span>
9
+ </div>
10
+ </template>
11
+
12
+ <script setup lang="ts">
13
+ const props = defineProps({
14
+ type: {
15
+ type: String,
16
+ default: 'button', // button | link
17
+ },
18
+
19
+ data: {
20
+ type: Object,
21
+ default: () => {},
22
+ },
23
+ })
24
+
25
+ // TODO: 内部跳转
26
+ const handleButtonClick = () => {
27
+ window.open(props.data.url, '_blank')
28
+ }
29
+
30
+ console.log('data=====', props.data)
31
+ </script>
32
+
33
+ <style scoped lang="scss">
34
+ .button-icon {
35
+ width: 18px;
36
+ height: 18px;
37
+ border-radius: $radius-full;
38
+ overflow: hidden;
39
+ background-color: $bg-primary;
40
+ position: relative;
41
+ margin-left: $spacing-xs;
42
+ transition: background-color $transition-normal;
43
+ flex-shrink: 0;
44
+
45
+ &::before, &::after {
46
+ content: "";
47
+ width: 6px;
48
+ height: 9px;
49
+ position: absolute;
50
+ top: 50%;
51
+ left: 57%;
52
+ background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNiIgaGVpZ2h0PSI5IiB2aWV3Qm94PSIwIDAgNiA5IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMC4yMzUxOTYgNy42MjA3OUwzLjM2MDE4IDQuNDk1OEwwLjIzNTE5NiAxLjM3MDgyQzAuMTYwNjMgMS4yOTYyNSAwLjEwMTQ4MSAxLjIwNzczIDAuMDYxMTI1OSAxLjExMDMxQzAuMDIwNzcxIDEuMDEyODggMS41NzEzN2UtMDkgMC45MDg0NiAwIDAuODAzMDA4Qy0xLjU3MTM2ZS0wOSAwLjY5NzU1NSAwLjAyMDc3MSAwLjU5MzEzNSAwLjA2MTEyNTkgMC40OTU3MUMwLjEwMTQ4MSAwLjM5ODI4NSAwLjE2MDYzIDAuMzA5NzYyIDAuMjM1MTk2IDAuMjM1MTk1QzAuMzA5NzYyIDAuMTYwNjI5IDAuMzk4Mjg1IDAuMTAxNDggMC40OTU3MSAwLjA2MTEyNTFDMC41OTMxMzYgMC4wMjA3NzAyIDAuNjk3NTU2IC0xLjU3MTM3ZS0wOSAwLjgwMzAwOCAwQzAuOTA4NDYxIDEuNTcxMzdlLTA5IDEuMDEyODggMC4wMjA3NzAyIDEuMTEwMzEgMC4wNjExMjUxQzEuMjA3NzMgMC4xMDE0OCAxLjI5NjI1IDAuMTYwNjI5IDEuMzcwODIgMC4yMzUxOTVMNS4wNjc2NCAzLjkzMjAyQzUuMzgxNzUgNC4yNDYxMyA1LjM4MTc1IDQuNzUzNTMgNS4wNjc2NCA1LjA2NzY0TDEuMzcwODIgOC43NjQ0NkMxLjI5NjMxIDguODM5MTMgMS4yMDc4IDguODk4MzYgMS4xMTAzNyA4LjkzODc4QzEuMDEyOTQgOC45NzkyIDAuOTA4NDkxIDkgMC44MDMwMDggOUMwLjY5NzUyNSA5IDAuNTkzMDc4IDguOTc5MiAwLjQ5NTY0NSA4LjkzODc4QzAuMzk4MjEyIDguODk4MzYgMC4zMDk3MDcgOC44MzkxMyAwLjIzNTE5NiA4Ljc2NDQ2Qy0wLjA3MDg1OTEgOC40NTAzNSAtMC4wNzg5MTMyIDcuOTM0ODkgMC4yMzUxOTYgNy42MjA3OVoiIGZpbGw9IiMwMDFFNjAiLz4KPC9zdmc+Cgo=);
53
+ background-position: 50%;
54
+ background-size: cover;
55
+ background-repeat: no-repeat;
56
+ background-color: hsla(0,0%,100%,0);
57
+ transition: transform .3s ease-in-out
58
+ }
59
+
60
+ &::before {
61
+ transform: translate(-260%,-50%)
62
+ }
63
+
64
+ &::after {
65
+ transform: translate(-50%,-50%)
66
+ }
67
+ }
68
+
69
+ .link-icon {
70
+ background-color: $primary-color;
71
+
72
+ &::before, &::after {
73
+ background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNiIgaGVpZ2h0PSI5IiB2aWV3Qm94PSIwIDAgNiA5IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMC4yMzUxOTYgNy42MjA3OUwzLjM2MDE4IDQuNDk1OEwwLjIzNTE5NiAxLjM3MDgyQzAuMTYwNjMgMS4yOTYyNSAwLjEwMTQ4MSAxLjIwNzczIDAuMDYxMTI1OSAxLjExMDMxQzAuMDIwNzcxIDEuMDEyODggMS41NzEzN2UtMDkgMC45MDg0NiAwIDAuODAzMDA4Qy0xLjU3MTM2ZS0wOSAwLjY5NzU1NSAwLjAyMDc3MSAwLjU5MzEzNSAwLjA2MTEyNTkgMC40OTU3MUMwLjEwMTQ4MSAwLjM5ODI4NSAwLjE2MDYzIDAuMzA5NzYyIDAuMjM1MTk2IDAuMjM1MTk1QzAuMzA5NzYyIDAuMTYwNjI5IDAuMzk4Mjg1IDAuMTAxNDggMC40OTU3MSAwLjA2MTEyNTFDMC41OTMxMzYgMC4wMjA3NzAyIDAuNjk3NTU2IC0xLjU3MTM3ZS0wOSAwLjgwMzAwOCAwQzAuOTA4NDYxIDEuNTcxMzdlLTA5IDEuMDEyODggMC4wMjA3NzAyIDEuMTEwMzEgMC4wNjExMjUxQzEuMjA3NzMgMC4xMDE0OCAxLjI5NjI1IDAuMTYwNjI5IDEuMzcwODIgMC4yMzUxOTVMNS4wNjc2NCAzLjkzMjAyQzUuMzgxNzUgNC4yNDYxMyA1LjM4MTc1IDQuNzUzNTMgNS4wNjc2NCA1LjA2NzY0TDEuMzcwODIgOC43NjQ0NkMxLjI5NjMxIDguODM5MTMgMS4yMDc4IDguODk4MzYgMS4xMTAzNyA4LjkzODc4QzEuMDEyOTQgOC45NzkyIDAuOTA4NDkxIDkgMC44MDMwMDggOUMwLjY5NzUyNSA5IDAuNTkzMDc4IDguOTc5MiAwLjQ5NTY0NSA4LjkzODc4QzAuMzk4MjEyIDguODk4MzYgMC4zMDk3MDcgOC44MzkxMyAwLjIzNTE5NiA4Ljc2NDQ2Qy0wLjA3MDg1OTEgOC40NTAzNSAtMC4wNzg5MTMyIDcuOTM0ODkgMC4yMzUxOTYgNy42MjA3OVoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=);
74
+ }
75
+ }
76
+
77
+ .link-button {
78
+ overflow: hidden;
79
+ text-decoration: none;
80
+ position: relative;
81
+ z-index: 1;
82
+ white-space: nowrap;
83
+ cursor: pointer;
84
+ transition: all $transition-normal;
85
+
86
+ .link-text {
87
+ font-weight: $font-weight-medium;
88
+ letter-spacing: .04em;
89
+ color: $text-important;
90
+ transition: color $transition-normal;
91
+ }
92
+
93
+ &::before {
94
+ content: "";
95
+ display: block;
96
+ position: absolute;
97
+ width: 200%;
98
+ height: 500%;
99
+ left: 50%;
100
+ top: 50%;
101
+ transform: translate(-50%,-50%);
102
+ transition: all $transition-normal;
103
+ z-index: -1;
104
+ -webkit-clip-path: circle(100% at -80% 90%);
105
+ clip-path: circle(100% at -80% 90%)
106
+ }
107
+
108
+ &:hover::before {
109
+ -webkit-clip-path: circle(100% at 50% 50%);
110
+ clip-path: circle(100% at 50% 50%)
111
+ }
112
+
113
+ &:hover {
114
+ .button-icon:before {
115
+ transform: translate(-50%,-50%)
116
+ }
117
+
118
+ .button-icon:after {
119
+ transform: translate(150%,-50%)
120
+ }
121
+
122
+ .button-icon:after, .button-icon:before {
123
+ background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNiIgaGVpZ2h0PSI5IiB2aWV3Qm94PSIwIDAgNiA5IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMC4yMzUxOTYgNy42MjA3OUwzLjM2MDE4IDQuNDk1OEwwLjIzNTE5NiAxLjM3MDgyQzAuMTYwNjMgMS4yOTYyNSAwLjEwMTQ4MSAxLjIwNzczIDAuMDYxMTI1OSAxLjExMDMxQzAuMDIwNzcxIDEuMDEyODggMS41NzEzN2UtMDkgMC45MDg0NiAwIDAuODAzMDA4Qy0xLjU3MTM2ZS0wOSAwLjY5NzU1NSAwLjAyMDc3MSAwLjU5MzEzNSAwLjA2MTEyNTkgMC40OTU3MUMwLjEwMTQ4MSAwLjM5ODI4NSAwLjE2MDYzIDAuMzA5NzYyIDAuMjM1MTk2IDAuMjM1MTk1QzAuMzA5NzYyIDAuMTYwNjI5IDAuMzk4Mjg1IDAuMTAxNDggMC40OTU3MSAwLjA2MTEyNTFDMC41OTMxMzYgMC4wMjA3NzAyIDAuNjk3NTU2IC0xLjU3MTM3ZS0wOSAwLjgwMzAwOCAwQzAuOTA4NDYxIDEuNTcxMzdlLTA5IDEuMDEyODggMC4wMjA3NzAyIDEuMTEwMzEgMC4wNjExMjUxQzEuMjA3NzMgMC4xMDE0OCAxLjI5NjI1IDAuMTYwNjI5IDEuMzcwODIgMC4yMzUxOTVMNS4wNjc2NCAzLjkzMjAyQzUuMzgxNzUgNC4yNDYxMyA1LjM4MTc1IDQuNzUzNTMgNS4wNjc2NCA1LjA2NzY0TDEuMzcwODIgOC43NjQ0NkMxLjI5NjMxIDguODM5MTMgMS4yMDc4IDguODk4MzYgMS4xMTAzNyA4LjkzODc4QzEuMDEyOTQgOC45NzkyIDAuOTA4NDkxIDkgMC44MDMwMDggOUMwLjY5NzUyNSA5IDAuNTkzMDc4IDguOTc5MiAwLjQ5NTY0NSA4LjkzODc4QzAuMzk4MjEyIDguODk4MzYgMC4zMDk3MDcgOC44MzkxMyAwLjIzNTE5NiA4Ljc2NDQ2Qy0wLjA3MDg1OTEgOC40NTAzNSAtMC4wNzg5MTMyIDcuOTM0ODkgMC4yMzUxOTYgNy42MjA3OVoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=);
124
+ background-position: 50%;
125
+ background-size: cover;
126
+ background-repeat: no-repeat;
127
+ background-color: hsla(0,0%,100%,0);
128
+ }
129
+ }
130
+ }
131
+
132
+ .button-primary {
133
+ @extend .link-button;
134
+ background-color: $button-bg;
135
+ padding: 11px 15px;
136
+ min-width: 160px;
137
+ border-radius: $radius-sm;
138
+ box-shadow: $shadow-sm;
139
+
140
+ .button-text {
141
+ font-weight: $font-weight-medium;
142
+ letter-spacing: .04em;
143
+ color: $text-white;
144
+ transition: color $transition-normal;
145
+ }
146
+
147
+ &::before {
148
+ background: $button-hover-bg;
149
+ }
150
+
151
+ .button-icon:after, .button-icon:before {
152
+ background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNiIgaGVpZ2h0PSI5IiB2aWV3Qm94PSIwIDAgNiA5IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMC4yMzUxOTYgNy42MjA3OUwzLjM2MDE4IDQuNDk1OEwwLjIzNTE5NiAxLjM3MDgyQzAuMTYwNjMgMS4yOTYyNSAwLjEwMTQ4MSAxLjIwNzczIDAuMDYxMTI1OSAxLjExMDMxQzAuMDIwNzcxIDEuMDEyODggMS41NzEzN2UtMDkgMC45MDg0NiAwIDAuODAzMDA4Qy0xLjU3MTM2ZS0wOSAwLjY5NzU1NSAwLjAyMDc3MSAwLjU5MzEzNSAwLjA2MTEyNTkgMC40OTU3MUMwLjEwMTQ4MSAwLjM5ODI4NSAwLjE2MDYzIDAuMzA5NzYyIDAuMjM1MTk2IDAuMjM1MTk1QzAuMzA5NzYyIDAuMTYwNjI5IDAuMzk4Mjg1IDAuMTAxNDggMC40OTU3MSAwLjA2MTEyNTFDMC41OTMxMzYgMC4wMjA3NzAyIDAuNjk3NTU2IC0xLjU3MTM3ZS0wOSAwLjgwMzAwOCAwQzAuOTA4NDYxIDEuNTcxMzdlLTA5IDEuMDEyODggMC4wMjA3NzAyIDEuMTEwMzEgMC4wNjExMjUxQzEuMjA3NzMgMC4xMDE0OCAxLjI5NjI1IDAuMTYwNjI5IDEuMzcwODIgMC4yMzUxOTVMNS4wNjc2NCAzLjkzMjAyQzUuMzgxNzUgNC4yNDYxMyA1LjM4MTc1IDQuNzUzNTMgNS4wNjc2NCA1LjA2NzY0TDEuMzcwODIgOC43NjQ0NkMxLjI5NjMxIDguODM5MTMgMS4yMDc4IDguODk4MzYgMS4xMTAzNyA4LjkzODc4QzEuMDEyOTQgOC45NzkyIDAuOTA4NDkxIDkgMC44MDMwMDggOUMwLjY5NzUyNSA5IDAuNTkzMDc4IDguOTc5MiAwLjQ5NTY0NSA4LjkzODc4QzAuMzk4MjEyIDguODk4MzYgMC4zMDk3MDcgOC44MzkxMyAwLjIzNTE5NiA4Ljc2NDQ2Qy0wLjA3MDg1OTEgOC40NTAzNSAtMC4wNzg5MTMyIDcuOTM0ODkgMC4yMzUxOTYgNy42MjA3OVoiIGZpbGw9IiMwMDFFNjAiLz4KPC9zdmc+Cgo=) !important;
153
+ }
154
+ }
155
+
156
+ @media(max-width: 1023.98px) {
157
+ .button-primary {
158
+ padding:11px 15px;
159
+ min-width: 100px
160
+ }
161
+ }
162
+
163
+ @media(max-width: 767.98px) {
164
+ .button-primary {
165
+ padding:8px 12px;
166
+ min-width: 80px
167
+ }
168
+ }
169
+
170
+ @media(max-width: 1023.98px) {
171
+ .button-primary {
172
+ padding:11px 15px;
173
+ min-width: 100px
174
+ }
175
+ }
176
+
177
+ @media(max-width: 767.98px) {
178
+ .button-primary {
179
+ padding:8px 12px;
180
+ min-width: 80px
181
+ }
182
+ }
183
+ </style>
@@ -0,0 +1,327 @@
1
+ <template>
2
+ <div class="image-container" v-if="type === 'Image'">
3
+ <a-image class="image" :src="data.imgSrc" :preview="preview" :alt="data.alt" fit="contain" width="100%" height="100%" />
4
+ <p class="image-desc" v-if="data.caption">{{ data.caption }}</p>
5
+ </div>
6
+
7
+ <div class="video-container flex-inline flex-center" v-if="type === 'Video'">
8
+ <!-- 获取播放状态 -->
9
+ <video class="video" ref="videoElement" :src="data.videoSrc" controls></video>
10
+ <template v-if="!isPlaying">
11
+ <div class="video-thumbnail flex flex-center">
12
+ <img :src="data.imgSrc">
13
+ </div>
14
+ <div class="play-button flex flex-center" @click="playVideo">
15
+ <icon-caret-right style="color: #fff" />
16
+ </div>
17
+ </template>
18
+ </div>
19
+
20
+ <div class="image-list-container" v-if="type === 'ImageList'">
21
+ <div class="image-preview" v-if="previewUrl">
22
+ <a-image class="image" :src="previewUrl" :preview="preview" fit="contain" width="100%" height="100%" />
23
+ </div>
24
+ <div class="image-list-wrapper">
25
+ <div
26
+ class="thumbnail__nav__prev"
27
+ v-show="showPrev"
28
+ @click="scrollPrev"
29
+ >
30
+
31
+ </div>
32
+ <div class="image-list" ref="imageListRef" @scroll="onScroll">
33
+ <template v-for="item in data.imageList" :key="item.id">
34
+ <img
35
+ v-if="item.src"
36
+ class="image"
37
+ :src="item.src"
38
+ @click="setPreviewUrl(item.src)"
39
+ />
40
+ </template>
41
+ </div>
42
+ <div
43
+ class="thumbnail__nav__next"
44
+ v-show="showNext"
45
+ @click="scrollNext"
46
+ >
47
+
48
+ </div>
49
+ </div>
50
+ </div>
51
+ </template>
52
+
53
+ <script lang="ts" setup>
54
+ import { ref, watch, onMounted, nextTick, onUnmounted } from 'vue'
55
+
56
+ const props = defineProps({
57
+ type: {
58
+ type: String,
59
+ default: 'Image' // Image | Video | ImageList
60
+ },
61
+ data: {
62
+ type: Object,
63
+ default: () => {}
64
+ },
65
+ // imgSrc: {
66
+ // type: String,
67
+ // default: 'https://osswebsite.ycyw.com/media-library/ywies-bj/images/home/ywies-tx.jpg'
68
+ // },
69
+ preview: {
70
+ type: Boolean,
71
+ default: true
72
+ },
73
+ // videoSrc: {
74
+ // type: String,
75
+ // default: 'http://mpv.videocc.net/4b964bbdf4/3/4b964bbdf481505df84cfd703c4b3043_2.mp4'
76
+ // },
77
+ // caption: {
78
+ // type: String,
79
+ // default: '图片'
80
+ // },
81
+ // imageList: {
82
+ // type: Array as PropType<string[]>,
83
+ // default: () => ['https://osswebsite.ycyw.com/media-library/ywies-bj/images/home/ywies-tx.jpg', 'https://osswebsite.ycyw.com/media-library/ywies-bj/images/home/ywies-tx.jpg']
84
+ // }
85
+ })
86
+
87
+ const videoElement = ref<HTMLVideoElement>();
88
+ const isPlaying = ref<boolean>(false);
89
+ const playVideo = () => {
90
+ videoElement.value?.play();
91
+ isPlaying.value = true;
92
+ }
93
+
94
+ const previewUrl = ref<string>(props.data?.imageList?.[0]?.src || '');
95
+ const setPreviewUrl = (url: string) => {
96
+ previewUrl.value = url;
97
+ }
98
+
99
+ const imageListRef = ref<HTMLDivElement | null>(null)
100
+ const showPrev = ref(false)
101
+ const showNext = ref(false)
102
+
103
+ const checkScroll = () => {
104
+ const el = imageListRef.value
105
+ if (!el) return
106
+ showPrev.value = el.scrollLeft > 0
107
+ showNext.value = el.scrollLeft + el.clientWidth < el.scrollWidth
108
+ }
109
+
110
+ const scrollPrev = () => {
111
+ const el = imageListRef.value
112
+ if (!el) return
113
+ el.scrollBy({ left: -el.clientWidth / 1.5, behavior: 'smooth' })
114
+ }
115
+
116
+ const scrollNext = () => {
117
+ const el = imageListRef.value
118
+ if (!el) return
119
+ el.scrollBy({ left: el.clientWidth / 1.5, behavior: 'smooth' })
120
+ }
121
+
122
+ const onScroll = () => {
123
+ checkScroll()
124
+ }
125
+
126
+ watch(() => props.data?.imageList, async () => {
127
+ await nextTick()
128
+ checkScroll()
129
+ })
130
+
131
+ onMounted(() => {
132
+ window.addEventListener('resize', checkScroll)
133
+ nextTick(checkScroll)
134
+ })
135
+
136
+ onUnmounted(() => {
137
+ window.removeEventListener('resize', checkScroll)
138
+ })
139
+ </script>
140
+
141
+ <style lang="scss" scoped>
142
+ .image-container {
143
+ width: 100%;
144
+ position: relative;
145
+
146
+ .image {
147
+ width: 100%;
148
+ height: auto;
149
+ object-fit: contain;
150
+ }
151
+
152
+ .image-desc {
153
+ margin-top: 12px;
154
+ font-size: $font-size-sm;
155
+ line-height: $line-height-relaxed;
156
+ letter-spacing: .01em;
157
+ }
158
+ }
159
+
160
+ .video-container {
161
+ position: relative;
162
+ width: 100%;
163
+ height: auto;
164
+ cursor: pointer;
165
+ overflow: hidden;
166
+
167
+ .video {
168
+ width: 100%;
169
+ height: auto;
170
+ }
171
+
172
+ .video-thumbnail {
173
+ position: absolute;
174
+ top: 0;
175
+ left: 0;
176
+ width: 100%;
177
+ height: 100%;
178
+ background: #000;
179
+
180
+ img {
181
+ height: 100%;
182
+ }
183
+ }
184
+
185
+ .play-button {
186
+ position: absolute;
187
+ top: 50%;
188
+ left: 50%;
189
+ transform: translate(-50%, -50%);
190
+ font-size: 3em;
191
+ line-height: 1.5em;
192
+ height: 1.63332em;
193
+ width: 3em;
194
+ opacity: 1;
195
+ border: .06666em solid #fff;
196
+ background-color: #2b333f;
197
+ background-color: rgba(43, 51, 63, .7);
198
+ border-radius: .3em;
199
+ transition: all .4s;
200
+ cursor: pointer;
201
+ }
202
+ }
203
+
204
+ .image-list-container {
205
+ width: 100%;
206
+
207
+ .image-preview {
208
+ position: relative;
209
+ width: 100%;
210
+ height: 0;
211
+ padding-bottom: 58.33%;
212
+ overflow: hidden;
213
+
214
+ .image {
215
+ position: absolute;
216
+ left: 0;
217
+ width: 100%;
218
+ height: 100%;
219
+ object-fit: contain;
220
+ cursor: pointer;
221
+ }
222
+ }
223
+
224
+ .image-list-wrapper {
225
+ position: relative;
226
+
227
+ .image-list {
228
+ display: flex;
229
+ margin-top: 12px;
230
+ overflow-x: scroll;
231
+ overflow-y: hidden;
232
+ scroll-behavior: smooth;
233
+ scrollbar-color: transparent;
234
+ scrollbar-width: none;
235
+
236
+ .image {
237
+ flex-shrink: 0;
238
+ width: 87.4px;
239
+ height: 55px;
240
+ cursor: pointer;
241
+ }
242
+
243
+ .image:not(:last-of-type) {
244
+ margin-right: 10.6px
245
+ }
246
+ }
247
+
248
+ .thumbnail__nav__prev,
249
+ .thumbnail__nav__next {
250
+ position: absolute;
251
+ width: 33px;
252
+ height: 100%;
253
+ background-color: #fff;
254
+ display: flex;
255
+ align-items: center;
256
+ justify-content: center;
257
+ z-index: 1;
258
+ cursor: pointer;
259
+ }
260
+
261
+ .thumbnail__nav__prev {
262
+ left: -1px;
263
+ }
264
+
265
+ .thumbnail__nav__prev:after {
266
+ transform: scale(-1);
267
+ }
268
+
269
+ .thumbnail__nav__next {
270
+ right: -1px;
271
+ }
272
+ }
273
+ }
274
+
275
+ @media(max-width: 767.98px) {
276
+ .image-container .image {
277
+ border-radius: 0;
278
+ }
279
+ }
280
+
281
+ @media(max-width: 1023.98px) {
282
+ .image-desc p {
283
+ font-size:14px;
284
+ line-height: 1.714;
285
+ letter-spacing: .01em
286
+ }
287
+ }
288
+
289
+ @media(max-width: 767.98px) {
290
+ .video-container {
291
+ width:100vw;
292
+ padding: 0
293
+ }
294
+ }
295
+
296
+ @media(max-width: 767.98px) {
297
+ .image-list-container .image-preview {
298
+ padding-bottom:68.75%
299
+ }
300
+ }
301
+
302
+ @media(max-width: 1023.98px) {
303
+ .thumbnail__nav__prev,
304
+ .thumbnail__nav__next {
305
+ width:28px
306
+ }
307
+ }
308
+
309
+ @media(max-width: 767.98px) {
310
+ .thumbnail__nav__prev,
311
+ .thumbnail__nav__next {
312
+ box-shadow:0 4px 4px hsla(0,0%,100%,.2)
313
+ }
314
+ }
315
+
316
+ @media(max-width: 900px) {
317
+ .image-list-container .image-list-wrapper .image-list .image {
318
+ width:80px
319
+ }
320
+ }
321
+
322
+ @media(max-width: 767.98px) {
323
+ .image-list-container .image-list-wrapper .image-list .image {
324
+ width:75px
325
+ }
326
+ }
327
+ </style>
@@ -0,0 +1,74 @@
1
+ <template>
2
+ <div class="operate-page" v-show="show">
3
+ <div class="operate-btn flex justify-end">
4
+ <div class="btn-item btn-copy flex items-center" @click="handleCopy">
5
+ <icon-copy />
6
+ <span class="btn-text">复制</span>
7
+ </div>
8
+ <div class="btn-item btn-delete flex items-center" @click="handleDelete">
9
+ <icon-delete />
10
+ <span class="btn-text">删除</span>
11
+ </div>
12
+ <div class="btn-item btn-edit flex items-center" @click="handleEdit">
13
+ <icon-edit />
14
+ <span class="btn-text">编辑</span>
15
+ </div>
16
+ </div>
17
+ </div>
18
+ </template>
19
+
20
+ <script lang="ts" setup>
21
+ defineProps({
22
+ show: {
23
+ type: Boolean,
24
+ default: false,
25
+ },
26
+ })
27
+
28
+ const emit = defineEmits(['handleCopy', 'handleDelete', 'handleEdit'])
29
+
30
+ const handleCopy = () => {
31
+ emit('handleCopy')
32
+ }
33
+ const handleDelete = () => {
34
+ emit('handleDelete')
35
+ }
36
+ const handleEdit = () => {
37
+ emit('handleEdit')
38
+ }
39
+ </script>
40
+
41
+ <style lang="scss" scoped>
42
+ .operate-page {
43
+ position: absolute;
44
+ top: 0;
45
+ left: 0;
46
+ right: 0;
47
+ bottom: 0;
48
+ padding: 20px;
49
+
50
+ .operate-btn {
51
+ .btn-item {
52
+ margin-left: 12px;
53
+ padding: 4px 16px;
54
+ font-size: 10px;
55
+ color: #fff;
56
+ border-radius: 4px;
57
+ font-weight: 600;
58
+ cursor: pointer;
59
+ }
60
+
61
+ .btn-copy {
62
+ background: $warning-color;
63
+ }
64
+
65
+ .btn-delete {
66
+ background: $error-color;
67
+ }
68
+
69
+ .btn-edit {
70
+ background: $primary-color;
71
+ }
72
+ }
73
+ }
74
+ </style>