Merge branch 'master' of https://github.com/BaiMeow/hdu-cs-wiki
This commit is contained in:
@@ -4,6 +4,11 @@ import mathjax3 from 'markdown-it-mathjax3';
|
||||
import { main_sidebar, chapter2, chapter3, chapter4, chapter5, chapter6, chapter7, chapter8, chapter9 } from './sidebar.js';
|
||||
import { nav } from './nav.js';
|
||||
import PanguPlugin from 'markdown-it-pangu'
|
||||
import { createWriteStream } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
import { SitemapStream } from 'sitemap'
|
||||
|
||||
const links = []
|
||||
|
||||
const customElements = [
|
||||
'mjx-container',
|
||||
@@ -152,5 +157,23 @@ export default withMermaid({
|
||||
},
|
||||
},
|
||||
},
|
||||
transformHtml: (_, id, { pageData }) => {
|
||||
if (!/[\\/]404\.html$/.test(id))
|
||||
links.push({
|
||||
// you might need to change this if not using clean urls mode
|
||||
url: pageData.relativePath.replace(/((^|\/)index)?\.md$/, '$2'),
|
||||
lastmod: pageData.lastUpdated
|
||||
})
|
||||
},
|
||||
buildEnd: async ({ outDir }) => {
|
||||
const sitemap = new SitemapStream({
|
||||
hostname: 'https://hdu-cs.wiki/'
|
||||
})
|
||||
const writeStream = createWriteStream(resolve(outDir, 'sitemap.xml'))
|
||||
sitemap.pipe(writeStream)
|
||||
links.forEach((link) => sitemap.write(link))
|
||||
sitemap.end()
|
||||
await new Promise((r) => writeStream.on('finish', r))
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ export function nav() {
|
||||
{ text: '9.计算机网络', link: '9.计算机网络/9.计算机网络' },
|
||||
]
|
||||
},
|
||||
{ text: '博客', link: '/blog/' },
|
||||
{ text: 'Wiki史', link: '/wiki史' },
|
||||
{
|
||||
text: '友链', items:
|
||||
|
||||
@@ -23,8 +23,7 @@ export function main_sidebar() {
|
||||
{ text: '1.9问题专题:好想进入实验室', link: '/1.杭电生存指南/1.9问题专题:好想进入实验室' },
|
||||
{ text: '1.10如何读论文', link: '/1.杭电生存指南/1.10如何读论文' },
|
||||
{ text: '1.11陷入虚无主义?进来看看吧', link: '/1.杭电生存指南/1.11陷入虚无主义?进来看看吧' },
|
||||
{ text: '1.12程序员如何活久一点', link: '/1.杭电生存指南/1.12程序员如何活久一点' },
|
||||
{ text: '1.13选课原则与抢课技巧', link: '/1.杭电生存指南/1.13选课原则与抢课技巧' },
|
||||
{ text: '1.12选课原则与抢课技巧', link: '/1.杭电生存指南/1.12选课原则与抢课技巧' },
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -652,7 +651,6 @@ export function chapter9() {
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: '9.计算机网络', link: '/9.计算机网络/9.计算机网络' },
|
||||
{ text: '9.1链路层', link: '/9.计算机网络/9.1链路层' },
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
BIN
.vitepress/theme/font/NotoSansMono-Regular.ttf
Normal file
BIN
.vitepress/theme/font/NotoSansMono-Regular.ttf
Normal file
Binary file not shown.
BIN
.vitepress/theme/font/NotoSansSC-Bold.otf
Normal file
BIN
.vitepress/theme/font/NotoSansSC-Bold.otf
Normal file
Binary file not shown.
BIN
.vitepress/theme/font/NotoSansSC-Regular.otf
Normal file
BIN
.vitepress/theme/font/NotoSansSC-Regular.otf
Normal file
Binary file not shown.
@@ -2,10 +2,35 @@
|
||||
* Customize default theme styling by overriding CSS variables:
|
||||
* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
|
||||
*/
|
||||
@import url('https://fonts.loli.net/css2?family=Noto+Color+Emoji&family=Noto+Sans+Mono:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;700&display=swap');
|
||||
/**
|
||||
* Colors
|
||||
* -------------------------------------------------------------------------- */
|
||||
@font-face {
|
||||
font-family: 'Noto Color Emoji';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(https://gstatic.loli.net/s/notocoloremoji/v25/Yq6P-KqIXTD0t4D9z1ESnKM3-HpFabsE4tq3luCC7p-aXxcn.9.woff2) format('woff2');
|
||||
unicode-range: U+200d, U+261d, U+2620, U+2639-263a, U+2665, U+270a-270d, U+2728, U+2763-2764, U+2b50, U+fe0f, U+1f31a-1f31f, U+1f32b, U+1f383, U+1f389, U+1f3fb-1f3ff, U+1f440-1f450, U+1f463-1f465, U+1f479-1f47b, U+1f47d-1f480, U+1f485, U+1f48b-1f48c, U+1f493-1f49f, U+1f4a4-1f4a6, U+1f4a8-1f4ab, U+1f4af, U+1f525, U+1f573, U+1f590, U+1f595-1f596, U+1f5a4, U+1f5e3, U+1f600-1f644, U+1f648-1f64a, U+1f64c, U+1f64f, U+1f90c-1f925, U+1f927-1f92f, U+1f932-1f933, U+1f970-1f976, U+1f978-1f97a, U+1f9a0, U+1f9b4-1f9b7, U+1f9bb, U+1f9be-1f9bf, U+1f9d0, U+1f9e0-1f9e1, U+1fa75-1fa79, U+1fac0-1fac2, U+1fae0-1fae6, U+1fae8, U+1faf0-1faf8;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Sans SC';
|
||||
font-weight: 400;
|
||||
src: url('./font/NotoSansSC-Regular.otf');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Sans SC';
|
||||
font-weight: 700;
|
||||
src: url('./font/NotoSansSC-Bold.otf');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Sans Mono';
|
||||
font-weight: 400;
|
||||
src: url('./font/NotoSansMono-Regular.ttf');
|
||||
}
|
||||
|
||||
.dark .vp-doc a,#loading, .dark .vp-doc a>code, .dark .VPNavBarMenuLink.VPNavBarMenuLink:hover, .dark .VPNavBarMenuLink.VPNavBarMenuLink.active, .dark .link.link:hover, .dark .link.link.active, .dark .edit-link-button.edit-link-button, .dark .pager-link .title {
|
||||
color: var(--vp-c-brand-lighter);
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# 程序员如何活久一点
|
||||
### 1. 术语
|
||||
|
||||
* ACM: All-Cause Mortality / 全因死亡率
|
||||
|
||||
### 2. 目标
|
||||
|
||||
* 稳健地活得更久
|
||||
|
||||
### 3. 关键结果
|
||||
|
||||
* 降低66.67%全因死亡率
|
||||
* 增加\~20年预期寿命
|
||||
* ~~维持多巴胺于中轴~~
|
||||
|
||||
### 4. 分析
|
||||
|
||||
* 主要参考:对ACM的学术文献相对较多,可以作为主要参考
|
||||
* 增加寿命与ACM关系非线性:显然增加寿命与ACM关系是非线性函数,这里假设 `DeltaLifeSpan=(1/(1+DeltaACM)-1)*10`(DeltaACM为ACM变化值;公式欢迎优化)
|
||||
* 变量无法简单叠加:显然各个变量之间并不符合独立同分布假设,变量之间的实际影响也并不明确
|
||||
* 存在矛盾观点:所有的证据都有文献/研究对应,但注意到:有些文献之间有显著矛盾的观点(如对于碳水摄入比例的矛盾);有些文献存在较大争议(如认为22点前睡觉会提升43%全因死亡率)
|
||||
* 研究仅表达相关:所有文献表明的更多是相关而非因果,在阅读时要考虑文献是否充分证明了因果 —— 如某文献表明了日均>=7000步的人有显著低的全因死亡率。但步数少的人可能包含更多长期病患,如果没有合理的排除这块数据,那此文献调查失真
|
||||
|
||||
### 5. 行动
|
||||
|
||||
* 输入
|
||||
* 固体:吃白肉(-11%\~-3% ACM)、蔬果为主(-26%\~-17% ACM),多吃辣(-23% ACM),多吃坚果(-27%\~-4% ACM),*少吃蛋黄(否则+7% ACM/0.5颗/天)(存在争议)*,中量碳水、多吃植物蛋白(-10% ACM),少吃超加工食物(-62%\~-18%)
|
||||
* 液体:喝咖啡(-22%\~-12% ACM),喝牛奶(-17%\~-10% ACM),喝茶(-15%\~-8% ACM),少喝或不喝甜味饮料(否则每天一杯+7% ACM,+多巴胺),戒酒或每周100g(纯酒精量(g)=饮酒量(ml)×酒精浓度(%)×酒精密度0.8g/ml)内(否则+\~50% ACM,无上限)
|
||||
* 气体:不吸烟(否则+~50% ACM,-12\~-11年寿命)
|
||||
* 光照:晒太阳(-~40% ACM)
|
||||
* 药物:二甲双胍(糖尿病人相比正常人可以+3年)、复合维生素(-8%癌症风险)、亚精胺(-60%\~-30% ACM)、葡萄糖胺(-39% ACM)
|
||||
* 输出
|
||||
* 运动:每周3次45分钟挥拍运动(-47% ACM)
|
||||
* 日常:刷牙(-25% ACM)
|
||||
* 睡眠:每天睡7小时全因死亡率最低;且22-24点间最好,*早睡+43% ACM,晚睡+15% ACM(存在争议)*
|
||||
* 上下文
|
||||
* 体重:减肥(-54% ACM)
|
||||
|
||||
::: tip 🧑🍳
|
||||
全文 [程序员延寿指南 | A programmer's guide to live longer](https://github.com/geekan/HowToLiveLonger)
|
||||
:::
|
||||
@@ -34,7 +34,7 @@ wget http://ftp.gnu.org/gnu/coreutils/coreutils-8.32.tar.xz
|
||||
tar -xJf coreutils-8.32.tar.xz
|
||||
cd coreutils-8.32/
|
||||
# Download patch
|
||||
wget https://raw.githubusercontent.com/jarun/advcpmv/master/advcpmv-0.8-8.32.patch
|
||||
wget https://ghproxy.com/https://raw.githubusercontent.com/jarun/advcpmv/master/advcpmv-0.8-8.32.patch
|
||||
# Patching display with process bar
|
||||
patch -p1 -i advcpmv-0.8-8.32.patch
|
||||
# Compile then install
|
||||
|
||||
@@ -148,10 +148,9 @@ https://www.runoob.com/http/http-intro.html
|
||||
|
||||
#### 补充资料:
|
||||
|
||||
- [《互联网时代》纪录片](https://www.bilibili.com/video/BV1DU4y147XR/) - 与 HTTP 没什么关系,但给当时的我带来极大的震撼和触动。互联网是人类连接的重要一步,是对人类自由、平等、互通之理念长达半个世纪的深刻贯彻。
|
||||
|
||||
<Bilibili bvid='BV1DU4y147XR'/>
|
||||
- [《互联网时代》纪录片](https://www.bilibili.com/video/BV1uE411o7UW/) - 与 HTTP 没什么关系,但给当时的我带来极大的震撼和触动。互联网是人类连接的重要一步,是对人类自由、平等、互通之理念长达半个世纪的深刻贯彻。
|
||||
|
||||
<Bilibili bvid='BV1uE411o7UW'/>
|
||||
|
||||
> 原本稀薄的得以聚合,曾经蜷曲的得以伸展,容易被忽略的得以显现,可能被排斥的获得接纳:孤独的不再孤独,卑微的不再卑微,每一个生命绽放的声音,从来没有像这样韵味深长。
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
本讲义的计算机网络部分共分为5个章节
|
||||
|
||||
## 计网速通
|
||||
## 计算机网络速通
|
||||
|
||||
虽然名字看起来像是考前抱佛脚的章节,但他速通的并不是计网这一课程,是做简单Web开发所必须具备的计网知识。
|
||||
|
||||
@@ -16,29 +16,31 @@
|
||||
|
||||
上面提到“应用层和传输层”,或许你现在还不知道计算机网络的五层结构(也有其他划分,但是该划分利于学习),这也没关系,在本章节,可以暂时也不需要知道。
|
||||
|
||||
而计算机网络这一课程其实往往并不太会涉及到这一块内容,或许网络开发和协议分析一类的选修课程会讲解这一部分内容?
|
||||
计算机网络这一课程其实往往并不太会涉及到这一块内容,或许网络开发一类的选修课程会讲解这一部分内容。
|
||||
|
||||
## 计网基础
|
||||
## 计算机网络基础
|
||||
|
||||
这里是计算机网络课程的重点内容,并且适当地做出一些拓展,尽量让大家对计算机网络拥有一个完整且合理自洽的知识图谱。
|
||||
这里是计算机网络课程的重点内容,并且适当地做出一些拓展,使其更贴近于现行互联网,尽量让大家对计算机网络拥有一个完整且合理自洽的知识图谱。
|
||||
|
||||
写这篇讲义的我本人非常注重知识的自洽,就比如说计网的整个体系,他确实很庞大也需要这么庞大来解决全球的网络问题。
|
||||
|
||||
我认为如果你的知识并不能够自洽,那么在你的脑海中这其实就是异常的,不自然的,需要拐弯子才能想明白的。反之,在你的脑海中自洽的知识你是很容易理清其中逻辑的而且不容易忘,因为此时你会觉得“他就该这样,不然呢?”。
|
||||
|
||||
在这个章节我们会从物理层开始自底向上地介绍计算机网络,直到讲解完传输层,不是自顶向下哈,这里选择的是教材的反方向。两个方向其实都有他的道理,自底向上是符合历史逻辑的,毕竟得先有下层的支持才会有上层。
|
||||
在这个章节我们会从物理层开始自底向上地介绍计算机网络,直到讲解完传输层,自底向上是符合历史逻辑的,得先有下层的支持才会有上层。
|
||||
|
||||
## 路由与交换
|
||||
|
||||
路由与交换的理论知识,并不涉及实践,其实大家也没这个需求,就不做过多的讲解了。
|
||||
路由与交换的理论知识,并不涉及实践主要应付考试,但为了追求知识体系完整,会比考试内容稍多,但都是理解性质的。其实大家一般也没这个需求,除非专门做运维或者类似方向的开发,大伙都不需要了解具体怎么搭建网络,不会做过多的原理性讲解了。
|
||||
|
||||
如果你确实有在真实世界中部署路由协议的需求,请移步路由佬入门指南或者拿好你的设备并考虑加入DN11。
|
||||
如果你确实有在真实世界中搭建网络的需求,请移步路由佬入门指南或者拿好你的设备并考虑加入DN11。
|
||||
|
||||
主要讨论一下路由器,交换机,各种路由协议和他们工作的位置,还有NAT,最终把这些东西排排好,给大家一个完整的互联网模型(对比真实互联网做了一些简化,但该有的协议和设备都会有)
|
||||
这里主要讨论一下路由器,交换机,各种路由协议和他们工作的位置,还有NAT,最终把这些东西排排好,给大家一个完整的互联网模型(对比真实互联网做了一些简化,但该有的协议类型都会有)
|
||||
|
||||
## 隧道和代理
|
||||
|
||||
其实到现在互联网的全图景已经差不多讲解完了,但除此之外隧道和代理也是计算机网络中重要的一部分,他们工作的比较高的层却提供着更低层次的功能(其实路由协议很多也这样)。
|
||||
其实到现在一个理想化的互联网全图景已经差不多讲解完了,现在要正式完全脱离计算机网络这一课程的范畴了。
|
||||
|
||||
隧道和代理也是计算机网络中重要的一部分,他们工作的比较高的层却提供着更低层次的功能(其实路由协议很多也这样)。
|
||||
|
||||
前面讲解到,通过配置路由协议可以进行路由交换完成组网,但这仅仅可用于物理设备,如果两台路由器之间并没有网线的直接连接,那么我们的路由协议根本无法工作。
|
||||
|
||||
@@ -61,3 +63,49 @@
|
||||
有这样的一个群体,我们普遍称呼他们为“路由佬”,他们便是这样一群,沉迷于配网的一群人。
|
||||
|
||||
本章节存在的意义和前面的章节不同,并非是教学,而是劝人快去配网,非常重实践,上面讨论的都是简化模型,理想模型,学习模型,再往下就是实验性网络和真实互联网了,这其实已经脱离了该讲义的宗旨了,所以只会概述概述概述。
|
||||
## 画个饼先
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
计算机网络 --> 计算机网络速通
|
||||
计算机网络 --> 计算机网络基础
|
||||
计算机网络 --> 路由与交换
|
||||
计算机网络 --> 隧道与代理
|
||||
计算机网络 --> 路由佬入门指南
|
||||
计算机网络基础 ---> 物理层
|
||||
计算机网络基础 ---> 链路层
|
||||
计算机网络基础 ---> 网络层
|
||||
计算机网络基础 ---> 传输层
|
||||
计算机网络基础 ---> DNS与应用层概述
|
||||
路由与交换 ---> 路由设备
|
||||
路由与交换 ---> 路由协议
|
||||
路由与交换 ---> NAT
|
||||
路由与交换 ---> 真实互联网概述
|
||||
隧道与代理 ---> GRE
|
||||
隧道与代理 ---> WireGuard
|
||||
隧道与代理 ---> L2TP/IPSec
|
||||
隧道与代理 ---> 正向代理
|
||||
隧道与代理 ---> 反向代理
|
||||
路由佬入门指南 ---> openwrt/ikuai/ros/vyos 介绍
|
||||
路由佬入门指南 ---> 主路由,旁路由,单臂路由 以及 All in boom
|
||||
路由佬入门指南 ---> 双节点异地组网,以 WireGuard 为例
|
||||
路由佬入门指南 ---> 多节点高可用网络概论,以 OSPF over WireGuard 为例
|
||||
路由佬入门指南 ---> 大规模实验性网络概论
|
||||
路由佬入门指南 ---> 走得更深入...
|
||||
链路层 ---> 数据帧/MAC/CRC
|
||||
链路层 ---> PPP
|
||||
链路层 ---> ARP
|
||||
网络层 ---> IP地址
|
||||
网络层 ---> 子网/掩码/CIDR
|
||||
网络层 ---> IPv6概述
|
||||
传输层 ---> 端口
|
||||
传输层 ---> UDP
|
||||
传输层 ---> TCP概述
|
||||
传输层 ---> TCP握手挥手
|
||||
传输层 ---> TCP滑动窗口
|
||||
传输层 ---> TCP拥塞控制
|
||||
路由协议 ---> RIP
|
||||
路由协议 ---> OSPF
|
||||
路由协议 ---> 自治域与BGP概述
|
||||
|
||||
```
|
||||
|
||||
@@ -159,3 +159,38 @@ Fork 本仓库,然后在你的仓库中进行修改,修改完成后在本仓
|
||||
:::tip
|
||||
语法自查 https://mermaid.js.org
|
||||
:::
|
||||
|
||||
3. 代码分块
|
||||
|
||||
```
|
||||
::: code-group
|
||||
|
||||
```sh [npm]
|
||||
$ npm install -D vitepress
|
||||
```
|
||||
|
||||
```sh [pnpm]
|
||||
$ pnpm add -D vitepress
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
$ yarn add -D vitepress
|
||||
```
|
||||
|
||||
:::
|
||||
```
|
||||
::: code-group
|
||||
|
||||
```sh [npm]
|
||||
$ npm install -D vitepress
|
||||
```
|
||||
|
||||
```sh [pnpm]
|
||||
$ pnpm add -D vitepress
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
$ yarn add -D vitepress
|
||||
```
|
||||
|
||||
:::
|
||||
30
blog/index.md
Normal file
30
blog/index.md
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
title: Blogs
|
||||
footer: false
|
||||
editLink: false
|
||||
aside: false
|
||||
next: false
|
||||
lastUpdated: false
|
||||
sidebar: false
|
||||
---
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import PostList from '../components/PostList.vue'
|
||||
import Blogger from '../components/Blogger.vue'
|
||||
const goUrl = (url) => {
|
||||
window.open(url, "_blank")
|
||||
}
|
||||
</script>
|
||||
|
||||
# Friends <Badge type="tip" text="join us" @click="goUrl('https://github.com/NX-Official/friends-link-plus/edit/main/input/friends.json')" />
|
||||
|
||||
<Suspense><Blogger ></Blogger></Suspense>
|
||||
|
||||
---
|
||||
|
||||
# Recent Posts <Badge type="warning" text="beta" />
|
||||
|
||||
<Suspense><PostList ></PostList></Suspense>
|
||||
|
||||
<a href="https://github.com/NX-Official/friends-link-plus/edit/main/input/friends.json" target="_blank" style="font-size: 0.5rem; color: #666;">在GitHub上修改关注列表</a>
|
||||
51
components/Blogger.vue
Normal file
51
components/Blogger.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import VPTeamMembersItem from './BloggerItem.vue'
|
||||
const size = 'small'
|
||||
const props= {friends:(await (await fetch("https://ghproxy.com/https://raw.githubusercontent.com/NX-Official/friends-link-plus/main/output/friends.json")).json()).friends}
|
||||
const members = props.friends
|
||||
const classes = computed(() => [
|
||||
size ?? 'medium',
|
||||
`count-${members.length}`
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="VPTeamMembers" :class="classes">
|
||||
<div class="container">
|
||||
<div v-for="member in members" :key="member.name" class="item">
|
||||
<VPTeamMembersItem :size="size" :member="member" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPTeamMembers.small .container {
|
||||
grid-template-columns: repeat(auto-fit, minmax(224px, 1fr));
|
||||
}
|
||||
|
||||
.VPTeamMembers.small.count-1 .container { max-width: 276px; }
|
||||
.VPTeamMembers.small.count-2 .container { max-width: calc(276px * 2 + 24px); }
|
||||
.VPTeamMembers.small.count-3 .container { max-width: calc(276px * 3 + 24px * 2); }
|
||||
|
||||
.VPTeamMembers.medium .container {
|
||||
grid-template-columns: repeat(auto-fit, minmax(256px, 1fr));
|
||||
}
|
||||
|
||||
@media (min-width: 375px) {
|
||||
.VPTeamMembers.medium .container {
|
||||
grid-template-columns: repeat(auto-fit, minmax(288px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
.VPTeamMembers.medium.count-1 .container { max-width: 368px; }
|
||||
.VPTeamMembers.medium.count-2 .container { max-width: calc(368px * 2 + 24px); }
|
||||
|
||||
.container {
|
||||
display: grid;
|
||||
gap: 24px;
|
||||
margin: 0 auto;
|
||||
max-width: 1152px;
|
||||
}
|
||||
</style>
|
||||
239
components/BloggerItem.vue
Normal file
239
components/BloggerItem.vue
Normal file
@@ -0,0 +1,239 @@
|
||||
<script setup >
|
||||
|
||||
defineProps({
|
||||
size: String,
|
||||
member: Object
|
||||
})
|
||||
|
||||
const goUrl = (url) => {
|
||||
window.open(url, "_blank")
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article class="VPTeamMembersItem" :class="[size ?? 'medium']">
|
||||
<div class="profile" @click="goUrl(member.url)">
|
||||
<figure class="avatar">
|
||||
<img class="avatar-img" :src="member.avatar" :alt="member.name">
|
||||
</figure>
|
||||
<div class="data">
|
||||
<div class="author_name">
|
||||
{{ member.name }}
|
||||
</div>
|
||||
<p v-if="member.title || member.org" class="affiliation">
|
||||
<span v-if="member.title" class="title">
|
||||
{{ member.title }}
|
||||
</span>
|
||||
<span v-if="member.title && member.org" class="at">
|
||||
@
|
||||
</span>
|
||||
</p>
|
||||
<p v-if="member.description" class="desc" @click.stop>
|
||||
{{ member.description }}
|
||||
</p>
|
||||
<div v-if="member.url" class="links">
|
||||
<svg v-if="member.rss" @click="goUrl(member.rss)" xmlns="http://www.w3.org/2000/svg" width="16" height="16"
|
||||
viewBox="0 0 16 16">
|
||||
<path fill="currentColor"
|
||||
d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm1.5 2.5c5.523 0 10 4.477 10 10a1 1 0 1 1-2 0a8 8 0 0 0-8-8a1 1 0 0 1 0-2zm0 4a6 6 0 0 1 6 6a1 1 0 1 1-2 0a4 4 0 0 0-4-4a1 1 0 0 1 0-2zm.5 7a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.VPTeamMembersItem {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
border-radius: 12px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .profile {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .data {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .avatar {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .name {
|
||||
line-height: 24px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .affiliation {
|
||||
padding-top: 4px;
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .desc {
|
||||
padding-top: 12px;
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.small .links {
|
||||
margin: 0 -16px -20px;
|
||||
padding: 10px 0 0;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .profile {
|
||||
padding: 48px 32px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .data {
|
||||
padding-top: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .avatar {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .name {
|
||||
letter-spacing: 0.15px;
|
||||
line-height: 28px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .affiliation {
|
||||
padding-top: 4px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .desc {
|
||||
padding-top: 16px;
|
||||
max-width: 288px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.VPTeamMembersItem.medium .links {
|
||||
margin: 0 -16px -12px;
|
||||
padding: 16px 12px 0;
|
||||
}
|
||||
|
||||
.profile {
|
||||
flex-grow: 1;
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.data {
|
||||
text-align: center;
|
||||
/* margin: 0 auto; */
|
||||
}
|
||||
|
||||
.avatar {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
/* margin: 0 auto; */
|
||||
border-radius: 50%;
|
||||
box-shadow: var(--vp-shadow-3);
|
||||
}
|
||||
|
||||
.avatar-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.author_name {
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.affiliation {
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.org.link {
|
||||
color: var(--vp-c-text-2);
|
||||
transition: color 0.25s;
|
||||
}
|
||||
|
||||
.org.link:hover {
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.desc {
|
||||
margin: 0 auto;
|
||||
word-wrap: break-word;
|
||||
white-space: pre-line;
|
||||
overflow-wrap: break-word;
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.desc :deep(a) {
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-brand);
|
||||
text-decoration-style: dotted;
|
||||
transition: color 0.25s;
|
||||
}
|
||||
|
||||
.links {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
.links svg {
|
||||
margin: 0 .5rem;
|
||||
}
|
||||
|
||||
.links :hover {
|
||||
fill: var(--vp-c-brand-lighter)
|
||||
}
|
||||
|
||||
.sp-link {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-sponsor);
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
transition: color 0.25s, background-color 0.25s;
|
||||
}
|
||||
|
||||
.sp .sp-link.link:hover,
|
||||
.sp .sp-link.link:focus {
|
||||
outline: none;
|
||||
color: var(--vp-c-white);
|
||||
background-color: var(--vp-c-sponsor);
|
||||
}
|
||||
|
||||
.sp-icon {
|
||||
margin-right: 8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: currentColor;
|
||||
}</style>
|
||||
149
components/Pagination.vue
Normal file
149
components/Pagination.vue
Normal file
@@ -0,0 +1,149 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
const props = defineProps(['modelValue', 'pageTotal'])
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const onPrev = () => {
|
||||
if (props.modelValue <= 1) return; // 限制上一页翻页按钮的边界
|
||||
emit('update:modelValue', props.modelValue - 1)
|
||||
}
|
||||
const onNext = () => {
|
||||
if (props.modelValue >= props.pageTotal) return; // 限制下一页翻页按钮的边界
|
||||
emit('update:modelValue', props.modelValue + 1)
|
||||
}
|
||||
const setPageNum = (pageNum) => {
|
||||
if (typeof pageNum !== 'number') return; //如果pageNum不是数值类型则返回
|
||||
if (pageNum < 1) return; // 限制上一页翻页按钮的边界
|
||||
if (pageNum > props.pageTotal) return; // 限制下一页翻页按钮的边界
|
||||
emit('update:modelValue', pageNum)
|
||||
}
|
||||
|
||||
const genPageArray = (current, total, size) => {
|
||||
let arr = []
|
||||
if (total < size + 2) {
|
||||
arr = Array.from({ length: total }, (v, k) => k + 1)
|
||||
} else if (current < size - 2) {
|
||||
arr = Array.from(function* gen(i, l) { while (i < l) yield i++; }(1, size - 2 + 1))
|
||||
arr.push('...')
|
||||
arr.push(total)
|
||||
} else if (total - current < size - 2) {
|
||||
arr.push(1)
|
||||
arr.push('...')
|
||||
arr = arr.concat(Array.from(function* gen(i, l) { while (i < l) yield i++; }(total - size + 2, total + 1)))
|
||||
} else {
|
||||
arr.push(1)
|
||||
arr.push('...')
|
||||
arr = arr.concat(Array.from(function* gen(i, l) { while (i < l) yield i++; }(current - Math.floor((size - 4) / 2), current - Math.floor((size - 4) / 2) + size - 4 + 1)))
|
||||
arr.push('...')
|
||||
arr.push(total)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
const pageArrayLg = computed(() => {
|
||||
const current = props.modelValue
|
||||
const total = props.pageTotal
|
||||
return genPageArray(current, total, 17)
|
||||
})
|
||||
const pageArrayMd = computed(() => {
|
||||
const current = props.modelValue
|
||||
const total = props.pageTotal
|
||||
return genPageArray(current, total, 10)
|
||||
})
|
||||
const pageArraySm = computed(() => {
|
||||
const current = props.modelValue
|
||||
const total = props.pageTotal
|
||||
return genPageArray(current, total, 6)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="container" v-if="props.pageTotal > 1">
|
||||
<div class="paper-item" @click="onPrev" style="display: flex;"><</div>
|
||||
<div v-for="(item, index) in pageArrayLg" :key="index" @click="setPageNum(item)" class="paper-item paper-lg"
|
||||
:class="{ 'active': item == props.modelValue }">{{ item }}</div>
|
||||
<div v-for="(item, index) in pageArrayMd" :key="index" @click="setPageNum(item)" class="paper-item paper-md"
|
||||
:class="{ 'active': item == props.modelValue }">{{ item }}</div>
|
||||
<div v-for="(item, index) in pageArraySm" :key="index" @click="setPageNum(item)" class="paper-item paper-sm"
|
||||
:class="{ 'active': item == props.modelValue }">{{ item }}</div>
|
||||
<div class="paper-item" @click="onNext" style="display: flex;">></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
margin: 1rem 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
/* font-weight: 600; */
|
||||
}
|
||||
|
||||
@media screen and (min-width: 780px) {
|
||||
|
||||
.paper-lg,
|
||||
.paper-sm {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.paper-md {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1024px) {
|
||||
|
||||
.paper-md,
|
||||
.paper-sm {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.paper-lg {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 780px) {
|
||||
|
||||
.paper-lg,
|
||||
.paper-md {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.paper-sm {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.paper-item {
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
margin: 0 .5rem;
|
||||
padding: 0rem .25rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #f6f6f7;
|
||||
border-radius: .25rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.paper-item:hover {
|
||||
background-color: #0099ff0d;
|
||||
--un-text-opacity: 1;
|
||||
color: var(--vp-c-brand-lighter);
|
||||
}
|
||||
|
||||
.paper-item.active {
|
||||
background-color: #0099ff0d;
|
||||
--un-text-opacity: 1;
|
||||
color: var(--vp-c-brand-lighter);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
|
||||
.paper-item {
|
||||
background-color: #9ca3af0d;
|
||||
}
|
||||
}</style>
|
||||
222
components/PostItem.vue
Normal file
222
components/PostItem.vue
Normal file
@@ -0,0 +1,222 @@
|
||||
<template>
|
||||
<div class="blog-item" @click="openBlog(PostURL)">
|
||||
<div class="title" v-if="inMobile">{{ Title }}</div>
|
||||
<div class="info-container">
|
||||
<div class="info-part">
|
||||
<div class="title" v-if="!inMobile">{{ Title }}</div>
|
||||
<div class="description" v-if="!!Content">
|
||||
{{ Content }}
|
||||
</div>
|
||||
<div class="badge-list" v-if="!inMobile">
|
||||
<a class="split" v-if="Author" :href="withBase(AuthorURL)" @click.stop target="_blank">{{ Author }}</a>
|
||||
<span class="split">{{ showTime }}</span>
|
||||
<span class="split" v-if="tag?.length">{{ tag.join(' · ') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="cover"
|
||||
class="cover-img"
|
||||
:style="`background-image: url(${cover});`"
|
||||
></div>
|
||||
</div>
|
||||
<div class="badge-list" v-if="inMobile">
|
||||
<a class="split" v-if="Author" :href="withBase(AuthorURL)" @click.stop target="_blank">{{ Author }}</a>
|
||||
<span class="split">{{ showTime }}</span>
|
||||
<span class="split" v-if="tag?.length">{{ tag.join(' · ') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { withBase } from 'vitepress'
|
||||
import { computed } from 'vue'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
const openBlog = (url) => {
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
const { width } = useWindowSize()
|
||||
const inMobile = computed(() => width.value <= 500)
|
||||
function formatDate(d, fmt = 'yyyy-MM-dd hh:mm:ss') {
|
||||
if (!(d instanceof Date)) {
|
||||
d = new Date(d)
|
||||
}
|
||||
const o = {
|
||||
'M+': d.getMonth() + 1, // 月份
|
||||
'd+': d.getDate(), // 日
|
||||
'h+': d.getHours(), // 小时
|
||||
'm+': d.getMinutes(), // 分
|
||||
's+': d.getSeconds(), // 秒
|
||||
'q+': Math.floor((d.getMonth() + 3) / 3), // 季度
|
||||
S: d.getMilliseconds() // 毫秒
|
||||
}
|
||||
if (/(y+)/.test(fmt)) {
|
||||
fmt = fmt.replace(
|
||||
RegExp.$1,
|
||||
`${d.getFullYear()}`.substr(4 - RegExp.$1.length)
|
||||
)
|
||||
}
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const k in o) {
|
||||
if (new RegExp(`(${k})`).test(fmt))
|
||||
fmt = fmt.replace(
|
||||
RegExp.$1,
|
||||
RegExp.$1.length === 1 ? o[k] : `00${o[k]}`.substr(`${o[k]}`.length)
|
||||
)
|
||||
}
|
||||
return fmt
|
||||
}
|
||||
function formatShowDate(date) {
|
||||
const source = date ? +new Date(date) : +new Date()
|
||||
const now = +new Date()
|
||||
const diff = now - source
|
||||
const oneSeconds = 1000
|
||||
const oneMinute = oneSeconds * 60
|
||||
const oneHour = oneMinute * 60
|
||||
const oneDay = oneHour * 24
|
||||
const oneWeek = oneDay * 7
|
||||
if (diff < oneMinute) {
|
||||
return `${Math.floor(diff / oneSeconds)}秒前`
|
||||
}
|
||||
if (diff < oneHour) {
|
||||
return `${Math.floor(diff / oneMinute)}分钟前`
|
||||
}
|
||||
if (diff < oneDay) {
|
||||
return `${Math.floor(diff / oneHour)}小时前`
|
||||
}
|
||||
if (diff < oneWeek) {
|
||||
return `${Math.floor(diff / oneDay)}天前`
|
||||
}
|
||||
|
||||
return formatDate(new Date(date), 'yyyy-MM-dd')
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
Title: String,
|
||||
Date: String,
|
||||
Content: String,
|
||||
tag: {
|
||||
type: Array,
|
||||
required: false,
|
||||
},
|
||||
Author: String,
|
||||
cover: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
PostURL: String,
|
||||
AuthorURL: String
|
||||
})
|
||||
|
||||
const showTime = computed(() => {
|
||||
return formatShowDate(props.Date)
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.blog-item .pin {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
top: -4px;
|
||||
left: -4px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.blog-item:hover .pin {
|
||||
opacity: 1;
|
||||
}
|
||||
.blog-item .pin::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 120%;
|
||||
height: 30px;
|
||||
background-image: linear-gradient(
|
||||
45deg,
|
||||
var(--blog-theme-color),
|
||||
var(--blog-theme-color)
|
||||
);
|
||||
transform: rotate(-45deg) translateY(-20px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.23);
|
||||
}
|
||||
|
||||
.blog-item {
|
||||
position: relative;
|
||||
border: 1px solid rgba(82, 82, 89, .32);
|
||||
border-radius: .5rem;
|
||||
padding: 1.5rem;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: border-color .25s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
.blog-item:hover {
|
||||
border: 1px solid #09f;
|
||||
}
|
||||
|
||||
.info-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.info-part {
|
||||
flex: 1;
|
||||
}
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.description {
|
||||
color: var(--description-font-color);
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
.description-html {
|
||||
font-size: 14px;
|
||||
}
|
||||
.badge-list {
|
||||
font-size: 13px;
|
||||
color: var(--badge-font-color);
|
||||
margin-top: 8px;
|
||||
}
|
||||
.badge-list .split:not(:last-child)::after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 1px;
|
||||
height: 8px;
|
||||
margin: 0 10px;
|
||||
background-color: #4e5969;
|
||||
}
|
||||
.cover-img {
|
||||
width: 120px;
|
||||
height: 80px;
|
||||
margin-left: 24px;
|
||||
border-radius: 2px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 120px 80px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
.cover-img {
|
||||
width: 100px;
|
||||
height: 60px;
|
||||
background-size: 100px 60px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
247
components/PostList.vue
Normal file
247
components/PostList.vue
Normal file
@@ -0,0 +1,247 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import Pagination from './Pagination.vue';
|
||||
import PostItem from './PostItem.vue';
|
||||
const props= {data:(await (await fetch("https://ghproxy.com/https://raw.githubusercontent.com/NX-Official/friends-link-plus/main/output/friends.json")).json()).posts}
|
||||
const pageSize = 10
|
||||
// const Date = ref('')
|
||||
const pageTotal = ref(Math.ceil(props.data.length / pageSize))
|
||||
const pageNum = ref(1)
|
||||
// const searchText = ref('')
|
||||
// const onsearchText = ref('')
|
||||
const pluginLists = computed(() => {
|
||||
let data_ = props.data//.filter(item => item.Date == Date.value)
|
||||
// if (!!onsearchText.value) {
|
||||
// data_ = data_.filter(item => item.name.indexOf(onsearchText.value) > -1)
|
||||
// }
|
||||
pageTotal.value = Math.ceil(data_.length / pageSize)
|
||||
data_ = data_.slice((pageNum.value - 1) * pageSize, pageNum.value * pageSize)
|
||||
return data_
|
||||
})
|
||||
// const setDate = (Date_) => {
|
||||
// Date.value = Date_
|
||||
// searchText.value = ""
|
||||
// onSearch()
|
||||
// }
|
||||
// const onSearch = () => {
|
||||
// onsearchText.value = searchText.value
|
||||
// pageNum.value = 1
|
||||
// }
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- <div class="tab">
|
||||
<div opacity="80" text="sm">
|
||||
类型{{ props.data }}
|
||||
</div>
|
||||
<div class="select-list">
|
||||
<button class="select-button" @click="setDate('plugin')" :class="{ 'active': type == 'plugin' }">
|
||||
插件
|
||||
</button>
|
||||
<button class="select-button" @click="setType('adapter')" :class="{ 'active': type == 'adapter' }">
|
||||
适配器
|
||||
</button>
|
||||
<button class="select-button" @click="setType('example')" :class="{ 'active': type == 'example' }">
|
||||
样例
|
||||
</button>
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- <div class="search-bar">
|
||||
<div class="divider" style="margin-top: 1rem;" />
|
||||
<div class="search" @change="onSearch">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 32 32" class="icon">
|
||||
<path fill="currentColor"
|
||||
d="m29 27.586l-7.552-7.552a11.018 11.018 0 1 0-1.414 1.414L27.586 29ZM4 13a9 9 0 1 1 9 9a9.01 9.01 0 0 1-9-9Z" />
|
||||
</svg>
|
||||
<input data-v-48d9a5fe="" class="search-input" type="text" role="search" placeholder="Search..."
|
||||
v-model="searchText">
|
||||
</div>
|
||||
<div class="divider" style="margin-bottom: 1rem;" />
|
||||
</div> -->
|
||||
<Pagination :pageTotal="pageTotal" v-model="pageNum" style="width: 100%;padding: 1rem 0;" key="0" />
|
||||
<div class="card-list">
|
||||
<PostItem v-for="(item, index) in pluginLists" :key="index" :Title="item.Title" :Content="item.Content"
|
||||
:Date="item.Date" :Author="item.Author" :tag="item?.tag" :cover="item?.cover" :PostURL="item.PostURL" :AuthorURL="item.AuthorURL"/>
|
||||
</div>
|
||||
<Pagination :pageTotal="pageTotal" v-model="pageNum" style="width: 100%;padding: 1rem 0;" key="1" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.tab {
|
||||
grid-row-gap: .5rem;
|
||||
row-gap: .5rem;
|
||||
margin-top: 2.5rem;
|
||||
grid-template-columns: 80px auto;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.sm {
|
||||
font-size: .875rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.select-list {
|
||||
grid-gap: .5rem;
|
||||
gap: .5rem;
|
||||
flex-wrap: wrap;
|
||||
display: flex;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
.select-button {
|
||||
border-radius: .25rem;
|
||||
background-color: #9ca3af0d;
|
||||
padding: .125rem .5rem;
|
||||
font-size: .875rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.select-button:hover {
|
||||
cursor: pointer;
|
||||
background-color: #9ca3af1a;
|
||||
}
|
||||
|
||||
.select-button.active {
|
||||
background-color: #0099ff0d;
|
||||
--un-text-opacity: 1;
|
||||
color: var(--vp-c-brand-lighter);
|
||||
}
|
||||
|
||||
.divider {
|
||||
background-color: rgba(60, 60, 67, .12);
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.search {
|
||||
padding: .5rem;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-right: .5rem;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
.card-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
display: block;
|
||||
border: 1px solid rgba(82, 82, 89, .32);
|
||||
border-radius: .5rem;
|
||||
padding: 1.5rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: border-color .25s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
border: 1px solid #09f;
|
||||
}
|
||||
|
||||
.card-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
font-size: large;
|
||||
font-weight: bold;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-github {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card-github:hover {
|
||||
fill: #09f;
|
||||
}
|
||||
|
||||
.card-des {
|
||||
color: #3C3C43;
|
||||
opacity: .7;
|
||||
font-size: .875rem;
|
||||
line-height: 1.25rem;
|
||||
margin-top: .3rem;
|
||||
}
|
||||
|
||||
.card-tags {
|
||||
display: flex;
|
||||
margin-top: .5rem;
|
||||
margin-bottom: .5rem;
|
||||
font-size: .875rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.card-tag {
|
||||
margin: 0 .5rem;
|
||||
padding: 0 .5rem;
|
||||
background-color: #9ca3af2b;
|
||||
}
|
||||
|
||||
.card-tags .card-tag:first-child {
|
||||
margin-left: 0;
|
||||
/* background-color: #6e6e6e; */
|
||||
}
|
||||
|
||||
.card-details {
|
||||
margin: .8rem 0 .5rem 0;
|
||||
}
|
||||
|
||||
.card-text {
|
||||
margin-left: .5rem;
|
||||
font-size: .95rem;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
.card-detail {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: .4rem 1rem;
|
||||
background-color: #f6f6f7;
|
||||
border-radius: .5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card-button:hover {
|
||||
color: #09f;
|
||||
}
|
||||
|
||||
.card-button:hover {
|
||||
fill: #09f;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
|
||||
.card-button {
|
||||
background-color: #9ca3af0d;
|
||||
}
|
||||
|
||||
.card-des {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
78
package-lock.json
generated
78
package-lock.json
generated
@@ -11,7 +11,8 @@
|
||||
"@jupyterlab/theme-light-extension": "^4.0.3",
|
||||
"@vueuse/core": "^10.2.1",
|
||||
"markdown-it": "^13.0.1",
|
||||
"markdown-it-pangu": "^1.0.2"
|
||||
"markdown-it-pangu": "^1.0.2",
|
||||
"sitemap": "^7.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mermaid-js/mermaid-mindmap": "^9.3.0",
|
||||
@@ -1377,6 +1378,11 @@
|
||||
"integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "17.0.45",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-17.0.45.tgz",
|
||||
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.5",
|
||||
"resolved": "https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.5.tgz",
|
||||
@@ -1392,6 +1398,14 @@
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmmirror.com/@types/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/scheduler": {
|
||||
"version": "0.16.3",
|
||||
"resolved": "https://registry.npmmirror.com/@types/scheduler/-/scheduler-0.16.3.tgz",
|
||||
@@ -1742,6 +1756,11 @@
|
||||
"integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/arg/-/arg-5.0.2.tgz",
|
||||
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
|
||||
@@ -3516,6 +3535,11 @@
|
||||
"postcss": "^8.3.11"
|
||||
}
|
||||
},
|
||||
"node_modules/sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmmirror.com/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.0.tgz",
|
||||
@@ -3567,6 +3591,24 @@
|
||||
"vscode-textmate": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sitemap": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/sitemap/-/sitemap-7.1.1.tgz",
|
||||
"integrity": "sha512-mK3aFtjz4VdJN0igpIJrinf3EO8U8mxOPsTBzSsy06UtjZQJ3YY3o3Xa7zSc5nMqcMrRwlChHZ18Kxg0caiPBg==",
|
||||
"dependencies": {
|
||||
"@types/node": "^17.0.5",
|
||||
"@types/sax": "^1.2.1",
|
||||
"arg": "^5.0.0",
|
||||
"sax": "^1.2.4"
|
||||
},
|
||||
"bin": {
|
||||
"sitemap": "dist/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0",
|
||||
"npm": ">=5.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/slick": {
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmmirror.com/slick/-/slick-1.12.2.tgz",
|
||||
@@ -5568,6 +5610,11 @@
|
||||
"integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "17.0.45",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-17.0.45.tgz",
|
||||
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="
|
||||
},
|
||||
"@types/prop-types": {
|
||||
"version": "15.7.5",
|
||||
"resolved": "https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.5.tgz",
|
||||
@@ -5583,6 +5630,14 @@
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"@types/sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmmirror.com/@types/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/scheduler": {
|
||||
"version": "0.16.3",
|
||||
"resolved": "https://registry.npmmirror.com/@types/scheduler/-/scheduler-0.16.3.tgz",
|
||||
@@ -5816,6 +5871,11 @@
|
||||
"integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==",
|
||||
"dev": true
|
||||
},
|
||||
"arg": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/arg/-/arg-5.0.2.tgz",
|
||||
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
|
||||
},
|
||||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
|
||||
@@ -7293,6 +7353,11 @@
|
||||
"postcss": "^8.3.11"
|
||||
}
|
||||
},
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmmirror.com/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
},
|
||||
"scheduler": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.0.tgz",
|
||||
@@ -7335,6 +7400,17 @@
|
||||
"vscode-textmate": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"sitemap": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/sitemap/-/sitemap-7.1.1.tgz",
|
||||
"integrity": "sha512-mK3aFtjz4VdJN0igpIJrinf3EO8U8mxOPsTBzSsy06UtjZQJ3YY3o3Xa7zSc5nMqcMrRwlChHZ18Kxg0caiPBg==",
|
||||
"requires": {
|
||||
"@types/node": "^17.0.5",
|
||||
"@types/sax": "^1.2.1",
|
||||
"arg": "^5.0.0",
|
||||
"sax": "^1.2.4"
|
||||
}
|
||||
},
|
||||
"slick": {
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmmirror.com/slick/-/slick-1.12.2.tgz",
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
"@jupyterlab/theme-light-extension": "^4.0.3",
|
||||
"@vueuse/core": "^10.2.1",
|
||||
"markdown-it": "^13.0.1",
|
||||
"markdown-it-pangu": "^1.0.2"
|
||||
"markdown-it-pangu": "^1.0.2",
|
||||
"sitemap": "^7.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mermaid-js/mermaid-mindmap": "^9.3.0",
|
||||
|
||||
Reference in New Issue
Block a user