mirror of
https://github.com/ClovertaTheTrilobita/SanYeCao-blog.git
synced 2026-09-04 20:55:41 +00:00
Compare commits
18 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a506012a42 | ||
| c4a1c21f49 | |||
|
|
c9d5ed26d2 | ||
| b45eb418c0 | |||
|
|
98923bf0b8 | ||
| 2e8f53bc5b | |||
| 873fe50a44 | |||
|
|
531d0263da | ||
| f3f45ebe1e | |||
|
|
8b8ca8cbc6 | ||
| 08c4f13d54 | |||
| cbad40b5cd | |||
|
|
8f65b9dbd5 | ||
| a4d28d7ad8 | |||
|
|
d9df46084a | ||
| 8f42e7fa7b | |||
|
|
80118913ad | ||
| 0374cbe864 |
12 changed files with 609 additions and 431 deletions
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
|
@ -58,12 +58,12 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout blog-content branch
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: blog-content
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
|
|
@ -105,6 +105,15 @@ jobs:
|
|||
dist/ \
|
||||
${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_PATH}/
|
||||
|
||||
- name: Submit to IndexNow
|
||||
uses: bojieyang/indexnow-action@v3
|
||||
with:
|
||||
sitemap-location: '${{ vars.SITE_URL }}sitemap-index.xml'
|
||||
key: ${{ vars.INDEXNOW_KEY }}
|
||||
lastmod-required: false
|
||||
endpoint: api.indexnow.org
|
||||
limit: 1000
|
||||
|
||||
manual-deploy:
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -120,12 +129,12 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout blog-content branch
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: blog-content
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
|
|
@ -165,4 +174,13 @@ jobs:
|
|||
--no-group \
|
||||
-e "ssh -p ${DEPLOY_PORT}" \
|
||||
dist/ \
|
||||
${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_PATH}/
|
||||
${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_PATH}/
|
||||
|
||||
- name: Submit to IndexNow
|
||||
uses: bojieyang/indexnow-action@v3
|
||||
with:
|
||||
sitemap-location: '${{ vars.SITE_URL }}sitemap.xml'
|
||||
key: ${{ vars.INDEXNOW_KEY }}
|
||||
lastmod-required: false
|
||||
endpoint: api.indexnow.org
|
||||
limit: 1000
|
||||
|
|
@ -4,9 +4,9 @@
|
|||
✨SanYeCao Blog✨<br>
|
||||
🌊Lightweight / Fast / Beautiful🌊<br><br>
|
||||
Built With<br>
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Astro-6.0-purple">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Nodejs-24-green">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Heart-♥️-pink">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Astro-6.0-purple?style=for-the-badge">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Nodejs-24-green?style=for-the-badge">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Heart-♥️-pink?style=for-the-badge">
|
||||
<br>
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,13 @@
|
|||
✨三叶草Blog✨<br>
|
||||
🌊轻度/快速/美观🌊<br><br>
|
||||
Built With<br>
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Astro-6.0-purple">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Nodejs-24-green">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Heart-♥️-pink">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Astro-6.0-purple?style=for-the-badge">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Nodejs-24-green?style=for-the-badge">
|
||||
<img alt="Static Badge" src="https://img.shields.io/badge/Heart-♥️-pink?style=for-the-badge">
|
||||
<br>
|
||||
</p>
|
||||
|
||||
|
||||
## 😋 特性
|
||||
|
||||
<br>
|
||||
|
|
|
|||
|
|
@ -88,10 +88,29 @@ Simply copy all contents of your `.env` file into the variable value.
|
|||
|
||||
Also in <b>`Settings > Secrets and variables > Actions`</b>, add four `Repository variables`:
|
||||
|
||||
| Variable Name | Value Example |
|
||||
| ------------- | --------------------------------------------------------------------------- |
|
||||
| `DEPLOY_HOST` | Server IP address, for example `192.168.1.1` |
|
||||
| `DEPLOY_PATH` | Deployment path on the server, for example `/www/wwwroot/blog.cloverta.top` |
|
||||
| `DEPLOY_PORT` | SSH port of the server, usually `22` |
|
||||
| `DEPLOY_USER` | Login username, for example `root` |
|
||||
| **Variable Name** | **Value** |
|
||||
| ----------------- | ------------------------------------------------------------ |
|
||||
| `DEPLOY_HOST` | The IP address of your server, e.g. `192.168.1.1` |
|
||||
| `DEPLOY_PATH` | The deployment path on the server, e.g. `/www/wwwroot/blog.cloverta.top` |
|
||||
| `DEPLOY_PORT` | The SSH port of your server, usually `22` |
|
||||
| `DEPLOY_USER` | The login user, e.g. `root` |
|
||||
| `INDEXNOW_KEY` | A string used as the key submitted to IndexNow. You can directly use `888c64d8d7d9a2b605bcd5277021a414` |
|
||||
| `SITE_URL` | Your domain name, e.g. `https://blog.cloverta.top/`. Make sure to include the trailing slash |
|
||||
|
||||
#### About `INDEXNOW_KEY`
|
||||
|
||||
The repository's `Actions` workflow will automatically submit updates to [IndexNow](https://www.indexnow.org/). You need to generate a random key in the `public` directory so that IndexNow can verify that you own the website.
|
||||
|
||||
If you do not want to configure your own key, you can simply use the `Key` included in this repository:
|
||||
|
||||
```txt
|
||||
888c64d8d7d9a2b605bcd5277021a414
|
||||
```
|
||||
|
||||
If you want to generate your own key, you can use:
|
||||
|
||||
```bash
|
||||
openssl rand -hex 16
|
||||
```
|
||||
|
||||
This will generate a random string. For example, if the output is `abcdefg123`, you need to save it as `public/abcdefg123.txt`, with the contents of the file also set to `abcdefg123`.
|
||||
|
|
|
|||
|
|
@ -88,10 +88,29 @@ PUBLIC_REMARK42_SITE_ID=
|
|||
|
||||
同样,在<b>`Settings > Secrets and variables > Actions`</b>中,添加四个`Repository variables`,分别为:
|
||||
|
||||
| 密钥名 | 内容 |
|
||||
| ------------- | -------------------------------------------------------- |
|
||||
| `DEPLOY_HOST` | 服务器IP地址,如`192.168.1.1` |
|
||||
| `DEPLOY_PATH` | 在服务器上的部署路径,如`/www/wwwroot/blog.cloverta.top` |
|
||||
| `DEPLOY_PORT` | 服务器SSH端口,一般是`22` |
|
||||
| `DEPLOY_USER` | 登录用户,例如`root` |
|
||||
| 密钥名 | 内容 |
|
||||
| -------------- | ------------------------------------------------------------ |
|
||||
| `DEPLOY_HOST` | 服务器IP地址,如`192.168.1.1` |
|
||||
| `DEPLOY_PATH` | 在服务器上的部署路径,如`/www/wwwroot/blog.cloverta.top` |
|
||||
| `DEPLOY_PORT` | 服务器SSH端口,一般是`22` |
|
||||
| `DEPLOY_USER` | 登录用户,例如`root` |
|
||||
| `INDEXNOW_KEY` | 提交至IndexNow的一串ID字符,可以直接填``888c64d8d7d9a2b605bcd5277021a414`` |
|
||||
| `SITE_URL` | 你的域名,例如`https://blog.cloverta.top/`,注意结尾要带反斜杠 |
|
||||
|
||||
#### 关于`INDEXNOW_KEY`
|
||||
|
||||
仓库的`Actions`会自动向 [Index Now](https://www.indexnow.org/) 推送更新,你需要在`public`目录下生成一个随机的key向Index Now证明这个网站是你的。
|
||||
|
||||
如果懒得配可以直接用这个仓库中的`Key`
|
||||
|
||||
```txt
|
||||
888c64d8d7d9a2b605bcd5277021a414
|
||||
```
|
||||
|
||||
如果你想生成一个自己的,你可以使用
|
||||
|
||||
```bash
|
||||
openssl rand -hex 16
|
||||
```
|
||||
|
||||
生成一串随机字符,假设输出内容为`abcdefg123`,你需要将其保存到`public/abcdefg123.txt`,并且内容也为`abcdefg123`。
|
||||
|
|
|
|||
682
package-lock.json
generated
682
package-lock.json
generated
File diff suppressed because it is too large
Load diff
1
public/888c64d8d7d9a2b605bcd5277021a414.txt
Normal file
1
public/888c64d8d7d9a2b605bcd5277021a414.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
888c64d8d7d9a2b605bcd5277021a414
|
||||
|
|
@ -56,7 +56,11 @@
|
|||
#back-to-top {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
border: #a7a7a7 1.5px solid;
|
||||
/* border: #a7a7a7 1.5px solid; */
|
||||
border-top: var(--deep-blue) 1.5px dotted;
|
||||
border-left: var(--deep-blue) 1.5px dotted;
|
||||
border-right: var(--deep-blue) 2.5px solid;
|
||||
border-bottom: var(--deep-blue) 2.5px solid;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
color: #222;
|
||||
|
|
@ -118,7 +122,8 @@
|
|||
transition:
|
||||
opacity 0.2s ease,
|
||||
transform 0.27s ease,
|
||||
visibility 0.2s ease;
|
||||
visibility 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
#theme-toggle-fab.show,
|
||||
|
|
@ -130,7 +135,8 @@
|
|||
|
||||
#theme-toggle-fab.show:hover,
|
||||
#back-to-top.show:hover {
|
||||
transform: translateY(-2px);
|
||||
transform: translateY(-2.5px);
|
||||
box-shadow: 2px 3px 0px var(--deep-blue);
|
||||
}
|
||||
|
||||
:global(.dark) #theme-toggle-fab,
|
||||
|
|
|
|||
|
|
@ -5,18 +5,19 @@ import { getLangFromUrl } from "@/i18n";
|
|||
|
||||
const lang = getLangFromUrl(Astro.url);
|
||||
const links = await getCollection("friends");
|
||||
// const { links = [] } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="friendly-link-list">
|
||||
{
|
||||
links.map((link: any) => (
|
||||
<FriendlyLinkItem
|
||||
name={link.data.name}
|
||||
description={link.data.description}
|
||||
avatar={link.data.avatar}
|
||||
url={link.data.url}
|
||||
/>
|
||||
<div class="friendly-link-wrapper">
|
||||
<FriendlyLinkItem
|
||||
name={link.data.name}
|
||||
description={link.data.description}
|
||||
avatar={link.data.avatar}
|
||||
url={link.data.url}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
|
@ -25,15 +26,75 @@ const links = await getCollection("friends");
|
|||
.friendly-link-list {
|
||||
max-width: 770px;
|
||||
margin: 0 auto;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
grid-template-columns: repeat(24, minmax(0, 1fr));
|
||||
gap: 1rem;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.friendly-link-wrapper {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.friendly-link-wrapper :global(.friendly-link-card) {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (min-width: 721px) {
|
||||
/*
|
||||
* 连续波浪:
|
||||
* 第 1 行:5.5 : 6.5
|
||||
* 第 2 行:6 : 6
|
||||
* 第 3 行:6.5 : 5.5
|
||||
* 第 4 行:6 : 6
|
||||
* 然后重复
|
||||
*/
|
||||
|
||||
/* 5.5,即 11 / 24 */
|
||||
.friendly-link-wrapper:nth-child(8n + 1),
|
||||
.friendly-link-wrapper:nth-child(8n + 6) {
|
||||
grid-column: span 11;
|
||||
}
|
||||
|
||||
/* 6,即 12 / 24 */
|
||||
.friendly-link-wrapper:nth-child(8n + 3),
|
||||
.friendly-link-wrapper:nth-child(8n + 4),
|
||||
.friendly-link-wrapper:nth-child(8n + 7),
|
||||
.friendly-link-wrapper:nth-child(8n + 8) {
|
||||
grid-column: span 12;
|
||||
}
|
||||
|
||||
/* 6.5,即 13 / 24 */
|
||||
.friendly-link-wrapper:nth-child(8n + 2),
|
||||
.friendly-link-wrapper:nth-child(8n + 5) {
|
||||
grid-column: span 13;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.friendly-link-list {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.friendly-link-wrapper {
|
||||
justify-self: left;
|
||||
}
|
||||
|
||||
.friendly-link-wrapper:nth-child(4n + 1) {
|
||||
width: 84%;
|
||||
}
|
||||
|
||||
/* 第 2、4、6、8……张 */
|
||||
.friendly-link-wrapper:nth-child(4n + 2),
|
||||
.friendly-link-wrapper:nth-child(4n) {
|
||||
width: 92%;
|
||||
}
|
||||
|
||||
/* 第 3、7、11……张 */
|
||||
.friendly-link-wrapper:nth-child(4n + 3) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -45,11 +45,24 @@ const {
|
|||
<script is:inline>
|
||||
function addCodeCopyButtons() {
|
||||
document.querySelectorAll("pre").forEach((pre) => {
|
||||
if (pre.querySelector(":scope > .code-copy-button")) return;
|
||||
|
||||
const code = pre.querySelector("code");
|
||||
if (!code) return;
|
||||
|
||||
/* 已经处理过则跳过 */
|
||||
if (
|
||||
pre.parentElement?.classList.contains("code-block-wrapper")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 创建外层容器 */
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.className = "code-block-wrapper";
|
||||
|
||||
pre.parentNode?.insertBefore(wrapper, pre);
|
||||
wrapper.appendChild(pre);
|
||||
|
||||
/* 创建复制按钮 */
|
||||
const button = document.createElement("button");
|
||||
button.className = "code-copy-button";
|
||||
button.type = "button";
|
||||
|
|
@ -63,6 +76,7 @@ const {
|
|||
icon.setAttribute("aria-hidden", "true");
|
||||
|
||||
button.appendChild(icon);
|
||||
wrapper.appendChild(button);
|
||||
|
||||
button.addEventListener("click", async () => {
|
||||
const text = code.textContent ?? "";
|
||||
|
|
@ -74,6 +88,7 @@ const {
|
|||
textarea.value = text;
|
||||
textarea.style.position = "fixed";
|
||||
textarea.style.opacity = "0";
|
||||
textarea.style.pointerEvents = "none";
|
||||
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
|
|
@ -93,8 +108,6 @@ const {
|
|||
button.classList.remove("copied");
|
||||
}, 1500);
|
||||
});
|
||||
|
||||
pre.appendChild(button);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -193,6 +193,10 @@ const t = getTranslations(lang);
|
|||
justify-content: center;
|
||||
text-decoration: none;
|
||||
border: #536493 1.5px solid;
|
||||
border-top: #536493 2.5px dotted;
|
||||
border-left: #536493 2.5px dotted;
|
||||
border-right: #536493 2.5px solid;
|
||||
border-bottom: #536493 2.5px solid;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
color: #222;
|
||||
/* box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16); */
|
||||
|
|
@ -217,7 +221,8 @@ const t = getTranslations(lang);
|
|||
}
|
||||
|
||||
.back-button.show:hover {
|
||||
transform: translateY(-2px);
|
||||
transform: translateY(-2.5px);
|
||||
box-shadow: 2px 3px 0px var(--deep-blue);
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
|
|
@ -369,87 +374,86 @@ const t = getTranslations(lang);
|
|||
}
|
||||
}
|
||||
|
||||
details {
|
||||
margin: 1.5rem 0;
|
||||
overflow: hidden;
|
||||
border-top: 2px solid #1e3a5f;
|
||||
border-radius: 0 0 0.5rem 0.5rem;
|
||||
background: rgba(128, 128, 128, 0.14);
|
||||
}
|
||||
|
||||
details {
|
||||
margin: 1.5rem 0;
|
||||
overflow: hidden;
|
||||
border-top: 2px solid #1e3a5f;
|
||||
border-radius: 0 0 0.5rem 0.5rem;
|
||||
background: rgba(128, 128, 128, 0.14);
|
||||
}
|
||||
details summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.8rem 0.9rem;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
user-select: none;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
details summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.8rem 0.9rem;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
user-select: none;
|
||||
list-style: none;
|
||||
}
|
||||
details summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
details summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
details summary::before {
|
||||
content: "›";
|
||||
display: inline-block;
|
||||
font-size: 1.25rem;
|
||||
line-height: 1;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
details summary::before {
|
||||
content: "›";
|
||||
display: inline-block;
|
||||
font-size: 1.25rem;
|
||||
line-height: 1;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
details[open] summary::before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
details[open] summary::before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
/* 展开内容 */
|
||||
details > :not(summary) {
|
||||
box-sizing: border-box;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
/* 展开内容 */
|
||||
details > :not(summary) {
|
||||
box-sizing: border-box;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
/* 为列表序号预留空间 */
|
||||
details > ol,
|
||||
details > ul {
|
||||
padding: 0.6rem 1rem 1rem 3rem;
|
||||
}
|
||||
|
||||
/* 为列表序号预留空间 */
|
||||
details > ol,
|
||||
details > ul {
|
||||
padding: 0.6rem 1rem 1rem 3rem;
|
||||
}
|
||||
details li {
|
||||
margin: 0.8rem 0;
|
||||
}
|
||||
|
||||
details li {
|
||||
margin: 0.8rem 0;
|
||||
}
|
||||
blockquote {
|
||||
margin: 1.25rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
border-left: 4px solid var(--deep-red);
|
||||
background: rgba(128, 128, 128, 0.1);
|
||||
border-radius: 0 0.4rem 0.4rem 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 1.25rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
border-left: 4px solid var(--deep-red);
|
||||
background: rgba(128, 128, 128, 0.1);
|
||||
border-radius: 0 0.4rem 0.4rem 0;
|
||||
}
|
||||
blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
blockquote p + p {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
blockquote p + p {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
/* 块级公式:超出屏幕时只滚动公式,不撑宽整篇文章 */
|
||||
.katex-display {
|
||||
/* 块级公式:超出屏幕时只滚动公式,不撑宽整篇文章 */
|
||||
.katex-display {
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
padding: 0.25rem 0;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
}
|
||||
|
||||
/* 避免 KaTeX 内部元素强行把父容器撑宽 */
|
||||
.katex-display > .katex {
|
||||
/* 避免 KaTeX 内部元素强行把父容器撑宽 */
|
||||
.katex-display > .katex {
|
||||
min-width: max-content;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
pre {
|
||||
.code-block-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.code-block-wrapper pre {
|
||||
padding: 1rem;
|
||||
border-radius: 3px;
|
||||
overflow-x: auto;
|
||||
|
|
|
|||
Loading…
Reference in a new issue