1 | <template>
|
2 | <div
|
3 | class="editor"
|
4 | :class="{
|
5 | 'editor--shrink': isSidebarShown
|
6 | }"
|
7 | >
|
8 |
|
9 | <template v-if="config.editorViewMode === 'waterfall'">
|
10 | <div
|
11 | class="editor-box"
|
12 | v-for="[type, content] in showBoxes"
|
13 | :key="type + content.key"
|
14 | >
|
15 | <header
|
16 | class="editor-boxName"
|
17 | :class="{
|
18 | 'editor-boxName--folded': isSandboxFolded(type)
|
19 | }"
|
20 | @dblclick="toggleFold(type)"
|
21 | >
|
22 | <span class="editor-boxType">{{ type.toUpperCase() }}</span>
|
23 | <span class="editor-boxTransformer">{{ content.transformer }}</span>
|
24 | </header>
|
25 | <sandbox
|
26 | class="editor-sandbox"
|
27 | :is-folded="isSandboxFolded(type)"
|
28 | :value="content.code"
|
29 | :language="content.transformer"
|
30 | :editorHook="content.editorHook"
|
31 | @input="codeUpdate(type, arguments)"
|
32 | ></sandbox>
|
33 | </div>
|
34 | </template>
|
35 | <template v-if="config.editorViewMode === 'tab'">
|
36 | <ul class="editor-tabs">
|
37 | <li
|
38 | class="editor-tab"
|
39 | :class="{
|
40 | 'editor-tab--active': currentBox === type
|
41 | }"
|
42 | v-for="[type, content] in showBoxes"
|
43 | :key="type"
|
44 | @click="updateCurrentBox(type)"
|
45 | >
|
46 | <span class="editor-tabName">{{
|
47 | content.tabName || type.toUpperCase()
|
48 | }}</span>
|
49 | <span v-show="currentBox === type" class="editor-tabTransformer">
|
50 | {{ content.transformer }}
|
51 | </span>
|
52 | </li>
|
53 | </ul>
|
54 | <sandbox
|
55 | v-for="[type, content] in showBoxes"
|
56 | :key="type + content.key"
|
57 | v-show="currentBox === type"
|
58 | class="editor-sandbox--tab"
|
59 | :value="content.code"
|
60 | :language="content.transformer"
|
61 | :editorHook="content.editorHook"
|
62 | @input="codeUpdate(type, arguments)"
|
63 | >
|
64 | <
|
65 | </sandbox>
|
66 | </template>
|
67 | </div>
|
68 | </template>
|
69 |
|
70 | <script>
|
71 | import PerfectScrollbar from 'perfect-scrollbar';
|
72 | import Sandbox from './sandbox.vue';
|
73 | import { mapState, mapActions } from 'vuex';
|
74 | export default {
|
75 | computed: {
|
76 | ...mapState([
|
77 | 'foldBoxes',
|
78 | 'foldBoxes',
|
79 | 'config',
|
80 | 'currentBox',
|
81 | 'isSidebarShown'
|
82 | ]),
|
83 | ...mapState({
|
84 | showBoxes(state) {
|
85 | return Object.entries(state.boxes).filter(([type, value]) => {
|
86 | return value.visible;
|
87 | });
|
88 | }
|
89 | })
|
90 | },
|
91 | components: { Sandbox },
|
92 | methods: {
|
93 | ...mapActions(['toggleBoxFold', 'updateCode', 'updateCurrentBox']),
|
94 | isSandboxFolded(type) {
|
95 | return this.foldBoxes.indexOf(type) > -1;
|
96 | },
|
97 | codeUpdate(type, [code]) {
|
98 | this.updateCode({ type, code });
|
99 | },
|
100 | toggleFold(type) {
|
101 | this.toggleBoxFold(type);
|
102 | }
|
103 | },
|
104 | mounted() {
|
105 | new PerfectScrollbar(document.querySelector('.editor'), {
|
106 | suppressScrollX: true
|
107 | });
|
108 | }
|
109 | };
|
110 | </script>
|
111 |
|
112 | <style lang="scss">
|
113 | @import '@/css/index.scss';
|
114 | @import '~perfect-scrollbar/css/perfect-scrollbar.css';
|
115 | .editor {
|
116 | height: 100%;
|
117 | overflow-y: auto;
|
118 | &-box {
|
119 | font-family: $link-font-family;
|
120 | margin: 0 20px 20px 20px;
|
121 | &Name {
|
122 | line-height: 60px;
|
123 | border-bottom: 1px solid rgba($c-highlight, 0.2);
|
124 | display: flex;
|
125 | justify-content: space-between;
|
126 | align-items: center;
|
127 | &Btn {
|
128 | width: 15px;
|
129 | height: 15px;
|
130 | background: $c-highlight;
|
131 | border-radius: 50%;
|
132 | overflow: hidden;
|
133 | position: relative;
|
134 | &::after {
|
135 | content: '';
|
136 | width: 100%;
|
137 | height: 100%;
|
138 | background: $c-bg;
|
139 | position: absolute;
|
140 | top: 0;
|
141 | left: 0;
|
142 | border-radius: 50%;
|
143 | transform: translate(-25%, -25%);
|
144 | transition: 0.5s all ease-out;
|
145 | }
|
146 | &--partial {
|
147 | &::after {
|
148 | transform: translate(-100%, -100%);
|
149 | }
|
150 | }
|
151 | }
|
152 | &--folded {
|
153 | & h2 {
|
154 | color: $c-font;
|
155 | }
|
156 | border-bottom-color: rgba($c-font, 0.2);
|
157 | opacity: 0.4;
|
158 | }
|
159 | }
|
160 | &Transformer {
|
161 | user-select: none;
|
162 | color: rgba($c-font, 0.4);
|
163 | }
|
164 | &Type {
|
165 | font-size: 18px;
|
166 | margin: 0;
|
167 | padding: 0;
|
168 | user-select: none;
|
169 | color: $c-highlight;
|
170 | }
|
171 | }
|
172 | &-tabs {
|
173 | display: flex;
|
174 | margin: 0;
|
175 | padding: 0;
|
176 | margin: 20px 10px 10px 10px;
|
177 | border-bottom: 1px solid rgba($c-highlight, 0.2);
|
178 | }
|
179 | &-tab {
|
180 | font-family: $link-font-family;
|
181 | list-style: none;
|
182 | flex-grow: 1;
|
183 | display: flex;
|
184 | flex-direction: column;
|
185 | align-items: center;
|
186 | justify-content: center;
|
187 | height: 30px;
|
188 | padding-bottom: 10px;
|
189 | filter: brightness(0.6);
|
190 | transition: 0.3s all ease-out;
|
191 | cursor: pointer;
|
192 | border-radius: 8px 8px 0 0;
|
193 | &--active {
|
194 | filter: brightness(1);
|
195 | background: rgba($c-highlight, 0.05);
|
196 | & .editor-tabName {
|
197 | transform: translateY(-6px);
|
198 | font-size: 22px;
|
199 | color: $c-highlight;
|
200 | text-shadow: 0 0 8px rgba($c-highlight, 0.5);
|
201 | }
|
202 | }
|
203 | &Name {
|
204 | transition: 0.3s all ease-out;
|
205 | color: rgba(#f6f4f2, 0.6);
|
206 | font-size: 18px;
|
207 | }
|
208 | &Transformer {
|
209 | font-size: 12px;
|
210 | color: rgba(#f6f4f2, 0.6);
|
211 | }
|
212 | }
|
213 | &-sandbox {
|
214 | &--tab {
|
215 | margin: 0 10px;
|
216 | transition: 0.3s all ease-out;
|
217 | height: calc(100% - 72px);
|
218 | }
|
219 | }
|
220 | }
|
221 |
|
222 | @media (max-width: $c-small-screen) {
|
223 | .editor {
|
224 | &--shrink {
|
225 | height: calc(100vh - 60px);
|
226 | }
|
227 | }
|
228 | }
|
229 | </style>
|