use composables.
This commit is contained in:
1147
public/dark.json
Normal file
1147
public/dark.json
Normal file
File diff suppressed because it is too large
Load Diff
1144
public/light.json
Normal file
1144
public/light.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ import Md from "./step-1/index.md"
|
|||||||
import Monaco from "../shared/monaco/index.vue"
|
import Monaco from "../shared/monaco/index.vue"
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
console.log(route.params.step)
|
// console.log(route.params.step)
|
||||||
|
|
||||||
const code = ref("")
|
const code = ref("")
|
||||||
|
|
||||||
@@ -19,6 +19,7 @@ function change(value: string) {
|
|||||||
<Md />
|
<Md />
|
||||||
{{ code }}
|
{{ code }}
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<!-- TODO: 这里有BUG -->
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<Monaco :value="code" @change="change" />
|
<Monaco :value="code" @change="change" />
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|||||||
15
src/main.ts
15
src/main.ts
@@ -1,6 +1,7 @@
|
|||||||
import { createRouter, createWebHistory } from "vue-router"
|
import { createRouter, createWebHistory } from "vue-router"
|
||||||
import { createPinia } from "pinia"
|
import { createPinia } from "pinia"
|
||||||
import "normalize.css"
|
import "normalize.css"
|
||||||
|
import "element-plus/theme-chalk/dark/css-vars.css"
|
||||||
import loader from "@monaco-editor/loader"
|
import loader from "@monaco-editor/loader"
|
||||||
|
|
||||||
import storage from "utils/storage"
|
import storage from "utils/storage"
|
||||||
@@ -9,7 +10,7 @@ import { STORAGE_KEY } from "utils/constants"
|
|||||||
import { routes } from "./routes"
|
import { routes } from "./routes"
|
||||||
import App from "./App.vue"
|
import App from "./App.vue"
|
||||||
|
|
||||||
import { useLoginStore } from "~/shared/store/login"
|
import { toggleLogin } from "./shared/composables/modal"
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(),
|
history: createWebHistory(),
|
||||||
@@ -19,8 +20,7 @@ const router = createRouter({
|
|||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
if (to.matched.some((record) => record.meta.requiresAuth)) {
|
if (to.matched.some((record) => record.meta.requiresAuth)) {
|
||||||
if (!storage.get(STORAGE_KEY.AUTHED)) {
|
if (!storage.get(STORAGE_KEY.AUTHED)) {
|
||||||
const login = useLoginStore()
|
toggleLogin(true)
|
||||||
login.show()
|
|
||||||
next("/")
|
next("/")
|
||||||
} else {
|
} else {
|
||||||
next()
|
next()
|
||||||
@@ -32,9 +32,14 @@ router.beforeEach((to, from, next) => {
|
|||||||
|
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
|
|
||||||
Promise.all([loader.init(), fetch("/dracula.json")]).then(([monaco, dark]) => {
|
loader.init().then((monaco) => {
|
||||||
window.monaco = monaco
|
window.monaco = monaco
|
||||||
dark.json().then((data) => monaco.editor.defineTheme("dark", data))
|
fetch("/dark.json").then((data) =>
|
||||||
|
data.json().then((theme) => monaco.editor.defineTheme("dark", theme))
|
||||||
|
)
|
||||||
|
fetch("/light.json").then((data) =>
|
||||||
|
data.json().then((theme) => monaco.editor.defineTheme("light", theme))
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
loader.config({
|
loader.config({
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { TabsPaneContext } from "element-plus"
|
||||||
import { SOURCES } from "utils/constants"
|
import { SOURCES } from "utils/constants"
|
||||||
import { Problem } from "utils/types"
|
import { Problem } from "utils/types"
|
||||||
import Monaco from "~/shared/Monaco/index.vue"
|
import Monaco from "~/shared/Monaco/index.vue"
|
||||||
import { useCodeStore } from "oj/store/code"
|
import { useCodeStore } from "oj/store/code"
|
||||||
import { submissionExists } from "oj/api"
|
import { submissionExists } from "oj/api"
|
||||||
import { TabsPaneContext } from "element-plus"
|
|
||||||
|
|
||||||
import SubmitPanel from "./SubmitPanel.vue"
|
import SubmitPanel from "./SubmitPanel.vue"
|
||||||
import TestcasePanel from "./TestcasePanel.vue"
|
import TestcasePanel from "./TestcasePanel.vue"
|
||||||
@@ -68,8 +68,8 @@ function onTab(pane: TabsPaneContext) {
|
|||||||
class="editor"
|
class="editor"
|
||||||
:language="code.language"
|
:language="code.language"
|
||||||
:value="code.value"
|
:value="code.value"
|
||||||
height="calc(100vh - 621px)"
|
|
||||||
@change="change"
|
@change="change"
|
||||||
|
height="calc(100vh - 621px)"
|
||||||
/>
|
/>
|
||||||
<el-tabs type="border-card" @tab-click="onTab" v-model="tab">
|
<el-tabs type="border-card" @tab-click="onTab" v-model="tab">
|
||||||
<TestcasePanel />
|
<TestcasePanel />
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export const routes = [
|
|||||||
{
|
{
|
||||||
path: "status",
|
path: "status",
|
||||||
component: () => import("oj/status/list.vue"),
|
component: () => import("oj/status/list.vue"),
|
||||||
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "status/:statusID",
|
path: "status/:statusID",
|
||||||
@@ -44,7 +45,7 @@ export const routes = [
|
|||||||
{
|
{
|
||||||
path: "/learn",
|
path: "/learn",
|
||||||
component: () => import("~/shared/layout/default.vue"),
|
component: () => import("~/shared/layout/default.vue"),
|
||||||
children: [{ path: ":step*", component: () => import("learn/index.vue") }],
|
children: [{ path: "", component: () => import("learn/index.vue") }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/admin",
|
path: "/admin",
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useLoginStore } from "../store/login"
|
import { Sunny, Moon } from "@element-plus/icons-vue"
|
||||||
import { useSignupStore } from "~/shared/store/signup"
|
|
||||||
import { logout } from "../api"
|
import { logout } from "../api"
|
||||||
import { useUserStore } from "../store/user"
|
import { useUserStore } from "../store/user"
|
||||||
|
import { isDark, toggleDark } from "~/shared/composables/dark"
|
||||||
|
import { toggleLogin, toggleSignup } from "~/shared/composables/modal"
|
||||||
|
|
||||||
const loginStore = useLoginStore()
|
|
||||||
const signupStore = useSignupStore()
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
@@ -34,26 +33,33 @@ onMounted(userStore.getMyProfile)
|
|||||||
<el-menu-item index="/status">提交</el-menu-item>
|
<el-menu-item index="/status">提交</el-menu-item>
|
||||||
<el-menu-item index="/rank">排名</el-menu-item>
|
<el-menu-item index="/rank">排名</el-menu-item>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
<div v-if="userStore.isFinished && !userStore.isAuthed" class="actions">
|
<el-space class="actions">
|
||||||
<el-button @click="loginStore.show">登录</el-button>
|
<el-button
|
||||||
<el-button @click="signupStore.show">注册</el-button>
|
circle
|
||||||
</div>
|
:icon="isDark ? Sunny : Moon"
|
||||||
<div v-if="userStore.isFinished && userStore.isAuthed" class="actions">
|
@click="toggleDark()"
|
||||||
<el-dropdown @command="handleDropdown">
|
></el-button>
|
||||||
<el-button>{{ userStore.user.username }}</el-button>
|
<div v-if="userStore.isFinished && !userStore.isAuthed">
|
||||||
<template #dropdown>
|
<el-button @click="toggleLogin(true)">登录</el-button>
|
||||||
<el-dropdown-menu>
|
<el-button @click="toggleSignup(true)">注册</el-button>
|
||||||
<el-dropdown-item>我的主页</el-dropdown-item>
|
</div>
|
||||||
<el-dropdown-item>我的提交</el-dropdown-item>
|
<div v-if="userStore.isFinished && userStore.isAuthed">
|
||||||
<el-dropdown-item>我的设置</el-dropdown-item>
|
<el-dropdown @command="handleDropdown">
|
||||||
<el-dropdown-item v-if="userStore.isAdminRole">
|
<el-button>{{ userStore.user.username }}</el-button>
|
||||||
后台管理
|
<template #dropdown>
|
||||||
</el-dropdown-item>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item divided command="logout">退出</el-dropdown-item>
|
<el-dropdown-item>我的主页</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
<el-dropdown-item>我的提交</el-dropdown-item>
|
||||||
</template>
|
<el-dropdown-item>我的设置</el-dropdown-item>
|
||||||
</el-dropdown>
|
<el-dropdown-item v-if="userStore.isAdminRole">
|
||||||
</div>
|
后台管理
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item divided command="logout">退出</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
</el-space>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { FormInstance } from "element-plus"
|
import { FormInstance } from "element-plus"
|
||||||
import { useSignupStore } from "~/shared/store/signup"
|
|
||||||
import { login } from "../api"
|
import { login } from "../api"
|
||||||
import { useLoginStore } from "../store/login"
|
import { loginModal, toggleLogin, toggleSignup } from "../composables/modal"
|
||||||
import { useUserStore } from "../store/user"
|
import { useUserStore } from "../store/user"
|
||||||
|
|
||||||
const loginStore = useLoginStore()
|
|
||||||
const signupStore = useSignupStore()
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const loginRef = ref<FormInstance>()
|
const loginRef = ref<FormInstance>()
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
@@ -29,15 +26,15 @@ async function submit() {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
await execute()
|
await execute()
|
||||||
if (!error.value) {
|
if (!error.value) {
|
||||||
loginStore.hide()
|
toggleLogin(false)
|
||||||
userStore.getMyProfile()
|
userStore.getMyProfile()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function goSignup() {
|
function goSignup() {
|
||||||
loginStore.hide()
|
toggleLogin(false)
|
||||||
signupStore.show()
|
toggleSignup(true)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -46,7 +43,7 @@ function goSignup() {
|
|||||||
style="max-width: 400px"
|
style="max-width: 400px"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
:close-on-press-escape="false"
|
:close-on-press-escape="false"
|
||||||
v-model="loginStore.visible"
|
v-model="loginModal"
|
||||||
title="登录"
|
title="登录"
|
||||||
>
|
>
|
||||||
<el-form
|
<el-form
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type * as Monaco from "monaco-editor"
|
|||||||
import { LANGUAGE_VALUE } from "utils/constants"
|
import { LANGUAGE_VALUE } from "utils/constants"
|
||||||
import { LANGUAGE } from "utils/types"
|
import { LANGUAGE } from "utils/types"
|
||||||
import { isMobile } from "utils/breakpoints"
|
import { isMobile } from "utils/breakpoints"
|
||||||
|
import { isDark } from "../composables/dark"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
value: string
|
value: string
|
||||||
@@ -35,7 +36,7 @@ onMounted(function () {
|
|||||||
|
|
||||||
editor = window.monaco.editor.create(monacoEditorRef.value, {
|
editor = window.monaco.editor.create(monacoEditorRef.value, {
|
||||||
model,
|
model,
|
||||||
theme: "dark", // 官方自带三种主题vs, hc-black, or vs-dark
|
theme: isDark.value ? "dark" : "light", // 官方自带三种主题vs, hc-black, or vs-dark
|
||||||
minimap: {
|
minimap: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
@@ -78,6 +79,10 @@ onMounted(function () {
|
|||||||
model.setValue(props.value)
|
model.setValue(props.value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
window.monaco.editor.setTheme(isDark.value ? "dark" : "light")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useSignupStore } from "../store/signup"
|
import { signupModal } from "../composables/modal"
|
||||||
const store = useSignupStore()
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
:close-on-press-escape="false"
|
:close-on-press-escape="false"
|
||||||
v-model="store.visible"
|
v-model="signupModal"
|
||||||
title="注册"
|
title="注册"
|
||||||
>
|
>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|||||||
2
src/shared/composables/dark.ts
Normal file
2
src/shared/composables/dark.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export const isDark = useDark({ storageKey: "theme-appearance" })
|
||||||
|
export const toggleDark = useToggle(isDark)
|
||||||
2
src/shared/composables/modal.ts
Normal file
2
src/shared/composables/modal.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export const [loginModal, toggleLogin] = useToggle()
|
||||||
|
export const [signupModal, toggleSignup] = useToggle()
|
||||||
@@ -3,6 +3,7 @@ import type * as Monaco from "monaco-editor"
|
|||||||
import { LANGUAGE_VALUE } from "utils/constants"
|
import { LANGUAGE_VALUE } from "utils/constants"
|
||||||
import { LANGUAGE } from "utils/types"
|
import { LANGUAGE } from "utils/types"
|
||||||
import { isMobile } from "utils/breakpoints"
|
import { isMobile } from "utils/breakpoints"
|
||||||
|
import { isDark } from "../composables/dark"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
value: string
|
value: string
|
||||||
@@ -35,7 +36,7 @@ onMounted(function () {
|
|||||||
|
|
||||||
editor = window.monaco.editor.create(monacoEditorRef.value, {
|
editor = window.monaco.editor.create(monacoEditorRef.value, {
|
||||||
model,
|
model,
|
||||||
theme: "dark", // 官方自带三种主题vs, hc-black, or vs-dark
|
theme: isDark.value ? "dark" : "light", // 官方自带三种主题vs, hc-black, or vs-dark
|
||||||
minimap: {
|
minimap: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
@@ -78,6 +79,10 @@ onMounted(function () {
|
|||||||
model.setValue(props.value)
|
model.setValue(props.value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
window.monaco.editor.setTheme(isDark.value ? "dark" : "light")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
export const useLoginStore = defineStore("login", () => {
|
|
||||||
const [visible] = useToggle()
|
|
||||||
|
|
||||||
function show() {
|
|
||||||
visible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function hide() {
|
|
||||||
visible.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
return { visible, show, hide }
|
|
||||||
})
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
export const useSignupStore = defineStore("signup", () => {
|
|
||||||
const [visible] = useToggle()
|
|
||||||
|
|
||||||
function show() {
|
|
||||||
visible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function hide() {
|
|
||||||
visible.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
return { visible, show, hide }
|
|
||||||
})
|
|
||||||
Reference in New Issue
Block a user