fix: 日历页显示页签+页签样式优化+iframe自适应+骨架屏
- useProjects: 访问 hidden 模块(/cqy)时仍显示其页签并高亮, 让用户知道当前位置;主页仍隐藏日历页签 - TabNav: 非激活页签加圆角背景与 hover 背景反馈,激活页签 下边线贯通整宽,更像页签 - Calendar: iframe 去除固定 800x600,改 width/height:100% + aspect-ratio 自适应(宽屏16:10,窄屏4:3,min-height 400px) - Calendar: 加载骨架屏覆盖层(iframe @load 后淡出), iframe 始终在 DOM 中确保 load 事件触发 - i18n: 日历页签文案改「cqy课程表」/「CQY Timetable」 headless 验证:/cqy 显示页签且激活、hover 有背景反馈、 iframe 自适应宽窄屏、骨架屏加载后淡出
This commit is contained in:
@@ -45,22 +45,24 @@ const { projects } = useProjects()
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
transition: color var(--transition);
|
||||
border-radius: var(--radius-sm) var(--radius-sm) 0 0;
|
||||
transition: color var(--transition), background var(--transition);
|
||||
}
|
||||
.tab-nav__item:hover {
|
||||
color: var(--text-primary);
|
||||
background: var(--surface);
|
||||
}
|
||||
.tab-nav__item.is-active {
|
||||
color: var(--accent);
|
||||
background: var(--surface);
|
||||
}
|
||||
.tab-nav__item.is-active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: var(--space-md);
|
||||
right: var(--space-md);
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: -1px;
|
||||
height: 2px;
|
||||
background: var(--accent);
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import modules from '../modules/index.js'
|
||||
import { ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
// 读取已注册模块列表,供 TabNav 渲染页签
|
||||
// hidden 模块(如日历页)不显示在导航中,但仍可通过路由直接访问
|
||||
// hidden 模块(如日历页)默认不显示在导航中,但当用户正在访问该页时
|
||||
// 仍显示其页签(描下边高亮),让用户知道当前所在位置。
|
||||
export function useProjects() {
|
||||
const projects = ref(modules.filter((m) => !m.hidden))
|
||||
const route = useRoute()
|
||||
const projects = computed(() =>
|
||||
modules.filter((m) => !m.hidden || m.id === route.meta.moduleId)
|
||||
)
|
||||
return { projects }
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export default {
|
||||
},
|
||||
tabs: {
|
||||
mobileGame: 'Mobile Game Project',
|
||||
calendar: 'Calendar'
|
||||
calendar: 'CQY Timetable'
|
||||
},
|
||||
mobileGame: {
|
||||
hero: {
|
||||
|
||||
@@ -9,7 +9,7 @@ export default {
|
||||
},
|
||||
tabs: {
|
||||
mobileGame: '移动游戏项目',
|
||||
calendar: '日历'
|
||||
calendar: 'cqy课程表'
|
||||
},
|
||||
mobileGame: {
|
||||
hero: {
|
||||
|
||||
@@ -1,26 +1,38 @@
|
||||
<script setup>
|
||||
// 日历页 -- 隐藏页,仅可通过手动访问 /cqy 进入,不在导航中显示
|
||||
const calendarSrc =
|
||||
import { ref, computed } from 'vue'
|
||||
import { useLocale } from '../../composables/useLocale.js'
|
||||
|
||||
const { t } = useLocale()
|
||||
|
||||
// 谷歌日历 embed URL(周视图)
|
||||
const calendarSrc = computed(() =>
|
||||
'https://calendar.google.com/calendar/embed?height=600&wkst=2&ctz=Australia%2FMelbourne&showPrint=0&mode=WEEK' +
|
||||
'&src=Y2E0YTE5ZWYwNDM3OTYyYzY5YjEyYzYxYWVmOGVlZjY3MGU5ZDdmYjRlNzJlOTFjNDJjMzllM2Q2NGU5ZTAzNkBncm91cC5jYWxlbmRhci5nb29nbGUuY29t' +
|
||||
'&src=emguYXVzdHJhbGlhbiNob2xpZGF5QGdyb3VwLnYuY2FsZW5kYXIuZ29vZ2xlLmNvbQ' +
|
||||
'&color=%237986cb&color=%230b8043'
|
||||
)
|
||||
|
||||
const loaded = ref(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="calendar-page">
|
||||
<div class="container">
|
||||
<h1 class="calendar-page__title">Calendar</h1>
|
||||
<h1 class="calendar-page__title">{{ t('tabs.calendar') }}</h1>
|
||||
<div class="calendar-page__frame">
|
||||
<!-- 加载占位骨架(覆盖层,iframe 加载完成后淡出) -->
|
||||
<Transition name="fade">
|
||||
<div v-if="!loaded" class="calendar-page__skeleton">
|
||||
<div class="calendar-page__skeleton-text">{{ t('common.loading') }}</div>
|
||||
</div>
|
||||
</Transition>
|
||||
<iframe
|
||||
:src="calendarSrc"
|
||||
style="border: solid 1px #777"
|
||||
width="800"
|
||||
height="600"
|
||||
class="calendar-page__iframe"
|
||||
frameborder="0"
|
||||
scrolling="no"
|
||||
loading="lazy"
|
||||
title="Google Calendar"
|
||||
:title="t('tabs.calendar')"
|
||||
@load="loaded = true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -36,13 +48,47 @@ const calendarSrc =
|
||||
margin-bottom: var(--space-lg);
|
||||
}
|
||||
.calendar-page__frame {
|
||||
position: relative;
|
||||
border-radius: var(--radius);
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.calendar-page__frame iframe {
|
||||
border: 1px solid var(--border);
|
||||
/* 自适应宽高:宽屏 16:9,窄屏更高 */
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
aspect-ratio: 4 / 3;
|
||||
min-height: 400px;
|
||||
}
|
||||
.calendar-page__iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
border: 0;
|
||||
}
|
||||
.calendar-page__skeleton {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--surface);
|
||||
}
|
||||
.calendar-page__skeleton-text {
|
||||
color: var(--text-tertiary);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.4s ease;
|
||||
}
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 769px) {
|
||||
.calendar-page__frame {
|
||||
aspect-ratio: 16 / 10;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user