This commit is contained in:
2025-02-23 23:17:06 +08:00
parent d934111354
commit e275da04ee
8 changed files with 200 additions and 134 deletions

View File

@@ -1,9 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { darkTheme, dateZhCN, zhCN } from "naive-ui" import { darkTheme, dateZhCN, zhCN } from "naive-ui"
import { useDark, useMagicKeys, whenever } from "@vueuse/core" import { useDark, useMagicKeys, whenever } from "@vueuse/core"
import Editor from "./components/Editor.vue" import Editors from "./components/Editors.vue"
import Preview from "./components/Preview.vue" import Preview from "./components/Preview.vue"
import { html, css, js } from "./store.ts"
const isDark = useDark() const isDark = useDark()
@@ -32,17 +31,7 @@ whenever(ctrl_r, () => {})
> >
<n-split :max="0.75" :min="0.25"> <n-split :max="0.75" :min="0.25">
<template #1> <template #1>
<n-tabs default-value="html" type="segment"> <Editors />
<n-tab-pane name="html" tab="HTML">
<Editor language="html" v-model:value="html" />
</n-tab-pane>
<n-tab-pane name="css" tab="CSS">
<Editor language="css" v-model:value="css" />
</n-tab-pane>
<n-tab-pane name="js" tab="JS">
<Editor language="js" v-model:value="js" />
</n-tab-pane>
</n-tabs>
</template> </template>
<template #2> <template #2>
<Preview /> <Preview />
@@ -50,5 +39,3 @@ whenever(ctrl_r, () => {})
</n-split> </n-split>
</n-config-provider> </n-config-provider>
</template> </template>
<style scoped></style>

View File

