添加主题

This commit is contained in:
zyronon
2023-08-16 00:21:52 +08:00
parent 934e54a477
commit d59038e2d3
7 changed files with 204 additions and 90 deletions

View File

@@ -20,6 +20,9 @@ import {usePlayWordAudio} from "@/hooks/usePlayWordAudio.ts"
import DictModal from "@/components/DictModal.vue"
import Backgorund from "@/components/Backgorund.vue"
import Statistics from "@/components/Statistics.vue";
import {ArrowLeft, ArrowRight, MenuFold} from '@icon-park/vue-next'
import useThemeColor from "@/hooks/useThemeColor";
import Tooltip from "@/components/Tooltip.vue";
let input = $ref('')
let wrong = $ref('')
@@ -158,46 +161,63 @@ onMounted(() => {
})
const show = $ref(false)
const {appearance, toggle} = useThemeColor()
</script>
<template>
<Backgorund/>
<div class="main-page">
<button @click="store.dictModalIsOpen = true">ok</button>
<button @click="store.dictModalIsOpen2 = true">ok</button>
<div class="content">
<div class="type-word">
<div class="translate">{{ store.word.trans.join('') }}</div>
<div class="word-wrapper">
<div class="word" :class="wrong&&'is-wrong'">
<span class="input" v-if="input">{{ input }}</span>
<span class="wrong" v-if="wrong">{{ wrong }}</span>
<template v-if="isDictation">
<div class="center">
<header>
<div class="info">
</div>
<div class="options">
<div class="my-button" @click="toggle">切换</div>
<div class="my-button" @click="store.dictModalIsOpen = true">ok</div>
<div class="my-button" @click="store.dictModalIsOpen2 = true">ok</div>
<Tooltip title="单词本">
<menu-fold class="menu" @click="store.sideIsOpen = !store.sideIsOpen"
theme="outline" size="20" fill="#929596"
:strokeWidth="2"/>
</Tooltip>
</div>
</header>
<div class="content">
<div class="type-word">
<div class="translate">{{ store.word.trans.join('') }}</div>
<div class="word-wrapper">
<div class="word" :class="wrong&&'is-wrong'">
<span class="input" v-if="input">{{ input }}</span>
<span class="wrong" v-if="wrong">{{ wrong }}</span>
<template v-if="isDictation">
<span class="letter" v-if="!showFullWord"
@mouseenter="showFullWord = true">{{ restWord.split('').map(v => '_').join('') }}</span>
<span class="letter" v-else @mouseleave="showFullWord = false">{{ restWord }}</span>
</template>
<span class="letter" v-else>{{ restWord }}</span>
<span class="letter" v-else @mouseleave="showFullWord = false">{{ restWord }}</span>
</template>
<span class="letter" v-else>{{ restWord }}</span>
</div>
<div class="audio" @click="playAudio(store.word.name)">播放</div>
</div>
<div class="phonetic">{{ store.word.usphone }}</div>
<div class="options">
<div class="option" :class="activeIndex === 0 &&'active'">忽略</div>
<div class="option" :class="activeIndex === 1 &&'active'">收藏</div>
<div class="option" :class="activeIndex === 2 &&'active'">下一个</div>
</div>
<div class="audio" @click="playAudio(store.word.name)">播放</div>
</div>
<div class="phonetic">{{ store.word.usphone }}</div>
<div class="options">
<div class="option" :class="activeIndex === 0 &&'active'">忽略</div>
<div class="option" :class="activeIndex === 1 &&'active'">收藏</div>
<div class="option" :class="activeIndex === 2 &&'active'">下一个</div>
</div>
</div>
<Side/>
</div>
<Side/>
<Statistics></Statistics>
<DictModal/>
</div>
</template>
<style scoped lang="scss">
@import "@/assets/css/colors";
@import "@/assets/css/colors.scss";
.main-page {
position: absolute;
@@ -206,73 +226,105 @@ const show = $ref(false)
width: 100vw;
height: 100%;
overflow: hidden;
display: flex;
font-size: 14rem;
display: flex;
justify-content: center;
.content {
flex: 1;
.center {
width: 70vw;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: 1px solid gray;
position: relative;
.type-word {
header {
margin-top: 10rem;
height: 60rem;
width: 50%;
background: var(--color-header-bg);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
font-size: 14rem;
color: gray;
gap: 2rem;
justify-content: space-between;
border-radius: 8rem;
position: relative;
z-index: 2;
padding: 10rem $space;
box-sizing: border-box;
.options {
margin-top: 10rem;
display: flex;
gap: 15rem;
font-size: 18rem;
.option {
cursor: pointer;
padding: 6rem 10rem;
border-radius: 4rem;
background: gray;
color: white;
&:hover {
//background: rgb(70, 67, 67) !important;
background: red;
}
&.active {
background: red;
}
}
}
.phonetic, .translate {
font-size: 20rem;
}
.word-wrapper {
display: flex;
align-items: center;
gap: 10rem;
}
}
.word {
font-size: 48rem;
line-height: 1;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
letter-spacing: 5rem;
.content {
position: relative;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
.input {
color: rgba(74, 222, 128, 0.8);
.type-word {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
font-size: 14rem;
color: gray;
gap: 2rem;
.options {
margin-top: 10rem;
display: flex;
gap: 15rem;
font-size: 18rem;
.option {
cursor: pointer;
padding: 6rem 10rem;
border-radius: 4rem;
background: gray;
color: white;
&:hover {
//background: rgb(70, 67, 67) !important;
background: red;
}
&.active {
background: red;
}
}
}
.wrong {
color: rgba(red, 0.6);
}
.phonetic, .translate {
font-size: 20rem;
}
&.is-wrong {
animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
.word-wrapper {
display: flex;
align-items: center;
gap: 10rem;
.word {
font-size: 48rem;
line-height: 1;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
letter-spacing: 5rem;
.input {
color: rgba(74, 222, 128, 0.8);
}
.wrong {
color: rgba(red, 0.6);
}
&.is-wrong {
animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
}
}
}
}

View File

@@ -2,6 +2,25 @@
@import "colors";
@import "anim";
:root {
--color-main-bg: rgb(226, 226, 226);
--color-second-bg: rgb(238,240,244);
--color-header-bg: white;
--color-font: black;
}
html[data-theme='dark'] {
--color-main-bg: rgba(0, 5, 24, 1);
--color-second-bg: rgb(60, 63, 65);
--color-header-bg: white;
}
$anim-time: 0.3s;
* {
transition: background-color $anim-time, color $anim-time;
}
html, body {
padding: 0;
margin: 0;

View File

@@ -90,7 +90,6 @@ onMounted(() => {
</script>
<style scoped lang="scss">
@import "@/assets/css/colors";
#background {
position: fixed;
@@ -98,7 +97,7 @@ onMounted(() => {
height: 100vh;
left: 0;
top: 0;
background: $dark-main-bg;
background-color: var(--color-main-bg);
canvas {
width: 100vw;

View File

@@ -40,16 +40,12 @@ function changeDict(dict: Dict, i: number) {
<div class="tab" :class="tabIndex===1&&'active'" @click="slideTo(1)">生词本</div>
<div class="tab" :class="tabIndex===2&&'active'" @click="slideTo(2)">已忽略</div>
</div>
<arrow-right class="close"
@click="store.sideIsOpen = false"
theme="outline" size="20" fill="#929596" :strokeWidth="2"/>
</header>
<div class="side-content">
<swiper @swiper="e=>swiperIns0 = e" class="mySwiper" :allow-touch-move="false">
<swiper-slide>
<div class="page0">
<header>
<arrow-left theme="outline" size="20" fill="#929596" :strokeWidth="2"/>
<div class="dict-name">{{ store.dict.chapterIndex + 1 }}.</div>
</header>
<WordList
@@ -119,9 +115,6 @@ function changeDict(dict: Dict, i: number) {
</swiper>
</div>
</div>
<menu-fold v-if="!store.sideIsOpen" class="menu" @click="store.sideIsOpen = true"
theme="outline" size="20" fill="#929596"
:strokeWidth="2"/>
</template>
<style scoped lang="scss">
@import "@/assets/css/colors";
@@ -134,16 +127,21 @@ function changeDict(dict: Dict, i: number) {
.side {
$width: 20vw;
position: absolute;
right: 0;
width: $width;
background: $dark-second-bg;
background: var(--color-second-bg);
height: 100%;
display: flex;
flex-direction: column;
transition: all .3s;
margin-right: -$width;
transform: rotate(-90deg);
transform-origin: 0 0 ;
z-index: 1;
&.open {
margin-right: 0;
//margin-right: 0;
transform: rotate(0deg);
}
$header-height: 40rem;
@@ -156,6 +154,7 @@ function changeDict(dict: Dict, i: number) {
.tabs {
padding: 10rem 20rem;
justify-content: flex-end;
width: 100%;
display: flex;
align-items: flex-end;
@@ -207,6 +206,7 @@ function changeDict(dict: Dict, i: number) {
position: relative;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 10rem;
font-size: 18rem;
color: white;

View File

@@ -23,7 +23,11 @@ export default {
this.show = true
nextTick(() => {
let tip = this.$refs.tip.getBoundingClientRect()
this.$refs.tip.style.top = rect.top - tip.height - 10 + 'px'
if (rect.top < 50) {
this.$refs.tip.style.top = rect.top + tip.height - 10 + 'px'
}else {
this.$refs.tip.style.top = rect.top - tip.height - 10 + 'px'
}
let tipWidth = tip.width
let rectWidth = rect.width
this.$refs.tip.style.left = rect.left - (tipWidth - rectWidth) / 2 + 'px'
@@ -53,7 +57,7 @@ export default {
}
</script>
<style lang="scss" scoped>
@import "@/assets/css/style";
@import "@/assets/css/style.scss";
.tip {
position: fixed;
@@ -61,6 +65,8 @@ export default {
z-index: 999;
border-radius: 4rem;
padding: 10rem;
background: $item-hover;
color: var(--color-font);
background: var(--color-header-bg);
box-shadow: 1px 1px 6px #bbbbbb;
}
</style>

View File

@@ -77,8 +77,7 @@ watch(() => props.list, () => {
box-sizing: border-box;
.item {
background: $dark-main-bg;
//background: $item-hover;
background: var(--color-header-bg);
border-radius: 6rem;
padding: 12rem;
//border: 1px solid gray;

View File

@@ -0,0 +1,39 @@
// 获取主题变量
import {ref, watchEffect} from "vue";
let appearance = ref<string>(localStorage.getItem('appearance') || 'auto')
// 查询当前系统主题颜色
const match: MediaQueryList = window.matchMedia("(prefers-color-scheme: dark)")
// 监听系统主题变化
match.addEventListener('change', followSystem)
function followSystem() {
const theme = match.matches ? 'dark' : 'light'
document.documentElement.setAttribute('data-theme', theme)
// document.documentElement.setAttribute('data-theme', 'dark')
}
watchEffect(() => {
// 如果主题变量为 auto, 则跟随系统主题
if (appearance.value === 'auto') {
followSystem()
} else {
document.documentElement.setAttribute('data-theme', appearance.value)
}
})
function toggle() {
if (appearance.value === 'auto') {
appearance.value = match.matches ? 'light' : 'dark'
} else {
appearance.value = appearance.value === 'light' ? 'dark' : 'light'
}
}
export default function useThemeColor() {
return {
appearance,
toggle
}
}