first commit
This commit is contained in:
22
src/App.vue
Normal file
22
src/App.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import { zhCN, dateZhCN, darkTheme } from "naive-ui"
|
||||
import Desktop from "./desktop/index.vue"
|
||||
import Mobile from "./mobile/index.vue"
|
||||
import { isDesktop, isMobile } from "./composables/breakpoints"
|
||||
import { useDark } from "@vueuse/core"
|
||||
const isDark = useDark()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-config-provider
|
||||
inline-theme-disabled
|
||||
:locale="zhCN"
|
||||
:date-locale="dateZhCN"
|
||||
:theme="isDark ? darkTheme : null"
|
||||
>
|
||||
<n-layout>
|
||||
<Desktop v-if="isDesktop" />
|
||||
<Mobile v-if="isMobile" />
|
||||
</n-layout>
|
||||
</n-config-provider>
|
||||
</template>
|
||||
56
src/api.ts
Normal file
56
src/api.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import axios from "axios"
|
||||
import { Code } from "./types"
|
||||
import { deadResults, languageToId } from "./templates"
|
||||
|
||||
function getChromeVersion() {
|
||||
var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)
|
||||
return raw ? parseInt(raw[2], 10) : 0
|
||||
}
|
||||
|
||||
const isLowVersion = getChromeVersion() < 80
|
||||
|
||||
const protocol = isLowVersion ? "http" : "https"
|
||||
|
||||
function encode(string?: string) {
|
||||
return btoa(String.fromCharCode(...new TextEncoder().encode(string ?? "")))
|
||||
}
|
||||
|
||||
function decode(bytes?: string) {
|
||||
const latin = atob(bytes ?? "")
|
||||
return new TextDecoder("utf-8").decode(
|
||||
Uint8Array.from({ length: latin.length }, (_, index) =>
|
||||
latin.charCodeAt(index),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
const http = axios.create({ baseURL: `${protocol}://judge0api.xuyue.cc` })
|
||||
|
||||
export async function submit(code: Code, input: string) {
|
||||
const encodedCode = encode(code.value)
|
||||
|
||||
if (encodedCode === deadResults[code.language].encoded) {
|
||||
return deadResults[code.language].result
|
||||
} else {
|
||||
const id = languageToId[code.language]
|
||||
let compilerOptions = ""
|
||||
if (id === 50) compilerOptions = "-lm" // 解决 GCC 的链接问题
|
||||
const payload = {
|
||||
source_code: encodedCode,
|
||||
language_id: id,
|
||||
stdin: encode(input),
|
||||
redirect_stderr_to_stdout: true,
|
||||
compiler_options: compilerOptions,
|
||||
}
|
||||
const response = await http.post("/submissions", payload, {
|
||||
params: { base64_encoded: true, wait: true },
|
||||
})
|
||||
const data = response.data
|
||||
return {
|
||||
status: data.status && data.status.id,
|
||||
output: [decode(data.compile_output), decode(data.stdout)]
|
||||
.join("\n")
|
||||
.trim(),
|
||||
}
|
||||
}
|
||||
}
|
||||
81
src/components/CodeEditor.vue
Normal file
81
src/components/CodeEditor.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<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 {
|
||||
label: string
|
||||
modelValue: string
|
||||
language?: LANGUAGE
|
||||
fontSize?: number
|
||||
readonly?: boolean
|
||||
placeholder?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
language: "c",
|
||||
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 === "c") {
|
||||
return cpp()
|
||||
}
|
||||
return python()
|
||||
})
|
||||
|
||||
function onChange(v: string) {
|
||||
emit("update:modelValue", v)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="title">{{ label }}</div>
|
||||
<Codemirror
|
||||
v-model="code"
|
||||
indentWithTab
|
||||
:extensions="[styleTheme, lang, isDark ? oneDark : smoothy]"
|
||||
:disabled="props.readonly"
|
||||
:tabSize="4"
|
||||
:placeholder="props.placeholder"
|
||||
:style="{ height: '100%', fontSize: props.fontSize + 'px' }"
|
||||
@change="onChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
.container {
|
||||
height: 100%;
|
||||
}
|
||||
.title {
|
||||
padding: 12px 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
6
src/composables/breakpoints.ts
Normal file
6
src/composables/breakpoints.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { breakpointsTailwind, useBreakpoints } from "@vueuse/core"
|
||||
|
||||
const breakpoints = useBreakpoints(breakpointsTailwind)
|
||||
|
||||
export const isMobile = breakpoints.smallerOrEqual("md")
|
||||
export const isDesktop = breakpoints.greater("md")
|
||||
35
src/composables/code.ts
Normal file
35
src/composables/code.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { ref } from "vue"
|
||||
import copyTextToClipboard from "copy-text-to-clipboard"
|
||||
import { Code } from "../types"
|
||||
import { sources } from "../templates"
|
||||
import { submit } from "../api"
|
||||
|
||||
export const code = ref<Code>({
|
||||
value: sources["python"],
|
||||
language: "python",
|
||||
})
|
||||
export const input = ref("")
|
||||
export const output = ref("")
|
||||
export const loading = ref(false)
|
||||
|
||||
export function copy() {
|
||||
copyTextToClipboard(code.value.value)
|
||||
}
|
||||
|
||||
export function reset() {
|
||||
code.value.value = sources["python"]
|
||||
output.value = ""
|
||||
}
|
||||
|
||||
export async function run() {
|
||||
loading.value = true
|
||||
const cleanCode = code.value.value.trim()
|
||||
if (!cleanCode) return
|
||||
output.value = ""
|
||||
const result = await submit(
|
||||
{ value: cleanCode, language: code.value.language },
|
||||
input.value.trim(),
|
||||
)
|
||||
output.value = result.output || ""
|
||||
loading.value = false
|
||||
}
|
||||
37
src/desktop/Content.vue
Normal file
37
src/desktop/Content.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<n-layout-content class="container">
|
||||
<n-split direction="horizontal" :min="1 / 3" :max="4 / 5">
|
||||
<template #1>
|
||||
<CodeEditor
|
||||
label="代码区"
|
||||
v-model="code.value"
|
||||
:language="code.language"
|
||||
/>
|
||||
</template>
|
||||
<template #2>
|
||||
<n-split
|
||||
direction="vertical"
|
||||
:default-size="1 / 3"
|
||||
:min="1 / 5"
|
||||
:max="3 / 5"
|
||||
>
|
||||
<template #1>
|
||||
<CodeEditor label="输入框" v-model="input" />
|
||||
</template>
|
||||
<template #2>
|
||||
<CodeEditor label="输出框" v-model="output" readonly />
|
||||
</template>
|
||||
</n-split>
|
||||
</template>
|
||||
</n-split>
|
||||
</n-layout-content>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { code, input, output } from "../composables/code"
|
||||
import CodeEditor from "../components/CodeEditor.vue"
|
||||
</script>
|
||||
<style scoped>
|
||||
.container {
|
||||
height: calc(100vh - 60px);
|
||||
}
|
||||
</style>
|
||||
53
src/desktop/Header.vue
Normal file
53
src/desktop/Header.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectOption } from "naive-ui"
|
||||
import { useDark, useToggle } from "@vueuse/core"
|
||||
import Play from "../icons/Play.vue"
|
||||
import { copy, reset, run, loading } from "../composables/code"
|
||||
|
||||
const isDark = useDark()
|
||||
const toggleDark = useToggle(isDark)
|
||||
|
||||
const languages: SelectOption[] = [
|
||||
{ value: "c", label: "C" },
|
||||
{ value: "python", label: "Python" },
|
||||
{ value: "cpp", label: "C++" },
|
||||
{ value: "java", label: "Java" },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-layout-header bordered class="header">
|
||||
<n-flex justify="space-between" align="center">
|
||||
<div class="title">徐越的自测猫</div>
|
||||
<n-flex>
|
||||
<n-button @click="toggleDark()">
|
||||
{{ isDark ? "浅色" : "深色" }}
|
||||
</n-button>
|
||||
<n-button @click="reset">重置</n-button>
|
||||
<n-button @click="copy">复制</n-button>
|
||||
<n-select class="select" :options="languages"></n-select>
|
||||
<n-button type="primary" @click="run" :loading="loading">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<Play />
|
||||
</n-icon>
|
||||
</template>
|
||||
运行 (F5)
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</n-layout-header>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.header {
|
||||
height: 60px;
|
||||
padding: 12px;
|
||||
}
|
||||
.title {
|
||||
font-size: 20px;
|
||||
}
|
||||
.select {
|
||||
width: 100px;
|
||||
}
|
||||
</style>
|
||||
8
src/desktop/index.vue
Normal file
8
src/desktop/index.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<Header />
|
||||
<Content />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import Header from "./Header.vue"
|
||||
import Content from "./Content.vue"
|
||||
</script>
|
||||
15
src/icons/Play.vue
Normal file
15
src/icons/Play.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<svg
|
||||
viewBox="0 0 1024 1024"
|
||||
focusable="false"
|
||||
data-icon="caret-right"
|
||||
width="18px"
|
||||
height="18px"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M715.8 493.5L335 165.1c-14.2-12.2-35-1.2-35 18.5v656.8c0 19.7 20.8 30.7 35 18.5l380.8-328.4c10.9-9.4 10.9-27.6 0-37z"
|
||||
></path>
|
||||
</svg>
|
||||
</template>
|
||||
37
src/main.ts
Normal file
37
src/main.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { createApp } from "vue"
|
||||
import {
|
||||
create,
|
||||
NButton,
|
||||
NConfigProvider,
|
||||
NInput,
|
||||
NLayout,
|
||||
NLayoutContent,
|
||||
NLayoutHeader,
|
||||
NSelect,
|
||||
NSpace,
|
||||
NSplit,
|
||||
NFlex,
|
||||
NIcon,
|
||||
} from "naive-ui"
|
||||
import App from "./App.vue"
|
||||
import "normalize.css"
|
||||
|
||||
const naive = create({
|
||||
components: [
|
||||
NButton,
|
||||
NConfigProvider,
|
||||
NLayout,
|
||||
NLayoutHeader,
|
||||
NLayoutContent,
|
||||
NSpace,
|
||||
NInput,
|
||||
NSelect,
|
||||
NSplit,
|
||||
NFlex,
|
||||
NIcon,
|
||||
],
|
||||
})
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(naive)
|
||||
app.mount("#app")
|
||||
1
src/mobile/index.vue
Normal file
1
src/mobile/index.vue
Normal file
@@ -0,0 +1 @@
|
||||
<template></template>
|
||||
55
src/templates.ts
Normal file
55
src/templates.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
const cSource =
|
||||
'#include<stdio.h>\r\n\r\nint main()\r\n{\r\n printf("黄岩一职");\r\n return 0;\r\n}'
|
||||
const cppSource =
|
||||
'#include<iostream>\r\n\r\nusing namespace std;\r\n\r\nint main()\r\n{\r\n cout<<"黄岩一职"<<endl;\r\n return 0;\r\n}'
|
||||
const pythonSource = 'print("黄岩一职")'
|
||||
const javaSource =
|
||||
'public class Main {\r\n public static void main(String[] args) {\r\n System.out.println("黄岩一职");\r\n }\r\n}'
|
||||
|
||||
export const languageToId = {
|
||||
c: 50,
|
||||
cpp: 54,
|
||||
java: 62,
|
||||
python: 71,
|
||||
}
|
||||
|
||||
export const sources = {
|
||||
c: cSource,
|
||||
cpp: cppSource,
|
||||
java: javaSource,
|
||||
python: pythonSource,
|
||||
}
|
||||
|
||||
export const deadResults = {
|
||||
c: {
|
||||
encoded:
|
||||
"I2luY2x1ZGU8c3RkaW8uaD4NCg0KaW50IG1haW4oKQ0Kew0KICAgIHByaW50Zigi6buE5bKp5LiA6IGMIik7DQogICAgcmV0dXJuIDA7DQp9",
|
||||
result: {
|
||||
status: 3,
|
||||
output: "黄岩一职",
|
||||
},
|
||||
},
|
||||
cpp: {
|
||||
encoded:
|
||||
"I2luY2x1ZGU8aW9zdHJlYW0+DQoNCnVzaW5nIG5hbWVzcGFjZSBzdGQ7DQoNCmludCBtYWluKCkNCnsNCiAgICBjb3V0PDwi6buE5bKp5LiA6IGMIjw8ZW5kbDsNCiAgICByZXR1cm4gMDsNCn0=",
|
||||
result: {
|
||||
status: 3,
|
||||
output: "黄岩一职",
|
||||
},
|
||||
},
|
||||
python: {
|
||||
encoded: "cHJpbnQoIum7hOWyqeS4gOiBjCIp",
|
||||
result: {
|
||||
status: 3,
|
||||
output: "黄岩一职",
|
||||
},
|
||||
},
|
||||
java: {
|
||||
encoded:
|
||||
"cHVibGljIGNsYXNzIE1haW4gew0KICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpIHsNCiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCLpu4TlsqnkuIDogYwiKTsNCiAgICB9DQp9",
|
||||
result: {
|
||||
status: 3,
|
||||
output: "黄岩一职",
|
||||
},
|
||||
},
|
||||
}
|
||||
110
src/themes/createTheme.ts
Normal file
110
src/themes/createTheme.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { EditorView } from "@codemirror/view"
|
||||
import { Extension } from "@codemirror/state"
|
||||
import {
|
||||
HighlightStyle,
|
||||
TagStyle,
|
||||
syntaxHighlighting,
|
||||
} from "@codemirror/language"
|
||||
|
||||
interface Options {
|
||||
/**
|
||||
* Theme variant. Determines which styles CodeMirror will apply by default.
|
||||
*/
|
||||
variant: Variant
|
||||
|
||||
/**
|
||||
* Settings to customize the look of the editor, like background, gutter, selection and others.
|
||||
*/
|
||||
settings: Settings
|
||||
|
||||
/**
|
||||
* Syntax highlighting styles.
|
||||
*/
|
||||
styles: TagStyle[]
|
||||
}
|
||||
|
||||
type Variant = "light" | "dark"
|
||||
|
||||
interface Settings {
|
||||
/**
|
||||
* Editor background.
|
||||
*/
|
||||
background: string
|
||||
|
||||
/**
|
||||
* Default text color.
|
||||
*/
|
||||
foreground: string
|
||||
|
||||
/**
|
||||
* Caret color.
|
||||
*/
|
||||
caret: string
|
||||
|
||||
/**
|
||||
* Selection background.
|
||||
*/
|
||||
selection: string
|
||||
|
||||
/**
|
||||
* Background of highlighted lines.
|
||||
*/
|
||||
lineHighlight: string
|
||||
|
||||
/**
|
||||
* Gutter background.
|
||||
*/
|
||||
gutterBackground: string
|
||||
|
||||
/**
|
||||
* Text color inside gutter.
|
||||
*/
|
||||
gutterForeground: string
|
||||
|
||||
gutterBorderRight: string
|
||||
}
|
||||
|
||||
export const createTheme = ({
|
||||
variant,
|
||||
settings,
|
||||
styles,
|
||||
}: Options): Extension => {
|
||||
const theme = EditorView.theme(
|
||||
{
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
"&": {
|
||||
backgroundColor: settings.background,
|
||||
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,
|
||||
},
|
||||
},
|
||||
{
|
||||
dark: variant === "dark",
|
||||
},
|
||||
)
|
||||
|
||||
const highlightStyle = HighlightStyle.define(styles)
|
||||
const extension = [theme, syntaxHighlighting(highlightStyle)]
|
||||
|
||||
return extension
|
||||
}
|
||||
149
src/themes/oneDark.ts
Normal file
149
src/themes/oneDark.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import { EditorView } from "@codemirror/view"
|
||||
import { Extension } from "@codemirror/state"
|
||||
import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"
|
||||
import { tags as t } from "@lezer/highlight"
|
||||
|
||||
// Using https://github.com/one-dark/vscode-one-dark-theme/ as reference for the colors
|
||||
|
||||
const chalky = "#e5c07b",
|
||||
coral = "#e06c75",
|
||||
cyan = "#56b6c2",
|
||||
invalid = "#ffffff",
|
||||
ivory = "#abb2bf",
|
||||
stone = "#7d8799", // Brightened compared to original to increase contrast
|
||||
malibu = "#61afef",
|
||||
sage = "#98c379",
|
||||
whiskey = "#d19a66",
|
||||
violet = "#c678dd",
|
||||
darkBackground = "#26262a",
|
||||
highlightBackground = "#2c313a",
|
||||
background = "#101014", // naive-ui
|
||||
tooltipBackground = "#353a42",
|
||||
selection = "#3E4451",
|
||||
cursor = "#528bff"
|
||||
|
||||
/// The editor theme styles for One Dark.
|
||||
const oneDarkTheme = EditorView.theme(
|
||||
{
|
||||
"&": {
|
||||
color: ivory,
|
||||
backgroundColor: background,
|
||||
},
|
||||
|
||||
".cm-content": {
|
||||
caretColor: cursor,
|
||||
},
|
||||
|
||||
".cm-cursor, .cm-dropCursor": { borderLeftColor: cursor },
|
||||
"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection":
|
||||
{ backgroundColor: selection },
|
||||
|
||||
".cm-panels": { backgroundColor: darkBackground, color: ivory },
|
||||
".cm-panels.cm-panels-top": { borderBottom: "2px solid black" },
|
||||
".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" },
|
||||
|
||||
".cm-searchMatch": {
|
||||
backgroundColor: "#72a1ff59",
|
||||
outline: "1px solid #457dff",
|
||||
},
|
||||
".cm-searchMatch.cm-searchMatch-selected": {
|
||||
backgroundColor: "#6199ff2f",
|
||||
},
|
||||
|
||||
".cm-activeLine": { backgroundColor: "#6699ff0b" },
|
||||
".cm-selectionMatch": { backgroundColor: "#aafe661a" },
|
||||
|
||||
"&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": {
|
||||
backgroundColor: "#bad0f847",
|
||||
},
|
||||
|
||||
".cm-gutters": {
|
||||
backgroundColor: background,
|
||||
color: stone,
|
||||
border: "none",
|
||||
},
|
||||
|
||||
".cm-activeLineGutter": {
|
||||
backgroundColor: highlightBackground,
|
||||
},
|
||||
|
||||
".cm-foldPlaceholder": {
|
||||
backgroundColor: "transparent",
|
||||
border: "none",
|
||||
color: "#ddd",
|
||||
},
|
||||
|
||||
".cm-tooltip": {
|
||||
border: "none",
|
||||
backgroundColor: tooltipBackground,
|
||||
},
|
||||
".cm-tooltip .cm-tooltip-arrow:before": {
|
||||
borderTopColor: "transparent",
|
||||
borderBottomColor: "transparent",
|
||||
},
|
||||
".cm-tooltip .cm-tooltip-arrow:after": {
|
||||
borderTopColor: tooltipBackground,
|
||||
borderBottomColor: tooltipBackground,
|
||||
},
|
||||
".cm-tooltip-autocomplete": {
|
||||
"& > ul > li[aria-selected]": {
|
||||
backgroundColor: highlightBackground,
|
||||
color: ivory,
|
||||
},
|
||||
},
|
||||
},
|
||||
{ dark: true },
|
||||
)
|
||||
|
||||
/// The highlighting style for code in the One Dark theme.
|
||||
const oneDarkHighlightStyle = HighlightStyle.define([
|
||||
{ tag: t.keyword, color: violet },
|
||||
{
|
||||
tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName],
|
||||
color: coral,
|
||||
},
|
||||
{ tag: [t.function(t.variableName), t.labelName], color: malibu },
|
||||
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: whiskey },
|
||||
{ tag: [t.definition(t.name), t.separator], color: ivory },
|
||||
{
|
||||
tag: [
|
||||
t.typeName,
|
||||
t.className,
|
||||
t.number,
|
||||
t.changed,
|
||||
t.annotation,
|
||||
t.modifier,
|
||||
t.self,
|
||||
t.namespace,
|
||||
],
|
||||
color: chalky,
|
||||
},
|
||||
{
|
||||
tag: [
|
||||
t.operator,
|
||||
t.operatorKeyword,
|
||||
t.url,
|
||||
t.escape,
|
||||
t.regexp,
|
||||
t.link,
|
||||
t.special(t.string),
|
||||
],
|
||||
color: cyan,
|
||||
},
|
||||
{ tag: [t.meta, t.comment], color: stone },
|
||||
{ tag: t.strong, fontWeight: "bold" },
|
||||
{ tag: t.emphasis, fontStyle: "italic" },
|
||||
{ tag: t.strikethrough, textDecoration: "line-through" },
|
||||
{ tag: t.link, color: stone, textDecoration: "underline" },
|
||||
{ tag: t.heading, fontWeight: "bold", color: coral },
|
||||
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: whiskey },
|
||||
{ tag: [t.processingInstruction, t.string, t.inserted], color: sage },
|
||||
{ tag: t.invalid, color: invalid },
|
||||
])
|
||||
|
||||
/// Extension to enable the One Dark theme (both the editor theme and
|
||||
/// the highlight style).
|
||||
export const oneDark: Extension = [
|
||||
oneDarkTheme,
|
||||
syntaxHighlighting(oneDarkHighlightStyle),
|
||||
]
|
||||
83
src/themes/smoothy.ts
Normal file
83
src/themes/smoothy.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { tags as t } from "@lezer/highlight"
|
||||
import { createTheme } from "./createTheme"
|
||||
|
||||
// Author: Kenneth Reitz
|
||||
export const smoothy = createTheme({
|
||||
variant: "light",
|
||||
settings: {
|
||||
background: "#FFFFFF",
|
||||
foreground: "#000000",
|
||||
caret: "#000000",
|
||||
selection: "#FFFD0054",
|
||||
gutterBackground: "#FFFFFF",
|
||||
gutterForeground: "#00000070",
|
||||
gutterBorderRight: "none",
|
||||
lineHighlight: "#00000008",
|
||||
},
|
||||
styles: [
|
||||
{
|
||||
tag: t.comment,
|
||||
color: "#CFCFCF",
|
||||
},
|
||||
{
|
||||
tag: [t.number, t.bool, t.null],
|
||||
color: "#E66C29",
|
||||
},
|
||||
{
|
||||
tag: [
|
||||
t.className,
|
||||
t.definition(t.propertyName),
|
||||
t.function(t.variableName),
|
||||
t.labelName,
|
||||
t.definition(t.typeName),
|
||||
],
|
||||
color: "#2EB43B",
|
||||
},
|
||||
{
|
||||
tag: t.keyword,
|
||||
color: "#D8B229",
|
||||
},
|
||||
{
|
||||
tag: t.operator,
|
||||
color: "#4EA44E",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
{
|
||||
tag: [t.definitionKeyword, t.modifier],
|
||||
color: "#925A47",
|
||||
},
|
||||
{
|
||||
tag: t.string,
|
||||
color: "#704D3D",
|
||||
},
|
||||
{
|
||||
tag: t.typeName,
|
||||
color: "#2F8996",
|
||||
},
|
||||
{
|
||||
tag: [t.variableName, t.propertyName],
|
||||
color: "#77ACB0",
|
||||
},
|
||||
{
|
||||
tag: t.self,
|
||||
color: "#77ACB0",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
{
|
||||
tag: t.regexp,
|
||||
color: "#E3965E",
|
||||
},
|
||||
{
|
||||
tag: [t.tagName, t.angleBracket],
|
||||
color: "#BAA827",
|
||||
},
|
||||
{
|
||||
tag: t.attributeName,
|
||||
color: "#B06520",
|
||||
},
|
||||
{
|
||||
tag: t.derefOperator,
|
||||
color: "#000",
|
||||
},
|
||||
],
|
||||
})
|
||||
6
src/types.ts
Normal file
6
src/types.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export type LANGUAGE = "c" | "cpp" | "python" | "java"
|
||||
|
||||
export interface Code {
|
||||
value: string
|
||||
language: LANGUAGE
|
||||
}
|
||||
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
Reference in New Issue
Block a user