diff --git a/src/components/admin/MainWrapper.vue b/src/components/admin/MainWrapper.vue index a96b67e..74175bb 100644 --- a/src/components/admin/MainWrapper.vue +++ b/src/components/admin/MainWrapper.vue @@ -7,7 +7,7 @@ <span v-if="!collapsed">{{ state.name }}</span> </a-flex> <a-menu v-model:openKeys="state.openKeys" v-model:selectedKeys="state.selectedKeys" mode="inline" theme="light" - :inline-collapsed="state.collapsed" :items="items" style="border-inline-end: none;" @click="menuItemclick"> + :inline-collapsed="state.collapsed" :items="items" style="border-inline-end: none;"> </a-menu> </div> <div class="contentArea"> @@ -60,7 +60,7 @@ const items = reactive([ { key: '1', icon: () => h(DashboardOutlined), - label: '仪表盘', + label: h('a',{href:"/admin/dashboard"},'仪表盘'), title: '仪表盘', url: '/admin/dashboard' }, diff --git a/src/components/blogs/HomePage.vue b/src/components/blogs/HomePage.vue index f4f757d..c7e3157 100644 --- a/src/components/blogs/HomePage.vue +++ b/src/components/blogs/HomePage.vue @@ -2,13 +2,14 @@ <Simplebar @scroll="handleScroll"> <!-- 头部导航菜单 --> <div class="headerMenu" v-if="show_menu"> - <a-menu v-model:selectedKeys="current" mode="horizontal" :items="items" style="border-bottom: none;" /> + <a-menu v-model:selectedKeys="current" mode="horizontal" :items="items" style="border-bottom: none;" + @click="menuClick" /> <a-input-search v-model:value="value" placeholder="search" style="width: 200px" @search="onSearch" /> </div> - <div class="author"></div> + <div class="author" v-if="show_author"></div> <!-- 轮播 --> - <div> + <div v-if="show_carousel"> <a-carousel autoplay> <div class="img"><img src="/src/assets/images/nav1.png" alt=""></div> <div class="img"><img src="/src/assets/images/nav10.png" alt=""></div> @@ -73,55 +74,18 @@ <a-button type="dashed">Link</a-button> <a-button type="dashed">Link</a-button> <a-button type="dashed">Link</a-button> + <a-button type="dashed">Link</a-button> + <a-button type="dashed">Link</a-button> + <a-button type="dashed">Link</a-button> + <a-button type="dashed">Link</a-button> + <a-button type="dashed">Link</a-button> + <a-button type="dashed">Link</a-button> + <a-button type="dashed">Link</a-button> + <a-button type="dashed">Link</a-button> </div> </a-card> </div> - - <div class="main"> - <a-badge-ribbon text="Hippies" color="black"> - <a-card hoverable> - <h2>操作系统的安装</h2> - <div class="tag-group"> - <a-tag color="#E6E6FA"> - <template #icon> - <RiLiLined /> - </template> - {{ mainStatistic.mainDate }} - </a-tag> - <a-tag color="#6495ED"> - <template #icon> - <YanJingLined /> - </template> - {{ mainStatistic.mainWatchCount }} - </a-tag> - <a-tag color="#B0C4DE"> - <template #icon> - <XieZiLined /> - </template> - 字数≈{{ mainStatistic.mainWordCount }}字 - </a-tag> - <a-tag color="#20B2AA"> - <template #icon> - <YueDuLined /> - </template> - 阅读时长≈{{ mainStatistic.mainReadCount }}分 - </a-tag> - </div> - <div class="blog-content"> - <div> - <a-image :preview="false" :width="200" - src="https://cdn.naccl.top/blog/blogHosting/2024/02/B01/f56c5bbe-469c-4eb7-a994-9281d6eed689.png" /> - </div> - - <span style="height: 160px">测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试</span> - </div> - - <div class="read-button"> - <a-button type="primary" shape="round">阅读全文</a-button> - </div> - </a-card> - </a-badge-ribbon> - </div> + <RouterView /> <div class="rightBar"> <a-card hoverable style="width: 400px;"> <template #cover> @@ -157,12 +121,12 @@ </Simplebar> </template> <script lang="ts" setup> -import { h, reactive, ref } from 'vue'; +import { h, reactive, ref,nextTick } from 'vue'; import { MenuProps } from 'ant-design-vue/es/menu'; import { HomeOutlined, HighlightOutlined, ProfileOutlined, CameraOutlined, UsergroupDeleteOutlined, DownCircleOutlined } from '@ant-design/icons-vue'; import { MusicLined, EmailLined, QQLined, WechatLined, GravatarLined, GitHubLined } from "@/assets" import Typed from 'typed.js'; -import { onMounted } from 'vue'; +import { onMounted,watch } from 'vue'; import type { CSSProperties } from 'vue'; import { CaretRightOutlined } from '@ant-design/icons-vue'; import 'APlayer/dist/APlayer.min.css'; @@ -170,9 +134,10 @@ import APlayer from 'APlayer'; import { createEcharts } from "@/hooks/intex" import { SettingOutlined, EditOutlined, EllipsisOutlined } from '@ant-design/icons-vue'; import { RiLiLined, YueDuLined, YanJingLined, XieZiLined } from '@/assets'; -import { useRouter } from 'vue-router'; +import { useRouter, useRoute } from 'vue-router'; const random = ref(); const router = useRouter() +const route = useRoute() const heat = ref(null); const activeKey = ref(['']); const text = `A dog is a type of domesticated animal.Known for its loyalty and faithfulness,it can be found as a welcome guest in many households across the world.`; @@ -328,58 +293,32 @@ onMounted(() => { createEcharts(heat, heatMapData); }) -const current = ref<string[]>(['mail']); -const show_menu = ref(false); -// 定义滚动条滚到一半显示导航菜单 -const handleScroll = () => { - const scrollbar = document.querySelector('.simplebar-content-wrapper'); - if (scrollbar) { - const scrollOffset = scrollbar.scrollTop; - const halfViewportHeight = scrollbar.clientHeight / 2; - show_menu.value = scrollOffset > halfViewportHeight; - } -}; - -// 点击按钮,实现滚动到视窗高度距离,如果已经滚动,只需要滚动视窗高度-已经滚动的距离 -const downScroll = () => { - const scrollbar = document.querySelector('.simplebar-content-wrapper'); - if (scrollbar) { - const scrollTop = scrollbar.scrollTop; - - const viewportHeight = scrollbar.clientHeight; - const scrollDistance = viewportHeight - scrollTop - 60; - - setTimeout(() => { - scrollbar.scrollBy({ top: scrollDistance, behavior: 'smooth' }); - }, 300); - } -}; - -const mainStatistic = reactive<{ mainDate: string, mainWatchCount: string, mainWordCount: string, mainReadCount: string }>({ - mainDate: "2024-06-11", - mainWatchCount: "9999", - mainWordCount: "9999", - mainReadCount: "9999" -}) +// 导航菜单 +const show_menu = ref(false); +const show_carousel = ref(true); +const show_author = ref(true) const items = ref<MenuProps['items']>([ { key: 'home', icon: () => h(HomeOutlined), label: '首页', title: '首页', + url: '/' }, { key: 'blog', icon: () => h(HighlightOutlined), label: '博客', title: '博客', + url: "/blog" }, { key: 'diary', icon: () => h(ProfileOutlined), label: '日记', title: '日记', + url: '/diary' }, { key: 'album', @@ -412,6 +351,50 @@ const items = ref<MenuProps['items']>([ title: '关于sunfree', }, ]); +const handleScrollEnabled = ref(true); +// 定义滚动条滚到一半显示导航菜单 +const handleScroll = () => { + if (!handleScrollEnabled.value) return; + const scrollbar = document.querySelector('.simplebar-content-wrapper'); + if (scrollbar) { + const scrollOffset = scrollbar.scrollTop; + const halfViewportHeight = scrollbar.clientHeight / 2; + show_menu.value = scrollOffset > halfViewportHeight; + } +}; + +const menuClick = ({ item }: { items: any }) => { + // if (item.title != "首页") { + show_menu.value = true; + show_carousel.value = false; + handleScrollEnabled.value = false; + router.push(item.url) +} + +const current = ref<string[]>(['mail']); + + +// 点击按钮,实现滚动到视窗高度距离,如果已经滚动,只需要滚动视窗高度-已经滚动的距离 +const downScroll = () => { + const scrollbar = document.querySelector('.simplebar-content-wrapper'); + if (scrollbar) { + const scrollTop = scrollbar.scrollTop; + const viewportHeight = scrollbar.clientHeight; + const scrollDistance = viewportHeight - scrollTop + 48 + 48; + + setTimeout(() => { + scrollbar.scrollBy({ top: scrollDistance, behavior: 'smooth' }); + }, 300); + } +}; +// 定义文章 +// const articles=reactive({ +// img:"", + +// }) + + + const value = ref<string>(''); const onSearch = (searchValue: string) => { console.log('use value', searchValue); @@ -434,9 +417,8 @@ const gravatarClick = () => { display: flex; justify-content: center; align-items: center; - padding: 10px 0; width: 100%; - padding: 0 24px; + height: 48px; border-bottom: 1px solid rgba(5, 5, 5, 0.06); position: fixed; background-color: white; @@ -446,9 +428,7 @@ const gravatarClick = () => { z-index: 999; } -.headerMenu>* { - margin: 0 24px; -} + /* 作者名称 */ .author { @@ -493,7 +473,7 @@ const gravatarClick = () => { .mainContainer { display: flex; justify-content: center; - padding-top: 60px; + /* padding-top: 48px; */ background-color: rgba(5, 5, 5, 0.08); } @@ -537,39 +517,6 @@ const gravatarClick = () => { margin: 12px; } -.main { - width: 45%; - margin: 0 24px; -} - -.main h2 { - text-align: center; -} - -.main .tag-group { - display: flex; - justify-content: center; -} - -.main .tag-group>* { - color: black; - margin: 0 12px; -} - -.main .blog-content { - display: flex; - margin: 48px; -} -.main .blog-content>:nth-child(2){ - overflow: hidden; - text-overflow: ellipsis; - white-space: pre-wrap; /* 防止文本换行 */ -} - -.main .read-button { - display: flex; - justify-content: center; -} .rightBar { width: 20%; diff --git a/src/components/blogs/ceshi.vue b/src/components/blogs/ceshi.vue index a27216f..0247c72 100644 --- a/src/components/blogs/ceshi.vue +++ b/src/components/blogs/ceshi.vue @@ -1,27 +1,65 @@ <template> - <div ref="wordcloud" style="width: 500px; height: 500px;"></div> + <a-menu v-model:selectedKeys="current" mode="horizontal" :items="items" /> </template> - -<script setup> -import { ref, onMounted } from 'vue'; -import wordcloud from 'wordcloud'; - -const wordcloudRef = ref(null); - -const tags = [ - { text: 'Java', weight: 5 }, - { text: 'Python', weight: 3 }, - { text: 'JavaScript', weight: 7 }, - { text: 'Ant Design', weight: 2 }, - { text: 'Vue.js', weight: 4 }, - { text: 'React', weight: 6 }, - { text: 'Angular', weight: 3 }, - { text: 'CSS', weight: 4 }, - { text: 'HTML', weight: 5 } -]; - -onMounted(() => { - const canvas = wordcloudRef.value; - wordcloud(canvas, { list: tags }); -}); +<script lang="ts" setup> +import { h, ref } from 'vue'; +import { MailOutlined, AppstoreOutlined, SettingOutlined } from '@ant-design/icons-vue'; +import { MenuProps } from 'ant-design-vue'; +const current = ref<string[]>(['mail']); +const items = ref<MenuProps['items']>([ + { + key: 'mail', + icon: () => h(MailOutlined), + label: 'Navigation One', + title: 'Navigation One', + }, + { + key: 'app', + icon: () => h(AppstoreOutlined), + label: 'Navigation Two', + title: 'Navigation Two', + }, + { + key: 'sub1', + icon: () => h(SettingOutlined), + label: 'Navigation Three - Submenu', + title: 'Navigation Three - Submenu', + children: [ + { + type: 'group', + label: 'Item 1', + children: [ + { + label: 'Option 1', + key: 'setting:1', + }, + { + label: 'Option 2', + key: 'setting:2', + }, + ], + }, + { + type: 'group', + label: 'Item 2', + children: [ + { + label: 'Option 3', + key: 'setting:3', + }, + { + label: 'Option 4', + key: 'setting:4', + }, + ], + }, + ], + }, + { + key: 'alipay', + label: h('a', { href: 'https://antdv.com' }, 'Navigation Four - Link'), + title: 'Navigation Four - Link', + }, +]); </script> + diff --git a/src/router/admin.ts b/src/router/admin.ts index 1925f4d..5d98b9d 100644 --- a/src/router/admin.ts +++ b/src/router/admin.ts @@ -13,6 +13,11 @@ const adminRoute:Array<RouteRecordRaw>=[ } ] - } + }, + { + path: "/login", + name: "login", + component: () => import("@/components/admin/SignIn.vue"), + }, ] export default adminRoute \ No newline at end of file diff --git a/src/router/blog.ts b/src/router/blog.ts index e69de29..c474111 100644 --- a/src/router/blog.ts +++ b/src/router/blog.ts @@ -0,0 +1,28 @@ +import type { RouteRecordRaw } from 'vue-router' + +const blogRoute:Array<RouteRecordRaw>=[ + { + path: "/", + redirect:"/blog", + name: "home", + component: () => import("@/components/blogs/HomePage.vue"), + children:[ + { + path:"/blog", + name:"blog", + component:()=>import("@/views/blog/BlogContentView.vue") + }, + { + path:"/diary", + name:"diary", + component:()=>import("@/views/blog/DiaryContentView.vue") + }, + ] + }, + { + path:"/ceshi", + name:"ceshi", + component:()=>import("@/components/blogs/ceshi.vue") + } +] +export default blogRoute diff --git a/src/router/home.ts b/src/router/home.ts deleted file mode 100644 index 210c346..0000000 --- a/src/router/home.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { RouteRecordRaw } from 'vue-router' - -const homeRoute:Array<RouteRecordRaw>=[ - { - path: "/", - name: "home", - component: () => import("@/components/blogs/HomePage.vue"), - }, - { - path: "/login", - name: "login", - component: () => import("@/components/admin/SignIn.vue"), - }, - { - path:"/ceshi", - name:"ceshi", - component:()=>import("@/components/blogs/ceshi.vue") - } -] -export default homeRoute diff --git a/src/router/index.ts b/src/router/index.ts index 24b7c92..d881a9a 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,6 +1,6 @@ import { createRouter, createWebHistory,type RouteRecordRaw } from 'vue-router'; -import homeRoute from "./home" +import homeRoute from "./blog" import adminRoute from './admin'; const route:Array<RouteRecordRaw>=[ diff --git a/src/views/blog/BlogContentView.vue b/src/views/blog/BlogContentView.vue new file mode 100644 index 0000000..e5e118c --- /dev/null +++ b/src/views/blog/BlogContentView.vue @@ -0,0 +1,142 @@ +<template> + <div class="main"> + <div class="mainContent" v-for="article in 2"> + <a-badge-ribbon text="Hippies" color="black"> + <a-card hoverable> + <h2>操作系统的安装</h2> + <div class="tag-group"> + <a-tag color="#E6E6FA"> + <template #icon> + <RiLiLined /> + </template> + {{ mainStatistic.mainDate }} + </a-tag> + <a-tag color="#6495ED"> + <template #icon> + <YanJingLined /> + </template> + {{ mainStatistic.mainWatchCount }} + </a-tag> + <a-tag color="#B0C4DE"> + <template #icon> + <XieZiLined /> + </template> + 字数≈{{ mainStatistic.mainWordCount }}字 + </a-tag> + <a-tag color="#20B2AA"> + <template #icon> + <YueDuLined /> + </template> + 阅读时长≈{{ mainStatistic.mainReadCount }}分 + </a-tag> + </div> + <div class="blog-content"> + <div> + <a-image :preview="false" :width="200" + src="https://cdn.naccl.top/blog/blogHosting/2024/02/B01/f56c5bbe-469c-4eb7-a994-9281d6eed689.png" /> + </div> + <div class="text-container"> + 这是内容 + </div> + </div> + <div class="read-button"> + <a-button type="primary" shape="round">阅读全文</a-button> + </div> + </a-card> + </a-badge-ribbon> + </div> + </div> +</template> + +<script setup lang='ts'> +import { reactive } from 'vue'; +const mainStatistic = reactive<{ mainDate: string, mainWatchCount: string, mainWordCount: string, mainReadCount: string }>({ + mainDate: "2024-06-11", + mainWatchCount: "9999", + mainWordCount: "9999", + mainReadCount: "9999" +}) + +</script> + +<style scoped> +.main { + width: 45%; + margin: 0 24px; +} + +.main .mainContent { + margin-bottom: 24px; +} + +.main h2 { + text-align: center; +} + +.main .tag-group { + display: flex; + justify-content: center; +} + +.main .tag-group>* { + color: black; + margin: 0 12px; +} + +.main .blog-content { + display: flex; + margin: 48px; +} + +.main .blog-content>:nth-child(2) { + overflow: hidden; + text-overflow: ellipsis; + white-space: pre-wrap; + /* 防止文本换行 */ +} + +.main .read-button { + display: flex; + justify-content: center; + +} + +.main .read-button button { + color: #fff; + border: none; + cursor: pointer; + background-color: #007bff; + /* 初始背景颜色 */ + animation: colorChange 3s infinite alternate; + /* 添加颜色变化的动画 */ +} + +@keyframes colorChange { + 0% { + background-color: #007bff; + /* 初始颜色 */ + } + + 50% { + background-color: #ff7e5f; + /* 中间颜色 */ + } + + 100% { + background-color: #feb47b; + /* 结束颜色 */ + } +} + +.main .text-container { + text-overflow: ellipsis; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 6; + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 2; + margin-left: 24px; + +} +</style> \ No newline at end of file diff --git a/src/views/blog/DiaryContentView.vue b/src/views/blog/DiaryContentView.vue new file mode 100644 index 0000000..9038221 --- /dev/null +++ b/src/views/blog/DiaryContentView.vue @@ -0,0 +1,143 @@ +<template> + <div class="main"> + <div class="mainContent" v-for="article in 2"> + <a-badge-ribbon text="Hippies" color="black"> + <a-card hoverable> + <h2>操作系统的安装</h2> + <div class="tag-group"> + <a-tag color="#E6E6FA"> + <template #icon> + <RiLiLined /> + </template> + {{ mainStatistic.mainDate }} + </a-tag> + <a-tag color="#6495ED"> + <template #icon> + <YanJingLined /> + </template> + {{ mainStatistic.mainWatchCount }} + </a-tag> + <a-tag color="#B0C4DE"> + <template #icon> + <XieZiLined /> + </template> + 字数≈{{ mainStatistic.mainWordCount }}字 + </a-tag> + <a-tag color="#20B2AA"> + <template #icon> + <YueDuLined /> + </template> + 阅读时长≈{{ mainStatistic.mainReadCount }}分 + </a-tag> + </div> + <div class="blog-content"> + <div> + <a-image :preview="false" :width="200" + src="https://cdn.naccl.top/blog/blogHosting/2024/02/B01/f56c5bbe-469c-4eb7-a994-9281d6eed689.png" /> + </div> + <div class="text-container"> + 这是内容 + </div> + </div> + <div class="read-button"> + <a-button type="primary" shape="round">阅读全文</a-button> + </div> + </a-card> + </a-badge-ribbon> + </div> + </div> +</template> + +<script setup lang='ts'> +import { reactive } from 'vue'; +const mainStatistic = reactive<{ mainDate: string, mainWatchCount: string, mainWordCount: string, mainReadCount: string }>({ + mainDate: "2024-06-11", + mainWatchCount: "9999", + mainWordCount: "9999", + mainReadCount: "9999" +}) + +</script> + +<style scoped> +.main { + + width: 45%; + margin: 0 24px; +} + +.main .mainContent { + margin-bottom: 24px; +} + +.main h2 { + text-align: center; +} + +.main .tag-group { + display: flex; + justify-content: center; +} + +.main .tag-group>* { + color: black; + margin: 0 12px; +} + +.main .blog-content { + display: flex; + margin: 48px; +} + +.main .blog-content>:nth-child(2) { + overflow: hidden; + text-overflow: ellipsis; + white-space: pre-wrap; + /* 防止文本换行 */ +} + +.main .read-button { + display: flex; + justify-content: center; + +} + +.main .read-button button { + color: #fff; + border: none; + cursor: pointer; + background-color: #007bff; + /* 初始背景颜色 */ + animation: colorChange 3s infinite alternate; + /* 添加颜色变化的动画 */ +} + +@keyframes colorChange { + 0% { + background-color: #007bff; + /* 初始颜色 */ + } + + 50% { + background-color: #ff7e5f; + /* 中间颜色 */ + } + + 100% { + background-color: #feb47b; + /* 结束颜色 */ + } +} + +.main .text-container { + text-overflow: ellipsis; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 6; + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 2; + margin-left: 24px; + +} +</style> \ No newline at end of file