87 lines
1.8 KiB
Vue
87 lines
1.8 KiB
Vue
<script lang="ts" setup>
|
|
import { computed, ref, watch } from "vue"
|
|
import { useDark } from "@vueuse/core"
|
|
import { Codemirror } from "vue-codemirror"
|
|
import { cpp } from "@codemirror/lang-cpp"
|
|
import { python } from "@codemirror/lang-python"
|
|
import { EditorView } from "@codemirror/view"
|
|
import { LANGUAGE } from "../types"
|
|
import { oneDark } from "../themes/oneDark"
|
|
import { smoothy } from "../themes/smoothy"
|
|
|
|
interface Props {
|
|
modelValue: string
|
|
label?: string
|
|
language?: LANGUAGE
|
|
fontSize?: number
|
|
readonly?: boolean
|
|
placeholder?: string
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
language: "python",
|
|
fontSize: 24,
|
|
readonly: false,
|
|
placeholder: "",
|
|
})
|
|
|
|
const code = ref(props.modelValue)
|
|
const isDark = useDark()
|
|
const styleTheme = EditorView.baseTheme({
|
|
"& .cm-scroller": {
|
|
"font-family": "Consolas",
|
|
},
|
|
"&.cm-editor.cm-focused": {
|
|
outline: "none",
|
|
},
|
|
})
|
|
const emit = defineEmits(["update:modelValue"])
|
|
|
|
watch(
|
|
() => props.modelValue,
|
|
(v) => {
|
|
code.value = v
|
|
},
|
|
)
|
|
|
|
const lang = computed(() => {
|
|
if (props.language === "python") {
|
|
return python()
|
|
}
|
|
return cpp()
|
|
})
|
|
|
|
function onChange(v: string) {
|
|
emit("update:modelValue", v)
|
|
}
|
|
</script>
|
|
<template>
|
|
<n-flex align="center" class="header" v-if="props.label">
|
|
<span class="title">{{ label }}</span>
|
|
<slot name="actions"></slot>
|
|
</n-flex>
|
|
<Codemirror
|
|
v-model="code"
|
|
indentWithTab
|
|
:extensions="[styleTheme, lang, isDark ? oneDark : smoothy]"
|
|
:disabled="props.readonly"
|
|
:tabSize="4"
|
|
:placeholder="props.placeholder"
|
|
:style="{
|
|
height: props.label ? 'calc(100% - 60px)' : '100%',
|
|
fontSize: props.fontSize + 'px',
|
|
}"
|
|
@change="onChange"
|
|
/>
|
|
</template>
|
|
<style scoped>
|
|
.header {
|
|
padding: 12px 20px;
|
|
height: 60px;
|
|
box-sizing: border-box;
|
|
}
|
|
.title {
|
|
font-size: 16px;
|
|
}
|
|
</style>
|