This commit is contained in:
Zyronon
2025-12-20 02:02:31 +08:00
parent fe219cdb36
commit 5b67756ff9
3 changed files with 338 additions and 77 deletions

1
components.d.ts vendored
View File

@@ -80,6 +80,7 @@ declare module 'vue' {
IconFluentDismiss20Regular: typeof import('~icons/fluent/dismiss20-regular')['default']
IconFluentDismissCircle16Regular: typeof import('~icons/fluent/dismiss-circle16-regular')['default']
IconFluentDismissCircle20Filled: typeof import('~icons/fluent/dismiss-circle20-filled')['default']
IconFluentDocument20Regular: typeof import('~icons/fluent/document20-regular')['default']
IconFluentErrorCircle20Filled: typeof import('~icons/fluent/error-circle20-filled')['default']
IconFluentErrorCircle20Regular: typeof import('~icons/fluent/error-circle20-regular')['default']
IconFluentEye16Regular: typeof import('~icons/fluent/eye16-regular')['default']

View File

@@ -1,21 +1,263 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import BasePage from '@/components/BasePage.vue'
import BaseButton from '@/components/BaseButton.vue'
import BasePage from "@/components/BasePage.vue";
// 资源分类
const categories = ref([
{
id: 'new-concept',
name: '新概念英语',
icon: '📚',
description: '经典英语教材,适合系统学习',
resources: [
{
name: '新概念英语第一册',
description: '适合英语初学者',
difficulty: '入门',
link: 'https://pan.quark.cn/s/92a317cf1a16',
},
{
name: '新概念英语第二册',
description: '基础英语学习,巩固语法和词汇',
difficulty: '基础',
link: 'https://pan.quark.cn/s/1ee9c8a7e8e2',
},
{
name: '新概念英语第三册',
description: '提高英语水平,增强阅读能力',
difficulty: '进阶',
link: 'https://pan.quark.cn/s/b35c2859812a',
},
{
name: '新概念英语第四册',
description: '高级英语学习,提升综合能力',
difficulty: '高级',
link: 'https://pan.quark.cn/s/a56713cafbc5',
},
{
name: '新概念英青少年版',
description: '儿童读物',
difficulty: '7岁至14岁',
link: 'https://pan.quark.cn/s/9de8d7967de2',
},
{
name: '新概念英语1-4 教材高清PDF',
description: '仅 1-4 册的教材高清PDF',
difficulty: '',
link: 'https://pan.quark.cn/s/ec49145d6b00',
},
{
name: '新概念讲解视频',
description: '包含了 N 家机构/个人的讲解视频',
difficulty: '',
link: 'https://pan.quark.cn/s/09e98acd55b4',
},
],
},
{
id: 'exam',
name: '英语相关电视/电影',
icon: '🎯',
description: '雅思、托福等考试备考资料',
resources: [
{
name: '老友记',
description: '',
difficulty: '经典',
link: 'https://pan.quark.cn/s/674834e7a5b1',
},
{
name: '生活大爆炸',
description: '',
difficulty: '经典',
link: 'https://pan.quark.cn/s/0539c10704ba',
},
{
name: '是大臣/是首相',
description: '',
difficulty: '经典',
link: 'https://pan.quark.cn/s/316323ce51d5',
},
],
},
{
id: 'grammar',
name: '语法学习',
icon: '📝',
description: '系统性学习英语语法',
resources: [
{
name: '剑桥中级英语语法',
description: '清晰讲解语法点,配有大量练习',
difficulty: '中级',
link: 'https://pan.baidu.com/s/xxx',
},
{
name: 'English Grammar in Use',
description: '经典语法教材,适合自学',
difficulty: '中级',
link: 'https://pan.baidu.com/s/xxx',
},
{
name: "Murphy's English Grammar",
description: '系统讲解英语语法,适合各类学习者',
difficulty: '全级别',
link: 'https://pan.baidu.com/s/xxx',
},
],
},
{
id: 'listening',
name: '听力训练',
icon: '🎧',
description: '提升英语听力水平',
resources: [
{
name: 'VOA慢速英语合集',
description: '新闻类听力材料,语速适中,内容丰富',
difficulty: '中级',
link: 'https://pan.baidu.com/s/xxx',
},
{
name: 'BBC Learning English',
description: 'BBC官方英语学习资源涵盖多方面内容',
difficulty: '中高级',
link: 'https://pan.baidu.com/s/xxx',
},
{
name: 'TED演讲精选',
description: '高质量演讲,锻炼听力同时开拓视野',
difficulty: '中高级',
link: 'https://pan.baidu.com/s/xxx',
},
{
name: '哈弗演讲',
description: '高质量演讲,锻炼听力同时开拓视野',
difficulty: '中高级',
link: 'https://pan.quark.cn/s/f2bfa8a50d25',
},
],
},
])
// 当前选中的分类
const selectedCategory = ref('all')
// 筛选后的资源
const filteredResources = computed(() => {
if (selectedCategory.value === 'all') {
return categories.value
}
return categories.value.filter(cat => cat.id === selectedCategory.value)
})
// 跳转到网盘链接
const openLink = (url: string) => {
window.open(url, '_blank')
}
// 根据难度获取对应的样式类
const getDifficultyClass = (difficulty: string) => {
switch (difficulty) {
case '入门':
return 'bg-green-500'
case '基础':
return 'bg-blue-500'
case '中级':
return 'bg-purple-500'
case '进阶':
return 'bg-amber-500'
case '高级':
return 'bg-red-500'
case '全级别':
return 'bg-gray-500'
default:
return 'bg-blue-500'
}
}
</script>
<template>
<BasePage>
<div class="center">
<div class="card qa w-2/3">
<div class="font-bold text-2xl mb-6">分享个人收藏的一些学习资料</div>
<div class="list">
<div class="title">新概念相关</div>
<div class="line"></div>
<div class="flex flex-col items-center justify-center px-4 py-8 max-w-7xl mx-auto">
<!-- 页面标题 -->
<div class="text-center mb-8">
<h1 class="text-4xl font-bold mb-4">📚 英语学习资源分享</h1>
<p class="text-lg text-gray-600 dark:text-gray-300 max-w-3xl mx-auto">
以下是我整理的个人收藏的优质英语学习资源希望对大家有所帮助
</p>
</div>
<!-- 分类筛选 -->
<div
class="flex flex-wrap justify-center gap-2 mb-8 p-4 bg-white dark:bg-gray-800 rounded-lg shadow-md w-full"
>
<BaseButton
:type="selectedCategory === 'all' ? 'primary' : 'info'"
@click="selectedCategory = 'all'"
>
全部资源
</BaseButton>
<BaseButton
v-for="category in categories"
:key="category.id"
:type="selectedCategory === category.id ? 'primary' : 'info'"
@click="selectedCategory = category.id"
>
{{ category.icon }} {{ category.name }}
</BaseButton>
</div>
<!-- 资源列表 -->
<div class="w-full">
<div v-for="category in filteredResources" :key="category.id" class="mb-12">
<div class="text-center mb-6">
<h2 class="text-2xl font-bold mb-2">{{ category.icon }} {{ category.name }}</h2>
<p class="text-gray-600 dark:text-gray-300">{{ category.description }}</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
<div
v-for="resource in category.resources"
:key="resource.name"
class="card-white mb-0 hover:shadow-xl transition-all duration-300 hover:-translate-y-1 flex flex-col justify-between"
>
<div class="">
<div class="text-xl font-semibold mb-2 text-gray-800 dark:text-gray-100">
{{ resource.name }}
</div>
<p>
<span
v-if="resource.difficulty"
class="mr-2 inline-block px-3 py-1 rounded-full text-xs font-medium text-white"
:class="getDifficultyClass(resource.difficulty)"
>
{{ resource.difficulty }}
</span>
<span class=" text-gray-600 dark:text-gray-300 mb-4">{{
resource.description
}}</span>
</p>
</div>
<div class="flex flex-col gap-3">
<BaseButton type="primary" @click="openLink(resource.link)"> 打开链接 </BaseButton>
</div>
</div>
</div>
</div>
</div>
<!-- 页面底部 -->
<div class="mt-12 pt-8 border-t border-gray-200 dark:border-gray-700">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6">
<h3 class="text-xl font-bold mb-4">💡 温馨提示</h3>
<ul class="list-disc list-inside space-y-2 text-gray-600 dark:text-gray-300">
<li>所有资源均来自互联网收集仅供学习交流使用</li>
<li>如果链接失效请及时告知我会尽快更新</li>
</ul>
</div>
</div>
</div>
</BasePage>
</template>
<style scoped lang="scss">
</style>

View File

@@ -1,111 +1,128 @@
<script setup lang="ts">
import {ShortcutKey} from "@/types/types.ts";
import Logo from "@/components/Logo.vue";
import {useSettingStore} from "@/stores/setting.ts";
import {useRouter} from "vue-router";
import useTheme from "@/hooks/theme.ts";
import BaseIcon from "@/components/BaseIcon.vue";
import {useRuntimeStore} from "@/stores/runtime.ts";
import { jump2Feedback } from "@/utils";
import { ShortcutKey } from '@/types/types.ts'
import Logo from '@/components/Logo.vue'
import { useSettingStore } from '@/stores/setting.ts'
import { useRouter } from 'vue-router'
import useTheme from '@/hooks/theme.ts'
import BaseIcon from '@/components/BaseIcon.vue'
import { useRuntimeStore } from '@/stores/runtime.ts'
import { jump2Feedback } from '@/utils'
const settingStore = useSettingStore()
const runtimeStore = useRuntimeStore()
const router = useRouter()
const {toggleTheme, getTheme} = useTheme()
const { toggleTheme, getTheme } = useTheme()
//首页为了seo被剥离出去了现在是一个静态页面用nginx 重定向控制对应的跳转
function goHome() {
window.location.href = '/';
window.location.href = '/'
}
</script>
<template>
<div class="layout anim">
<!-- 第一个aside 占位用-->
<div class="aside space" :class="{'expand':settingStore.sideExpand}"></div>
<div class="aside anim fixed" :class="{'expand':settingStore.sideExpand}">
<div class="aside space" :class="{ expand: settingStore.sideExpand }"></div>
<div class="aside anim fixed" :class="{ expand: settingStore.sideExpand }">
<div class="top">
<Logo v-if="settingStore.sideExpand"/>
<Logo v-if="settingStore.sideExpand" />
<div class="row" @click="goHome">
<IconFluentHome20Regular/>
<IconFluentHome20Regular />
<span v-if="settingStore.sideExpand">主页</span>
</div>
<div class="row" @click="router.push('/words')">
<IconFluentTextUnderlineDouble20Regular/>
<IconFluentTextUnderlineDouble20Regular />
<span v-if="settingStore.sideExpand">单词</span>
</div>
<div id="article" class="row" @click="router.push('/articles')">
<div id="article" class="row" @click="router.push('/articles')">
<!-- <IconPhArticleNyTimes/>-->
<IconFluentBookLetter20Regular/>
<IconFluentBookLetter20Regular />
<span v-if="settingStore.sideExpand">文章</span>
</div>
<div class="row" @click="router.push('/setting')">
<IconFluentSettings20Regular/>
<IconFluentSettings20Regular />
<span v-if="settingStore.sideExpand">设置</span>
<div class="red-point" :class="!settingStore.sideExpand && 'top-1 right-0'" v-if="runtimeStore.isNew"></div>
<div
class="red-point"
:class="!settingStore.sideExpand && 'top-1 right-0'"
v-if="runtimeStore.isNew"
></div>
</div>
<div class="row" @click="router.push('/feedback')">
<IconFluentCommentEdit20Regular/>
<IconFluentCommentEdit20Regular />
<span v-if="settingStore.sideExpand">反馈</span>
</div>
<div class="row" @click="router.push('/qa')">
<IconFluentQuestionCircle20Regular/>
<IconFluentQuestionCircle20Regular />
<span v-if="settingStore.sideExpand">帮助</span>
</div>
<!-- <div class="row" @click="router.push('/doc')">-->
<!-- <IconFluentDocument20Regular/>-->
<!-- <span v-if="settingStore.sideExpand">资料</span>-->
<!-- </div>-->
<!-- <div class="row" @click="router.push('/user')">-->
<!-- <IconFluentPerson20Regular/>-->
<!-- <span v-if="settingStore.sideExpand">用户</span>-->
<!-- </div>-->
<div class="row" @click="router.push('/doc')">
<IconFluentDocument20Regular />
<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">
<IconFluentChevronLeft20Filled v-if="settingStore.sideExpand"/>
<IconFluentChevronLeft20Filled class="transform-rotate-180" v-else/>
<div class="bottom flex justify-evenly">
<BaseIcon @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"
>
<IconFluentWeatherMoon16Regular v-if="getTheme() === 'light'"/>
<IconFluentWeatherSunny16Regular v-else/>
<IconFluentWeatherMoon16Regular v-if="getTheme() === 'light'" />
<IconFluentWeatherSunny16Regular v-else />
</BaseIcon>
</div>
</div>
<!-- 移动端顶部菜单栏 -->
<div class="mobile-top-nav" :class="{'collapsed': settingStore.mobileNavCollapsed}">
<div class="mobile-top-nav" :class="{ collapsed: settingStore.mobileNavCollapsed }">
<div class="nav-items">
<div class="nav-item" @click="router.push('/')" :class="{'active': $route.path === '/'}">
<IconFluentHome20Regular/>
<div class="nav-item" @click="router.push('/')" :class="{ active: $route.path === '/' }">
<IconFluentHome20Regular />
<span>主页</span>
</div>
<div class="nav-item" @click="router.push('/words')" :class="{'active': $route.path.includes('/words')}">
<IconFluentTextUnderlineDouble20Regular/>
<div
class="nav-item"
@click="router.push('/words')"
:class="{ active: $route.path.includes('/words') }"
>
<IconFluentTextUnderlineDouble20Regular />
<span>单词</span>
</div>
<div class="nav-item" @click="router.push('/articles')" :class="{'active': $route.path.includes('/articles')}">
<IconFluentBookLetter20Regular/>
<div
class="nav-item"
@click="router.push('/articles')"
:class="{ active: $route.path.includes('/articles') }"
>
<IconFluentBookLetter20Regular />
<span>文章</span>
</div>
<div class="nav-item" @click="router.push('/setting')" :class="{'active': $route.path === '/setting'}">
<IconFluentSettings20Regular/>
<div
class="nav-item"
@click="router.push('/setting')"
:class="{ active: $route.path === '/setting' }"
>
<IconFluentSettings20Regular />
<span>设置</span>
<div class="red-point" v-if="runtimeStore.isNew"></div>
</div>
</div>
<div class="nav-toggle" @click="settingStore.mobileNavCollapsed = !settingStore.mobileNavCollapsed">
<IconFluentChevronDown20Filled v-if="!settingStore.mobileNavCollapsed"/>
<IconFluentChevronUp20Filled v-else/>
<div
class="nav-toggle"
@click="settingStore.mobileNavCollapsed = !settingStore.mobileNavCollapsed"
>
<IconFluentChevronDown20Filled v-if="!settingStore.mobileNavCollapsed" />
<IconFluentChevronUp20Filled v-else />
</div>
</div>
<div class="flex-1 z-1 relative main-content">
<router-view></router-view>
</div>
@@ -134,7 +151,7 @@ function goHome() {
.row {
@apply cursor-pointer rounded-md text p-2 my-2 flex items-center gap-2 relative shrink-0;
transition: all .5s;
transition: all 0.5s;
&:hover {
background: var(--btn-primary);
@@ -167,12 +184,12 @@ function goHome() {
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
transition: all 0.3s ease;
.nav-items {
display: flex;
justify-content: space-around;
padding: 0.5rem 0;
.nav-item {
display: flex;
flex-direction: column;
@@ -184,29 +201,30 @@ function goHome() {
min-width: 44px;
justify-content: center;
position: relative;
svg {
font-size: 1.2rem;
margin-bottom: 0.2rem;
color: var(--color-main-text);
}
span {
font-size: 0.7rem;
color: var(--color-main-text);
text-align: center;
}
&.active {
svg, span {
svg,
span {
color: var(--color-select-bg);
}
}
&:active {
transform: scale(0.95);
}
.red-point {
position: absolute;
top: 0.2rem;
@@ -218,7 +236,7 @@ function goHome() {
}
}
}
.nav-toggle {
position: absolute;
bottom: -1.5rem;
@@ -231,20 +249,20 @@ function goHome() {
padding: 0.3rem 0.8rem;
cursor: pointer;
transition: all 0.3s;
svg {
font-size: 1rem;
color: var(--color-main-text);
}
&:active {
transform: translateX(-50%) scale(0.95);
}
}
&.collapsed {
transform: translateY(calc(-100% + 1.5rem));
.nav-items {
opacity: 0;
pointer-events: none;
@@ -264,11 +282,11 @@ function goHome() {
.aside {
display: none;
}
.aside.space {
display: none;
}
.main-content {
width: 100%;
margin-left: 0;