@@ -51,6 +51,6 @@ const lang = computed(() => {
indentWithTab indentWithTab
:extensions="[styleTheme, lang, isDark ? oneDark : smoothy]" :extensions="[styleTheme, lang, isDark ? oneDark : smoothy]"
:tabSize="4" :tabSize="4"
:style="{ height: 'calc(100vh - 52px)', fontSize: props.fontSize + 'px' }" :style="{ height: '100%', fontSize: props.fontSize + 'px' }"
/> />
</template> </template>

View File

@@ -0,0 +1,60 @@
<template>
<n-tabs pane-class="pane" default-value="html" type="segment">
<n-tab-pane name="html" tab="HTML">
<Editor language="html" :font-size="size" v-model:value="html" />
</n-tab-pane>
<n-tab-pane name="css" tab="CSS">
<Editor language="css" :font-size="size" v-model:value="css" />
</n-tab-pane>
<n-tab-pane name="js" tab="JS">
<Editor language="js" :font-size="size" v-model:value="js" />
</n-tab-pane>
<n-tab-pane name="actions" tab="选项">
<n-flex vertical class="wrapper">
<!-- <n-flex align="center">
<span class="label">主题</span>
<n-button @click="toggleDark()">
{{ isDark ? "浅色" : "深色" }}
</n-button>
</n-flex> -->
<n-flex align="center">
<span class="label">重置</span>
<n-button @click="reset('html')">HTML</n-button>
<n-button @click="reset('css')">CSS</n-button>
<n-button @click="reset('js')">JS</n-button>
</n-flex>
<n-flex align="center">
<span class="label">字号</span>
<n-flex align="center">
<span :style="{ 'font-size': size + 'px' }">{{ size }}</span>
<n-button @click="changeSize(size - 2)" :disabled="size === 20">
调小
</n-button>
<n-button @click="changeSize(size + 2)" :disabled="size === 40">
调大
</n-button>
</n-flex>
</n-flex>
</n-flex>
</n-tab-pane>
</n-tabs>
</template>
<script lang="ts" setup>
import { useDark, useToggle } from "@vueuse/core"
import Editor from "./Editor.vue"
import { html, css, js, reset, size, changeSize } from "../store.ts"
const isDark = useDark()
const toggleDark = useToggle(isDark)
</script>
<style scoped>
.pane {
height: calc(100vh - 52px);
}
.wrapper {
padding: 12px;
}
.label {
font-size: 16px;
}
</style>

View File

@@ -8,12 +8,11 @@ import { onMounted, useTemplateRef, watch } from "vue"
const iframe = useTemplateRef<HTMLIFrameElement>("iframe") const iframe = useTemplateRef<HTMLIFrameElement>("iframe")
function preview() { function preview() {
if (!iframe.value) return if (!iframe.value) return
const doc = iframe.value.contentDocument const doc = iframe.value.contentDocument!
doc!.open() doc.open()
doc!.write(`<!DOCTYPE html> doc.write(`<!DOCTYPE html>
<html lang="zh-Hans-CN"> <html lang="zh-Hans-CN">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
@@ -25,7 +24,7 @@ function preview() {
${html.value} ${html.value}
</body> </body>
</html>`) </html>`)
doc!.close() doc.close()
} }
watch([html, css], preview) watch([html, css], preview)

View File

@@ -1,5 +1,25 @@
import { useStorage } from "@vueuse/core"; import { useStorage } from "@vueuse/core"
export const html = useStorage("web-html", `<div class="welcome">黄岩一职</div>`) const defaultHTML = `<div class="welcome">黄岩一职</div>`
export const css = useStorage("web-css", `.welcome { color: red; }`) const defaultCSS = `.welcome {
export const js = useStorage("web-js", "") color: red;
}`
export const html = useStorage("web-html", defaultHTML)
export const css = useStorage("web-css", defaultCSS)
export const js = useStorage("web-js", "")
export function reset(lang: "html" | "css" | "js") {
if (lang === "html") {
html.value = defaultHTML
} else if (lang === "css") {
css.value = defaultCSS
} else {
js.value = ""
}
}
export const size = useStorage("web-fontsize", 14)
export function changeSize(num: number) {
size.value = num
}

View File

@@ -1,110 +1,110 @@
import { import {
HighlightStyle, HighlightStyle,
type TagStyle, type TagStyle,
syntaxHighlighting, syntaxHighlighting,
} from "@codemirror/language" } from "@codemirror/language"
import { type Extension } from "@codemirror/state" import { type Extension } from "@codemirror/state"
import { EditorView } from "@codemirror/view" import { EditorView } from "@codemirror/view"
interface Options { interface Options {
/** /**
* Theme variant. Determines which styles CodeMirror will apply by default. * Theme variant. Determines which styles CodeMirror will apply by default.
*/ */
variant: Variant variant: Variant
/** /**
* Settings to customize the look of the editor, like background, gutter, selection and others. * Settings to customize the look of the editor, like background, gutter, selection and others.
*/ */
settings: Settings settings: Settings
/** /**
* Syntax highlighting styles. * Syntax highlighting styles.
*/ */
styles: TagStyle[] styles: TagStyle[]
} }
type Variant = "light" | "dark" type Variant = "light" | "dark"
interface Settings { interface Settings {
/** /**
* Editor background. * Editor background.
*/ */
background: string background: string
/** /**
* Default text color. * Default text color.
*/ */
foreground: string foreground: string
/** /**
* Caret color. * Caret color.
*/ */
caret: string caret: string
/** /**
* Selection background. * Selection background.
*/ */
selection: string selection: string
/** /**
* Background of highlighted lines. * Background of highlighted lines.
*/ */
lineHighlight: string lineHighlight: string
/** /**
* Gutter background. * Gutter background.
*/ */
gutterBackground: string gutterBackground: string
/** /**
* Text color inside gutter. * Text color inside gutter.
*/ */
gutterForeground: string gutterForeground: string
gutterBorderRight: string gutterBorderRight: string
} }
export const createTheme = ({ export const createTheme = ({
variant, variant,
settings, settings,
styles, styles,
}: Options): Extension => { }: Options): Extension => {
const theme = EditorView.theme( const theme = EditorView.theme(
{ {
// eslint-disable-next-line @typescript-eslint/naming-convention // eslint-disable-next-line @typescript-eslint/naming-convention
"&": { "&": {
backgroundColor: settings.background, backgroundColor: settings.background,
color: settings.foreground, color: settings.foreground,
},
".cm-content": {
caretColor: settings.caret,
},
".cm-cursor, .cm-dropCursor": {
borderLeftColor: settings.caret,
},
"&.cm-focused .cm-selectionBackgroundm .cm-selectionBackground, .cm-content ::selection":
{
backgroundColor: settings.selection,
},
".cm-activeLine": {
backgroundColor: settings.lineHighlight,
},
".cm-gutters": {
backgroundColor: settings.gutterBackground,
borderRight: settings.gutterBorderRight,
color: settings.gutterForeground,
},
".cm-activeLineGutter": {
backgroundColor: settings.lineHighlight,
},
}, },
{ ".cm-content": {
dark: variant === "dark", caretColor: settings.caret,
}, },
) ".cm-cursor, .cm-dropCursor": {
borderLeftColor: settings.caret,
const highlightStyle = HighlightStyle.define(styles) },
const extension = [theme, syntaxHighlighting(highlightStyle)] "&.cm-focused .cm-selectionBackgroundm .cm-selectionBackground, .cm-content ::selection":
{
return extension backgroundColor: settings.selection,
} },
".cm-activeLine": {
backgroundColor: settings.lineHighlight,
},
".cm-gutters": {
backgroundColor: settings.gutterBackground,
borderRight: settings.gutterBorderRight,
color: settings.gutterForeground,
},
".cm-activeLineGutter": {
backgroundColor: settings.lineHighlight,
},
},
{
dark: variant === "dark",
},
)
const highlightStyle = HighlightStyle.define(styles)
const extension = [theme, syntaxHighlighting(highlightStyle)]
return extension
}

View File

@@ -146,4 +146,4 @@ const oneDarkHighlightStyle = HighlightStyle.define([
export const oneDark: Extension = [ export const oneDark: Extension = [
oneDarkTheme, oneDarkTheme,
syntaxHighlighting(oneDarkHighlightStyle), syntaxHighlighting(oneDarkHighlightStyle),
] ]

View File

@@ -80,4 +80,4 @@ export const smoothy = createTheme({
color: "#000", color: "#000",
}, },
], ],
}) })