save
This commit is contained in:
14
Note.md
14
Note.md
@@ -65,4 +65,16 @@ I found this note on my car: 'Sir, we welcome you to our city. This is a 'No Par
|
||||
Food and talk
|
||||
A new play is coming to "The Globe"soon, I said. Will you be seeing it?
|
||||
|
||||
26的 of curse
|
||||
26的 of curse
|
||||
|
||||
1、例句可以选中单词,并添加到收藏
|
||||
|
||||
1、域名:你需要一个真正的品牌,type域名,契合内容,让人记得住
|
||||
2、口号太墨迹记不住,要简介:学习英语,一次敲击,一点进步记忆不再盲目,学习更高效,开源单词与文章练习工具
|
||||
3、布局:没有逻辑,首页进去看到标题,然后两个小的单词练习、文章联系,下面又是一大堆大的,没有逻辑和划分
|
||||
4、下面联系方式你需要放一个QQ群,社群资源,全放联系方式等于没放
|
||||
5、ABC页面弹出来的保存书签,不是加入书签就不迷失,是要让他们肌肉记忆住这个网站
|
||||
6、ABC页面太墨迹,不简洁,进度复杂,本周学习记录改成日历,有个标记,+激励分享功能,满足炫耀欲望
|
||||
7、设置不要用那个烂字体,真的很山寨,
|
||||
8、更新日志要按v版本和日期跟踪,要写的多,做得少,显示你在认真维护,是个令人尊重的程序员
|
||||
9、必须加后端、账号注册
|
||||
@@ -6,7 +6,7 @@
|
||||
"start": "vite",
|
||||
"dev": "vite",
|
||||
"test": "",
|
||||
"build": "vite build && node scripts/generate-sitemap.js",
|
||||
"build": "vite build && node scripts/do.js",
|
||||
"build-nocdn": "vite build",
|
||||
"build-tsc": "vue-tsc && vite build",
|
||||
"report": "vite build",
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
</script>
|
||||
<script>
|
||||
function nav(url) {
|
||||
history.pushState(null, "", url);
|
||||
window.location.href = url;
|
||||
// history.pushState(null, "", url);
|
||||
}
|
||||
|
||||
function toggleEl(val, close = false) {
|
||||
49
scripts/do.js
Normal file
49
scripts/do.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const {SitemapStream, streamToPromise} = require('sitemap')
|
||||
const {createWriteStream} = require('fs')
|
||||
const {resolve} = require('path')
|
||||
const fs = require('fs')
|
||||
|
||||
async function generateSitemap() {
|
||||
const bookList = require('../public/list/article.json')
|
||||
const dictList = require('../public/list/word.json')
|
||||
const SITE_URL = 'https://2study.top'
|
||||
|
||||
// 静态路由(首页、练习页等)
|
||||
const staticPages = [
|
||||
{url: '/', changefreq: 'daily', priority: 1.0},
|
||||
{url: '/words', changefreq: 'daily', priority: 0.9},
|
||||
{url: '/articles', changefreq: 'daily', priority: 0.9},
|
||||
{url: '/setting', changefreq: 'monthly', priority: 0.3},
|
||||
]
|
||||
|
||||
// 动态页面示例(假设你有文章或单词数据)
|
||||
const dynamicPages = bookList.flat().map(book => {
|
||||
return {url: '/practice-articles/' + book.id, changefreq: 'weekly', priority: 0.8}
|
||||
}).concat(dictList.flat().map(book => {
|
||||
return {url: '/practice-words/' + book.id, changefreq: 'weekly', priority: 0.8}
|
||||
}))
|
||||
const sitemap = new SitemapStream({hostname: SITE_URL})
|
||||
const writeStream = createWriteStream(resolve(__dirname, '../dist/sitemap.xml'))
|
||||
|
||||
sitemap.pipe(writeStream)
|
||||
|
||||
// 添加静态页
|
||||
staticPages.forEach(page => sitemap.write(page))
|
||||
|
||||
// 添加动态页
|
||||
dynamicPages.forEach(page => sitemap.write(page))
|
||||
|
||||
sitemap.end()
|
||||
|
||||
await streamToPromise(sitemap)
|
||||
console.log('✅ sitemap.xml 已生成在 dist 目录')
|
||||
}
|
||||
|
||||
function renameHtml() {
|
||||
//首页为了seo被剥离出去了,现在是一个静态页面,用nginx 重定向控制对应的跳转
|
||||
fs.renameSync('dist/index.html', 'dist/app.html')
|
||||
fs.renameSync('dist/static-home.html', 'dist/index.html')
|
||||
}
|
||||
|
||||
generateSitemap()
|
||||
renameHtml()
|
||||
@@ -1,42 +0,0 @@
|
||||
const {SitemapStream, streamToPromise} = require('sitemap')
|
||||
const {createWriteStream} = require('fs')
|
||||
const {resolve} = require('path')
|
||||
const bookList = require('../public/list/article.json')
|
||||
const dictList = require('../public/list/word.json')
|
||||
// 你的网站域名
|
||||
const SITE_URL = 'https://2study.top'
|
||||
|
||||
// 静态路由(首页、练习页等)
|
||||
const staticPages = [
|
||||
{url: '/', changefreq: 'daily', priority: 1.0},
|
||||
{url: '/words', changefreq: 'daily', priority: 0.9},
|
||||
{url: '/articles', changefreq: 'daily', priority: 0.9},
|
||||
{url: '/setting', changefreq: 'monthly', priority: 0.3},
|
||||
]
|
||||
|
||||
// 动态页面示例(假设你有文章或单词数据)
|
||||
const dynamicPages = bookList.flat().map(book => {
|
||||
return {url: '/practice-articles/' + book.id, changefreq: 'weekly', priority: 0.8}
|
||||
}).concat(dictList.flat().map(book => {
|
||||
return {url: '/practice-words/' + book.id, changefreq: 'weekly', priority: 0.8}
|
||||
}))
|
||||
|
||||
async function generateSitemap() {
|
||||
const sitemap = new SitemapStream({hostname: SITE_URL})
|
||||
const writeStream = createWriteStream(resolve(__dirname, '../dist/sitemap.xml'))
|
||||
|
||||
sitemap.pipe(writeStream)
|
||||
|
||||
// 添加静态页
|
||||
staticPages.forEach(page => sitemap.write(page))
|
||||
|
||||
// 添加动态页
|
||||
dynamicPages.forEach(page => sitemap.write(page))
|
||||
|
||||
sitemap.end()
|
||||
|
||||
await streamToPromise(sitemap)
|
||||
console.log('✅ sitemap.xml 已生成在 dist 目录')
|
||||
}
|
||||
|
||||
generateSitemap()
|
||||
@@ -1,189 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import Close from "@/components/icon/Close.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {watch} from "vue";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
|
||||
import {isMobile} from "@/utils";
|
||||
import {ProjectName, Host} from "@/config/env.ts";
|
||||
|
||||
let settingStore = useSettingStore()
|
||||
let showNotice = $ref(false)
|
||||
let show = $ref(false)
|
||||
let num = $ref(5)
|
||||
let timer = -1
|
||||
let mobile = $ref(isMobile())
|
||||
const isMac = /macintosh|mac os x/i.test(navigator.userAgent);
|
||||
|
||||
function toggleNotice() {
|
||||
showNotice = true
|
||||
settingStore.first = false
|
||||
timer = setInterval(() => {
|
||||
num--
|
||||
if (num <= 0) close()
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
function close() {
|
||||
clearInterval(timer)
|
||||
show = settingStore.first = false
|
||||
}
|
||||
|
||||
watch(() => settingStore.load, (n) => {
|
||||
if (n && settingStore.first) {
|
||||
setTimeout(() => {
|
||||
show = true
|
||||
}, 1000)
|
||||
}
|
||||
}, {immediate: true})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<transition name="right">
|
||||
<div class="CollectNotice"
|
||||
:class="{mobile}"
|
||||
v-if="show">
|
||||
<div class="notice">
|
||||
坚持练习,提高外语能力。将
|
||||
<span class="active">「{{ ProjectName }}」</span>
|
||||
保存为书签,永不迷失!
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<transition name="fade">
|
||||
<div class="collect" v-if="showNotice">
|
||||
<div class="href-wrapper">
|
||||
<div class="round">
|
||||
<div class="href">{{ Host }}</div>
|
||||
<IconFluentStar12Regular width="22"/>
|
||||
</div>
|
||||
<div class="right">
|
||||
👈
|
||||
<IconFluentStar20Filled class="star" width="22"/>
|
||||
点亮它!
|
||||
</div>
|
||||
</div>
|
||||
<div class="collect-keyboard" v-if="!mobile">或使用收藏快捷键<span
|
||||
class="active">{{ isMac ? 'Command' : 'Ctrl' }} + D</span></div>
|
||||
</div>
|
||||
<BaseButton v-else size="large" @click="toggleNotice">我想收藏</BaseButton>
|
||||
</transition>
|
||||
</div>
|
||||
<div class="close-wrapper">
|
||||
<span v-show="showNotice"><span class="active">{{ num }}s</span> 后自动关闭</span>
|
||||
<Close @click="close" title="关闭"/>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
.right-enter-active,
|
||||
.right-leave-active {
|
||||
transition: all .5s ease;
|
||||
}
|
||||
|
||||
.right-enter-from,
|
||||
.right-leave-to {
|
||||
transform: translateX(110%);
|
||||
}
|
||||
|
||||
.CollectNotice {
|
||||
position: fixed;
|
||||
right: var(--space);
|
||||
top: var(--space);
|
||||
z-index: 2;
|
||||
font-size: 1.2rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background: var(--color-notice-bg);
|
||||
padding: 1.8rem;
|
||||
border-radius: 0.7rem;
|
||||
width: 30rem;
|
||||
gap: 2.4rem;
|
||||
color: var(--color-font-1);
|
||||
line-height: 1.5;
|
||||
border: 1px solid var(--color-item-border);
|
||||
box-shadow: var(--shadow);
|
||||
box-sizing: border-box;
|
||||
|
||||
&.mobile {
|
||||
width: 95%;
|
||||
padding: 0.6rem;
|
||||
}
|
||||
|
||||
.notice {
|
||||
margin-top: 2.4rem;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: var(--color-select-bg);
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
.collect {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.href-wrapper {
|
||||
display: flex;
|
||||
font-size: 1rem;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
|
||||
.round {
|
||||
color: var(--color-font-1);
|
||||
border-radius: 3rem;
|
||||
padding: 0.6rem 0.6rem;
|
||||
padding-left: 1.2rem;
|
||||
gap: 2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: var(--color-primary);
|
||||
|
||||
.href {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.star {
|
||||
color: var(--color-select-bg);
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.collect-keyboard {
|
||||
margin-top: 1.2rem;
|
||||
font-size: 1rem;
|
||||
|
||||
span {
|
||||
margin-left: 0.6rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.close-wrapper {
|
||||
right: var(--space);
|
||||
top: var(--space);
|
||||
position: absolute;
|
||||
font-size: 0.9rem;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
color: var(--color-font-1);
|
||||
gap: 0.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -8,13 +8,15 @@ import useTheme from "@/hooks/theme.ts";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const router = useRouter()
|
||||
const {toggleTheme,getTheme} = useTheme()
|
||||
|
||||
const {toggleTheme, getTheme} = useTheme()
|
||||
|
||||
//首页为了seo被剥离出去了,现在是一个静态页面,用nginx 重定向控制对应的跳转
|
||||
function goHome() {
|
||||
window.location.href = '/';
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -24,7 +26,7 @@ const {toggleTheme,getTheme} = useTheme()
|
||||
<div class="aside anim fixed" :class="{'expand':settingStore.sideExpand}">
|
||||
<div class="top">
|
||||
<Logo v-if="settingStore.sideExpand"/>
|
||||
<div class="row" @click="router.push('/')">
|
||||
<div class="row" @click="goHome">
|
||||
<IconFluentHome20Regular/>
|
||||
<span v-if="settingStore.sideExpand">主页</span>
|
||||
</div>
|
||||
@@ -42,21 +44,21 @@ const {toggleTheme,getTheme} = useTheme()
|
||||
<span v-if="settingStore.sideExpand">设置</span>
|
||||
<div class="red-point" :class="!settingStore.sideExpand && 'top-1 right-0'" v-if="runtimeStore.isNew"></div>
|
||||
</div>
|
||||
<!-- <div class="row" @click="router.push('/user')">-->
|
||||
<!-- <IconFluentPerson20Regular/>-->
|
||||
<!-- <span v-if="settingStore.sideExpand">用户</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="row" @click="router.push('/user')">-->
|
||||
<!-- <IconFluentPerson20Regular/>-->
|
||||
<!-- <span v-if="settingStore.sideExpand">用户</span>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<div class="bottom flex justify-evenly ">
|
||||
<BaseIcon
|
||||
@click="settingStore.sideExpand = !settingStore.sideExpand">
|
||||
@click="settingStore.sideExpand = !settingStore.sideExpand">
|
||||
<IconFluentChevronLeft20Filled v-if="settingStore.sideExpand"/>
|
||||
<IconFluentChevronLeft20Filled class="transform-rotate-180" v-else/>
|
||||
</BaseIcon>
|
||||
<BaseIcon
|
||||
v-if="settingStore.sideExpand"
|
||||
:title="`切换主题(${settingStore.shortcutKeyMap[ShortcutKey.ToggleTheme]})`"
|
||||
@click="toggleTheme"
|
||||
v-if="settingStore.sideExpand"
|
||||
:title="`切换主题(${settingStore.shortcutKeyMap[ShortcutKey.ToggleTheme]})`"
|
||||
@click="toggleTheme"
|
||||
>
|
||||
<IconFluentWeatherMoon16Regular v-if="getTheme() === 'light'"/>
|
||||
<IconFluentWeatherSunny16Regular v-else/>
|
||||
|
||||
@@ -237,7 +237,7 @@ async function startPractice() {
|
||||
wordPracticeMode: settingStore.wordPracticeMode
|
||||
})
|
||||
let currentStudy = getCurrentStudyWord()
|
||||
nav('practice-words/' + store.sdict.id, {}, currentStudy)
|
||||
nav('practice-words/' + store.sdict.id, {}, {taskWords:currentStudy})
|
||||
}
|
||||
|
||||
async function addMyStudyList() {
|
||||
|
||||
@@ -9,6 +9,7 @@ import dayjs from "dayjs";
|
||||
import isBetween from "dayjs/plugin/isBetween";
|
||||
import {defineAsyncComponent, inject, watch} from "vue";
|
||||
import isoWeek from 'dayjs/plugin/isoWeek'
|
||||
import {msToHourMinute, msToMinute} from "@/utils";
|
||||
|
||||
dayjs.extend(isoWeek)
|
||||
dayjs.extend(isBetween);
|
||||
@@ -135,8 +136,7 @@ function options(emitType: string) {
|
||||
</div>
|
||||
|
||||
<div class="text-xl text-center flex flex-col justify-around">
|
||||
<div>非常棒! 坚持了 <span class="color-emerald-500 font-bold text-2xl">
|
||||
{{ dayjs().diff(statStore.startDate, 'm') }}</span>分钟
|
||||
<div>非常棒! 坚持了 <span class="color-emerald-500 font-bold text-2xl">{{msToHourMinute(statStore.spend) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center gap-10">
|
||||
|
||||
@@ -18,7 +18,6 @@ import DeleteIcon from "@/components/icon/DeleteIcon.vue";
|
||||
import PracticeSettingDialog from "@/pages/word/components/PracticeSettingDialog.vue";
|
||||
import ChangeLastPracticeIndexDialog from "@/pages/word/components/ChangeLastPracticeIndexDialog.vue";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import CollectNotice from "@/components/CollectNotice.vue";
|
||||
import {useFetch} from "@vueuse/core";
|
||||
import {CAN_REQUEST, DICT_LIST, PracticeSaveWordKey} from "@/config/env.ts";
|
||||
import {myDictList} from "@/apis";
|
||||
@@ -173,7 +172,7 @@ async function onShufflePracticeSettingOk(total) {
|
||||
localStorage.removeItem(PracticeSaveWordKey.key)
|
||||
|
||||
let ignoreList = [store.allIgnoreWords, store.knownWords][settingStore.ignoreSimpleWord ? 0 : 1]
|
||||
currentStudy.shuffle = shuffle(store.sdict.words.filter(v => !ignoreList.includes(v.word))).slice(0, total)
|
||||
currentStudy.shuffle = shuffle(store.sdict.words.slice(0, store.sdict.lastLearnIndex).filter(v => !ignoreList.includes(v.word))).slice(0, total)
|
||||
nav('practice-words/' + store.sdict.id, {}, {
|
||||
taskWords: currentStudy,
|
||||
total //用于再来一组时,随机出正确的长度,因为练习中可能会点击已掌握,导致重学一遍之后长度变少,如果再来一组,此时长度就不正确
|
||||
@@ -379,7 +378,6 @@ const {
|
||||
v-model="showShufflePracticeSettingDialog"
|
||||
@ok="onShufflePracticeSettingOk"/>
|
||||
|
||||
<CollectNotice/>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -141,6 +141,7 @@ function unknown(e) {
|
||||
if (!showWordResult) {
|
||||
showWordResult = true
|
||||
emit('wrong')
|
||||
if (settingStore.wordSound) volumeIconRef?.play()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ export const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/',
|
||||
component: Layout,
|
||||
redirect: '/',
|
||||
children: [
|
||||
{path: '/', component: Home},
|
||||
// {path: '/', component: Home},
|
||||
{path: '/', redirect: '/words'},
|
||||
{path: 'words', component: WordsPage},
|
||||
{path: 'word', redirect: '/words'},
|
||||
{path: 'practice-words/:id', component: PracticeWords},
|
||||
|
||||
@@ -69,7 +69,7 @@ export const getDefaultSettingState = (): SettingState => ({
|
||||
|
||||
keyboardSound: true,
|
||||
keyboardSoundVolume: 100,
|
||||
keyboardSoundFile: '机械键盘2',
|
||||
keyboardSoundFile: '笔记本键盘',
|
||||
|
||||
effectSound: true,
|
||||
effectSoundVolume: 100,
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import {defineConfig} from 'vite'
|
||||
import Vue from '@vitejs/plugin-vue'
|
||||
import VueJsx from "@vitejs/plugin-vue-jsx";
|
||||
import { resolve } from 'path'
|
||||
import { visualizer } from "rollup-plugin-visualizer";
|
||||
import {resolve} from 'path'
|
||||
import {visualizer} from "rollup-plugin-visualizer";
|
||||
import SlidePlugin from './src/components/slide/data.js';
|
||||
import { getLastCommit } from "git-last-commit";
|
||||
import {getLastCommit} from "git-last-commit";
|
||||
import UnoCSS from 'unocss/vite'
|
||||
import VueMacros from 'unplugin-vue-macros/vite'
|
||||
import Icons from 'unplugin-icons/vite'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
import IconsResolver from 'unplugin-icons/resolver'
|
||||
import { viteExternalsPlugin } from 'vite-plugin-externals'
|
||||
import {viteExternalsPlugin} from 'vite-plugin-externals'
|
||||
|
||||
function pathResolve(dir: string) {
|
||||
return resolve(__dirname, ".", dir)
|
||||
@@ -79,9 +79,6 @@ export default defineConfig(() => {
|
||||
],
|
||||
build: {
|
||||
rollupOptions: {
|
||||
input: {
|
||||
app: 'app.html' // 默认入口
|
||||
},
|
||||
// 因为已经把包复制过来了,里面的axios实例用的项目的,所以这行代码可以不要了
|
||||
// external: isCdnBuild ? ['axios'] : [],// 使用全局的 axios。因为百度翻译库内部用了0.19版本的axios,会被打包到代码里面
|
||||
output: {
|
||||
@@ -128,9 +125,6 @@ export default defineConfig(() => {
|
||||
port: 3000,
|
||||
open: false,
|
||||
host: '0.0.0.0',
|
||||
fs: {
|
||||
strict: false,
|
||||
},
|
||||
proxy: {
|
||||
'/baidu': 'https://api.fanyi.baidu.com/api/trans/vip/translate'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user