mirror of
https://github.com/KwiTsukasa/kt-template-online-playground.git
synced 2026-05-28 00:47:42 +08:00
131 lines
2.9 KiB
Vue
131 lines
2.9 KiB
Vue
<script setup lang="ts">
|
|
import Preview from './Preview.vue'
|
|
import SsrOutput from './SsrOutput.vue'
|
|
import { computed, inject, useTemplateRef, watchEffect } from 'vue'
|
|
import {
|
|
type EditorComponentType,
|
|
type OutputModes,
|
|
injectKeyProps,
|
|
} from '../types'
|
|
|
|
const props = defineProps<{
|
|
editorComponent: EditorComponentType
|
|
showCompileOutput?: boolean
|
|
showOpenSourceMap?: boolean
|
|
showSsrOutput?: boolean
|
|
ssr: boolean
|
|
}>()
|
|
|
|
const { store } = inject(injectKeyProps)!
|
|
const previewRef = useTemplateRef('preview')
|
|
const modes = computed(() => {
|
|
const outputModes: OutputModes[] = ['preview']
|
|
if (props.showCompileOutput) {
|
|
outputModes.push('js', 'css', 'ssr')
|
|
}
|
|
if (props.ssr && props.showSsrOutput) {
|
|
outputModes.push('ssr output')
|
|
}
|
|
return outputModes
|
|
})
|
|
|
|
const mode = computed<OutputModes>({
|
|
get: () => store.value.outputMode,
|
|
set: (value) => (store.value.outputMode = value),
|
|
})
|
|
|
|
watchEffect(() => {
|
|
if (!modes.value.includes(mode.value)) {
|
|
mode.value = modes.value[0]
|
|
}
|
|
})
|
|
|
|
const showSourceMap = computed(() => {
|
|
return props.showOpenSourceMap && (mode.value === 'js' || mode.value === 'ssr')
|
|
})
|
|
|
|
function openSourceMap() {
|
|
const { clientMap, ssrMap } = store.value.activeFile.compiled
|
|
window.open(mode.value === 'js' ? clientMap : ssrMap)
|
|
}
|
|
|
|
function reload() {
|
|
previewRef.value?.reload()
|
|
}
|
|
|
|
defineExpose({ reload, previewRef })
|
|
</script>
|
|
|
|
<template>
|
|
<div class="tab-buttons">
|
|
<button
|
|
v-for="m of modes"
|
|
:key="m"
|
|
:class="{ active: mode === m }"
|
|
@click="mode = m"
|
|
>
|
|
<span>{{ m }}</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="output-container">
|
|
<Preview ref="preview" :show="mode === 'preview'" :ssr="ssr" />
|
|
<SsrOutput
|
|
v-if="mode === 'ssr output'"
|
|
:context="store.ssrOutput.context"
|
|
:html="store.ssrOutput.html"
|
|
/>
|
|
<props.editorComponent
|
|
v-else-if="mode !== 'preview'"
|
|
readonly
|
|
:filename="store.activeFile.filename"
|
|
:value="store.activeFile.compiled[mode]"
|
|
:mode="mode"
|
|
/>
|
|
</div>
|
|
|
|
<div v-if="showSourceMap" class="tab-buttons open-sourcemap">
|
|
<button>
|
|
<span @click="openSourceMap">open sourceMap</span>
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.output-container {
|
|
height: calc(100% - var(--header-height));
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
|
|
.tab-buttons {
|
|
box-sizing: border-box;
|
|
border-bottom: 1px solid var(--border);
|
|
background-color: var(--bg);
|
|
height: var(--header-height);
|
|
overflow: hidden;
|
|
}
|
|
.tab-buttons button {
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
.tab-buttons span {
|
|
font-size: 13px;
|
|
font-family: var(--font-code);
|
|
text-transform: uppercase;
|
|
color: var(--text-light);
|
|
display: inline-block;
|
|
padding: 8px 16px 6px;
|
|
line-height: 20px;
|
|
}
|
|
button.active {
|
|
color: var(--color-branding-dark);
|
|
border-bottom: 3px solid var(--color-branding-dark);
|
|
}
|
|
.open-sourcemap {
|
|
position: absolute;
|
|
right: 0;
|
|
top: 0;
|
|
}
|
|
</style>
|