You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

569 lines
18 KiB

10 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
10 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
10 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
10 months ago
  1. <template>
  2. <Simplebar @scroll="handleScroll">
  3. <!-- 头部导航菜单 -->
  4. <div class="headerMenu" v-if="show_menu">
  5. <a-menu v-model:selectedKeys="current" mode="horizontal" :items="items" style="border-bottom: none;"
  6. @click="menuClick" @select="menuSelect"/>
  7. <a-input-search v-model:value="value" placeholder="search" style="width: 200px" @search="onSearch" />
  8. </div>
  9. <div class="author" v-if="show_author"></div>
  10. <!-- 轮播 -->
  11. <div class="carousel" v-if="show_carousel">
  12. <a-carousel autoplay>
  13. <div class="img"><img src="/src/assets/images/nav1.png" alt=""></div>
  14. <div class="img"><img src="/src/assets/images/nav10.png" alt=""></div>
  15. <div class="img"><img src="/src/assets/images/nav13.png" alt=""></div>
  16. </a-carousel>
  17. </div>
  18. <!-- 操作按钮滚动 -->
  19. <div class="anchorDown">
  20. <a-button type="link" shape="circle" size="large" @click="downScroll">
  21. <template #icon>
  22. <DownCircleOutlined style="font-size: 35px;color: aliceblue;" spin />
  23. </template>
  24. </a-button>
  25. </div>
  26. <!-- 主要内容区域 -->
  27. <div class="mainContainer" :style="mainCss">
  28. <div class="leftBar">
  29. <a-card hoverable>
  30. <template #cover>
  31. <img alt="example" :src="img" />
  32. </template>
  33. <h1>sunfree</h1>
  34. <div class="cardText"></div>
  35. <div class="button-group">
  36. <a-button shape="circle" size="large" @click="gravatarClick">
  37. <GravatarLined />
  38. </a-button>
  39. <a-button shape="circle" size="large">
  40. <QQLined />
  41. </a-button>
  42. <a-button shape="circle" size="large">
  43. <WechatLined />
  44. </a-button>
  45. <a-button shape="circle" size="large">
  46. <MusicLined />
  47. </a-button>
  48. <a-button shape="circle" size="large">
  49. <GitHubLined />
  50. </a-button>
  51. </div>
  52. <div class="fold-panel">
  53. <a-collapse v-model:activeKey="activeKey" :bordered="false" expandIconPosition="end">
  54. <template #expandIcon="{ isActive }">
  55. <caret-right-outlined :rotate="isActive ? 90 : 0" />
  56. </template>
  57. <a-collapse-panel key="1" header="内容1" :style="customStyle">
  58. <p>{{ text }}</p>
  59. </a-collapse-panel>
  60. <a-collapse-panel key="2" header="内容2" :style="customStyle">
  61. <p>{{ text }}</p>
  62. </a-collapse-panel>
  63. <a-collapse-panel key="3" header="内容3" :style="customStyle">
  64. <p>{{ text }}</p>
  65. </a-collapse-panel>
  66. </a-collapse>
  67. </div>
  68. </a-card>
  69. <a-card hoverable title="常用链接">
  70. <div class="button-group">
  71. <a-button type="dashed">Link</a-button>
  72. <a-button type="dashed">Link</a-button>
  73. <a-button type="dashed">Link</a-button>
  74. <a-button type="dashed">Link</a-button>
  75. <a-button type="dashed">Link</a-button>
  76. <a-button type="dashed">Link</a-button>
  77. <a-button type="dashed">Link</a-button>
  78. <a-button type="dashed">Link</a-button>
  79. <a-button type="dashed">Link</a-button>
  80. <a-button type="dashed">Link</a-button>
  81. <a-button type="dashed">Link</a-button>
  82. <a-button type="dashed">Link</a-button>
  83. </div>
  84. </a-card>
  85. </div>
  86. <RouterView />
  87. <div class="rightBar">
  88. <a-card hoverable style="width: 400px;">
  89. <template #cover>
  90. <div id="aplayer" style="width: 400px;"></div>
  91. <div class="heatmap" style="border-right: rgba(0, 0, 0, 0.5);">
  92. <div ref="heat" style="height: 100%;"></div>
  93. </div>
  94. <div class="statistic">
  95. <a-row>
  96. <a-col :span="8">
  97. <a-statistic title="DAYS" :value="112893" />
  98. </a-col>
  99. <a-col :span="8">
  100. <a-statistic title="DIARYS" :value="112893" />
  101. </a-col>
  102. <a-col :span="8">
  103. <a-statistic title="BLOGS" :value="112893" />
  104. </a-col>
  105. </a-row>
  106. </div>
  107. </template>
  108. </a-card>
  109. <a-card title="随机文章" :bordered="false" hoverable style="width: 400px;margin: 12px 0;">
  110. sces
  111. </a-card>
  112. <a-card title="标签云" :bordered="false" hoverable style="width: 400px;margin: 12px 0;">
  113. sces
  114. </a-card>
  115. </div>
  116. </div>
  117. </Simplebar>
  118. </template>
  119. <script lang="ts" setup>
  120. import { h, reactive, ref,nextTick } from 'vue';
  121. import { MenuProps } from 'ant-design-vue/es/menu';
  122. import { HomeOutlined, HighlightOutlined, ProfileOutlined, CameraOutlined, UsergroupDeleteOutlined, DownCircleOutlined } from '@ant-design/icons-vue';
  123. import { MusicLined, EmailLined, QQLined, WechatLined, GravatarLined, GitHubLined } from "@/assets"
  124. import Typed from 'typed.js';
  125. import { onMounted,watch } from 'vue';
  126. import type { CSSProperties } from 'vue';
  127. import { CaretRightOutlined } from '@ant-design/icons-vue';
  128. import 'APlayer/dist/APlayer.min.css';
  129. import APlayer from 'APlayer';
  130. import { createEcharts } from "@/hooks/intex"
  131. import { SettingOutlined, EditOutlined, EllipsisOutlined } from '@ant-design/icons-vue';
  132. import { RiLiLined, YueDuLined, YanJingLined, XieZiLined } from '@/assets';
  133. import { useRouter, useRoute } from 'vue-router';
  134. const random = ref();
  135. const router = useRouter()
  136. const route = useRoute()
  137. const heat = ref(null);
  138. const activeKey = ref(['']);
  139. 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.`;
  140. const customStyle =
  141. 'background: #F5F5F5;border-radius: 4px;margin-bottom: 12px;border: 0;overflow: hidden';
  142. const scrollbar=ref<Element | null>(null);
  143. onMounted(() => {
  144. // 定义home页的博客标题名
  145. new Typed('.author', {
  146. strings: ['SunFree.'],
  147. typeSpeed: 200,
  148. backSpeed: 150,
  149. loop: true,
  150. loopCount: Infinity,
  151. showCursor: false
  152. });
  153. // 定义个人座右铭
  154. new Typed('.cardText', {
  155. strings: ['做三流测试,品瀚霖人生!'],
  156. typeSpeed: 200,
  157. backSpeed: 150,
  158. loop: true, // 开启循环
  159. loopCount: Infinity, // 无限循环
  160. showCursor: false // 取消光标
  161. });
  162. new APlayer({
  163. container: document.getElementById('aplayer'),
  164. mini: false,
  165. autoplay: false,
  166. theme: '#FADFA3',
  167. loop: 'all',
  168. order: 'random',
  169. preload: 'auto',
  170. volume: 0.7,
  171. mutex: true,
  172. listFolded: true,
  173. listMaxHeight: 90,
  174. lrcType: 3,
  175. audio: [
  176. {
  177. name: 'name1',
  178. artist: 'artist1',
  179. url: 'url1.mp3',
  180. cover: 'cover1.jpg',
  181. lrc: 'lrc1.lrc',
  182. theme: '#ebd0c2'
  183. },
  184. {
  185. name: 'name2',
  186. artist: 'artist2',
  187. url: 'url2.mp3',
  188. cover: 'cover2.jpg',
  189. lrc: 'lrc2.lrc',
  190. theme: '#46718b'
  191. }
  192. ]
  193. });
  194. function generateDates(numDays: number) {
  195. const dates = [];
  196. const currentDate = new Date();
  197. for (let i = 0; i < numDays; i++) {
  198. const date = new Date(currentDate);
  199. date.setDate(currentDate.getDate() - i);
  200. dates.push(
  201. { date: date.toISOString().split('T')[0], blogCount: 0 }
  202. ); // 包含日期和评论数
  203. }
  204. return dates;
  205. }
  206. // 初始化60天的数据
  207. const data = generateDates(60);
  208. console.log(`output->`, data)
  209. data[3].blogCount = 5;
  210. data[15].blogCount = 10;
  211. data[25].blogCount = 3;
  212. // 重新排列数据
  213. const newData = [];
  214. for (let i = 0; i < 60; i += 15) {
  215. // 取出每个15天的数据,并反转顺序
  216. const chunk = data.slice(i, i + 15).reverse();
  217. newData.push(...chunk);
  218. }
  219. const formattedData = newData.map((value, index) => [index % 15, Math.floor(index / 15), value.blogCount]);
  220. const heatMapData = {
  221. tooltip: {
  222. position: 'top',
  223. formatter: function (params: any) {
  224. const item = newData[params.dataIndex];
  225. if (item.blogCount > 0) {
  226. return `${item.date}<br/>COMMENTS: ${item.blogCount}`;
  227. } else {
  228. return `${item.date}`;
  229. }
  230. }
  231. },
  232. grid: {
  233. left: '0', // 左边距
  234. right: '0', // 右边距
  235. top: '0', // 上边距
  236. bottom: '0',
  237. },
  238. xAxis: {
  239. type: 'category',
  240. data: Array.from({ length: 15 }, (_, i) => `Col ${i + 1}`),
  241. splitArea: {
  242. show: true
  243. },
  244. show: false
  245. },
  246. yAxis: {
  247. type: 'category',
  248. data: ['Row 1', 'Row 2', 'Row 3', 'Row 4'],
  249. splitArea: {
  250. show: false
  251. },
  252. show: false
  253. },
  254. visualMap: {
  255. min: 0,
  256. max: 10,
  257. calculable: true,
  258. orient: 'horizontal',
  259. left: 'center',
  260. bottom: '15%',
  261. itemGap: 5,
  262. show: false,
  263. inRange: {
  264. color: ['#ffffff', '#000000'] // 0评论是白色, 非0评论是黑色
  265. }
  266. },
  267. series: [{
  268. type: 'heatmap',
  269. data: formattedData,
  270. itemStyle: {
  271. borderColor: 'rgba(0, 0, 0, 0.1)', // 设置边框颜色
  272. borderWidth: 0.5, // 设置边框宽度
  273. },
  274. label: {
  275. show: false,
  276. },
  277. emphasis: {
  278. itemStyle: {
  279. shadowBlur: 10,
  280. shadowColor: 'rgba(0, 0, 0, 0.5)',
  281. borderColor: '#fff', // 鼠标悬停时的边框颜色
  282. borderWidth: 2 // 鼠标悬停时的边框宽度
  283. }
  284. }
  285. }]
  286. };
  287. createEcharts(heat, heatMapData);
  288. scrollbar.value = document.querySelector('.simplebar-content-wrapper');
  289. // const storedShowMenu = localStorage.getItem('show_menu');
  290. // const storedShowCarousel = localStorage.getItem('show_carousel');
  291. // const storedScrollPosition = localStorage.getItem('scrollPosition');
  292. // const storedMainCssMarginTop = localStorage.getItem('mainCss_marginTop');
  293. // if (storedShowMenu !== null) {
  294. // show_menu.value = storedShowMenu === 'true';
  295. // }
  296. // if (storedShowCarousel !== null) {
  297. // show_carousel.value = storedShowCarousel === 'true';
  298. // }
  299. // if (storedScrollPosition !== null && scrollbar.value) {
  300. // scrollbar.value.scrollTop = parseInt(storedScrollPosition, 10);
  301. // }
  302. // if (storedMainCssMarginTop !== null) {
  303. // mainCss.marginTop = storedMainCssMarginTop;
  304. // }
  305. })
  306. // 导航菜单
  307. const show_menu = ref(false);
  308. const show_carousel = ref(true);
  309. const show_author = ref(true)
  310. const mainCss=reactive({
  311. marginTop:"0px"
  312. })
  313. const items = ref<MenuProps['items']>([
  314. {
  315. key: 'home',
  316. icon: () => h(HomeOutlined),
  317. label: '首页',
  318. title: '首页',
  319. url: '/'
  320. },
  321. {
  322. key: 'blog',
  323. icon: () => h(HighlightOutlined),
  324. label: '博客',
  325. title: '博客',
  326. url: "/blog"
  327. },
  328. {
  329. key: 'diary',
  330. icon: () => h(ProfileOutlined),
  331. label: '日记',
  332. title: '日记',
  333. url: '/diary'
  334. },
  335. {
  336. key: 'album',
  337. icon: () => h(CameraOutlined),
  338. label: '相册',
  339. title: '相册',
  340. children: [
  341. {
  342. label: '相册1',
  343. key: 'album1',
  344. },
  345. {
  346. label: '相册2',
  347. key: 'album2',
  348. },
  349. {
  350. label: '相册3',
  351. key: 'album3',
  352. },
  353. {
  354. label: '相册4',
  355. key: 'album4',
  356. },
  357. ],
  358. },
  359. {
  360. key: 'aboutme',
  361. icon: () => h(UsergroupDeleteOutlined),
  362. label: '关于sunfree',
  363. title: '关于sunfree',
  364. },
  365. ]);
  366. const handleScrollEnabled = ref(true);
  367. // 定义滚动条滚到一半显示导航菜单
  368. const handleScroll = () => {
  369. if (!handleScrollEnabled.value) return;
  370. if (scrollbar.value) {
  371. const scrollOffset = scrollbar.value.scrollTop;
  372. const halfViewportHeight = scrollbar.value.clientHeight / 2;
  373. show_menu.value = scrollOffset > halfViewportHeight;
  374. }
  375. };
  376. const menuClick = ({ item }: { item: any }) => {
  377. handleScrollEnabled.value=false
  378. if (scrollbar.value) {
  379. }
  380. if (item.url=="/" || item.url=="/home") {
  381. handleScrollEnabled.value=true
  382. show_carousel.value=true
  383. }else{
  384. show_menu.value=true
  385. show_carousel.value=false
  386. scrollbar.value!.scrollTop=0
  387. mainCss.marginTop="48px"
  388. // localStorage.setItem('show_menu', 'true');
  389. // localStorage.setItem('show_carousel', 'false');
  390. // localStorage.setItem('scrollPosition', '0');
  391. // localStorage.setItem('mainCss_marginTop', '48px');
  392. }
  393. router.push(item.url)
  394. }
  395. const current = ref<string[]>(['mail']);
  396. // 点击按钮,实现滚动到视窗高度距离,如果已经滚动,只需要滚动视窗高度-已经滚动的距离
  397. const downScroll = () => {
  398. if (scrollbar.value) {
  399. const scrollTop = scrollbar.value.scrollTop;
  400. const viewportHeight = scrollbar.value.clientHeight;
  401. const scrollDistance = viewportHeight - scrollTop -48;
  402. setTimeout(() => {
  403. scrollbar.value!.scrollBy({ top: scrollDistance, behavior: 'smooth' });
  404. }, 300);
  405. }
  406. };
  407. // 定义文章
  408. // const articles=reactive({
  409. // img:"",
  410. // })
  411. const value = ref<string>('');
  412. const onSearch = (searchValue: string) => {
  413. console.log('use value', searchValue);
  414. console.log('or use this.value', value.value);
  415. };
  416. const img = ref("https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png")
  417. const gravatarClick = () => {
  418. window.open("https://www.baidu.com")
  419. }
  420. </script>
  421. <style scoped>
  422. .headerMenu {
  423. display: flex;
  424. justify-content: center;
  425. align-items: center;
  426. width: 100%;
  427. height: 48px;
  428. border-bottom: 1px solid rgba(5, 5, 5, 0.06);
  429. position: fixed;
  430. background-color: white;
  431. transform: translateX(-50%);
  432. top: 0;
  433. left: 50%;
  434. z-index: 999;
  435. }
  436. /* 作者名称 */
  437. .author {
  438. position: absolute;
  439. display: inline-block;
  440. font-size: 100px;
  441. font-family: 'Courier New', Courier, monospace;
  442. background: linear-gradient(270deg, #f5f4f2, #d6cdc7, #4b4949);
  443. background-size: 400% 400%;
  444. -webkit-background-clip: text;
  445. color: transparent;
  446. background-clip: text;
  447. animation: salon-light-animation 3s ease infinite;
  448. top: 50%;
  449. left: 50%;
  450. transform: translateX(-50%);
  451. z-index: 999;
  452. }
  453. @keyframes salon-light-animation {
  454. 0% {
  455. background-position: 0% 50%;
  456. }
  457. 50% {
  458. background-position: 100% 50%;
  459. }
  460. 100% {
  461. background-position: 0% 50%;
  462. }
  463. }
  464. .carousel img{
  465. height: 100vh;
  466. width: 100vw;
  467. }
  468. .anchorDown {
  469. position: absolute;
  470. bottom: 100px;
  471. left: 50%;
  472. border-style: hidden;
  473. transform: translateX(-50%);
  474. }
  475. .mainContainer {
  476. display: flex;
  477. justify-content: center;
  478. padding-top: 48px;
  479. background-color: rgba(5, 5, 5, 0.08);
  480. }
  481. .leftBar {
  482. width: 15%;
  483. }
  484. .leftBar img {
  485. /* 图片自适应容器并保持宽高比例 */
  486. aspect-ratio: 1/1;
  487. }
  488. .leftBar>* {
  489. margin-bottom: 24px;
  490. }
  491. .leftBar h1 {
  492. text-align: center;
  493. font-family: Georgia, 'Times New Roman', Times, serif;
  494. }
  495. .leftBar .cardText {
  496. min-height: 60px;
  497. text-align: center;
  498. }
  499. .leftBar>:first-child .button-group {
  500. display: flex;
  501. margin: 0 12px 24px 12px;
  502. justify-content: space-between;
  503. }
  504. .leftBar>:nth-child(2) .button-group {
  505. display: flex;
  506. flex-wrap: wrap;
  507. justify-content: space-between;
  508. }
  509. .leftBar>:nth-child(2) .button-group>* {
  510. width: 40%;
  511. margin: 12px;
  512. }
  513. .rightBar {
  514. width: 20%;
  515. }
  516. .aplayer {
  517. margin: 0 0 24px 0;
  518. }
  519. .heatmap {
  520. margin: 24px 0;
  521. }
  522. .statistic {
  523. text-align: center;
  524. }
  525. .sitebar {
  526. width: 400px;
  527. }
  528. </style>