mirror of
https://github.com/RhenCloud/Cloud-Home.git
synced 2026-06-11 00:24:56 +08:00
Compare commits
6 Commits
8506dab51e
...
6c7a3539f3
| Author | SHA1 | Date | |
|---|---|---|---|
| 6c7a3539f3 | |||
| e335ffe230 | |||
| 88da4ca96e | |||
| cb8c9c6764 | |||
| 414259cec6 | |||
| 1291910fb2 |
32
.github/workflows/lint-format.yml
vendored
32
.github/workflows/lint-format.yml
vendored
@@ -15,24 +15,18 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4
|
uses: oven-sh/setup-bun@v2
|
||||||
with:
|
with:
|
||||||
node-version: "24"
|
bun-version: latest
|
||||||
cache: "npm"
|
|
||||||
|
|
||||||
- name: Enable corepack and install npm
|
|
||||||
run: |
|
|
||||||
corepack enable
|
|
||||||
corepack prepare npm@latest --activate
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm install --frozen-lockfile
|
run: bun install
|
||||||
|
|
||||||
- name: Run ESLint
|
- name: Run ESLint
|
||||||
run: npm lint
|
run: bun run lint
|
||||||
|
|
||||||
- name: Run Prettier check
|
- name: Run Prettier check
|
||||||
run: npm format:check
|
run: bun run format:check
|
||||||
|
|
||||||
format:
|
format:
|
||||||
name: Auto-format (eslint --fix)
|
name: Auto-format (eslint --fix)
|
||||||
@@ -46,24 +40,18 @@ jobs:
|
|||||||
persist-credentials: true
|
persist-credentials: true
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4
|
uses: oven-sh/setup-bun@v2
|
||||||
with:
|
with:
|
||||||
node-version: "24"
|
bun-version: latest
|
||||||
cache: "npm"
|
|
||||||
|
|
||||||
- name: Enable corepack and install npm
|
|
||||||
run: |
|
|
||||||
corepack enable
|
|
||||||
corepack prepare npm@latest --activate
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm install --frozen-lockfile
|
run: bun install
|
||||||
|
|
||||||
- name: Run Prettier --write
|
- name: Run Prettier --write
|
||||||
run: npm format
|
run: bun run format
|
||||||
|
|
||||||
- name: Run ESLint --fix
|
- name: Run ESLint --fix
|
||||||
run: npm lint:fix
|
run: bun run lint:fix
|
||||||
|
|
||||||
- name: Commit & push fixes
|
- name: Commit & push fixes
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
96
AGENTS.md
Normal file
96
AGENTS.md
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
本文件用于指导 AI Coding Agents 在本仓库内高效、安全、一致地工作。优先遵循现有实现与仓库约定;除非必要,不要引入新架构。
|
||||||
|
|
||||||
|
## 项目概览
|
||||||
|
|
||||||
|
- 这是一个 Nuxt.js + TypeScript + Tailwind CSS + Bun 项目。
|
||||||
|
- 默认使用 Bun 作为包管理器与运行时。
|
||||||
|
- 优先采用 SSR 与 Nuxt conventions。
|
||||||
|
- 优先使用 Composition API。
|
||||||
|
- TypeScript 必须保持 strict mode。
|
||||||
|
|
||||||
|
|
||||||
|
## 环境与工具链
|
||||||
|
|
||||||
|
- 优先通过 `nix develop` 或 `nix shell` 补全缺失工具,不要假设系统已全局安装 node、npm、pnpm。
|
||||||
|
- 如果缺少开发工具,优先补充 `flake.nix`,或补充 `shell.nix` / devShell。
|
||||||
|
- 默认使用 Bun:
|
||||||
|
- 安装依赖:`bun install`
|
||||||
|
- 运行脚本:`bun run <script>`
|
||||||
|
- 避免使用 npm、pnpm、yarn
|
||||||
|
- 优先保证开发环境可复现,避免依赖本机隐式状态。
|
||||||
|
- 常用命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix develop
|
||||||
|
bun install
|
||||||
|
bun run dev
|
||||||
|
bun run build
|
||||||
|
bun run lint
|
||||||
|
```
|
||||||
|
|
||||||
|
## DevOps
|
||||||
|
|
||||||
|
- Docker 已支持,构建入口见 [Dockerfile](Dockerfile),本地联动服务见 [docker-compose.yml](docker-compose.yml)。默认使用 `docker compose up --build` 启动整套环境。
|
||||||
|
- Nix flake 已支持,开发环境以 [flake.nix](flake.nix) 为准;优先通过 `nix develop` 进入可复现 shell,再执行 Bun 命令。
|
||||||
|
- GitHub Actions 已配置 CI,检查顺序与本地一致:安装依赖、`bun run lint`、`bun run typecheck`、`bun run build`。
|
||||||
|
- 自动格式化使用 `bun run format`,修改代码后优先执行,保证 Prettier 与 Tailwind 排版一致。
|
||||||
|
- 自动 lint 与自动 typecheck 依赖仓库脚本和 CI;本地修改后优先跑 `bun run lint` 和 `bun run typecheck`,避免把问题留到流水线。
|
||||||
|
|
||||||
|
## TypeScript 规范
|
||||||
|
|
||||||
|
- 参考规范:[TypeScript 风格指南](https://siiway.org/zh/dev/ts-style.html)
|
||||||
|
- 默认使用 `const`,禁止 `var`。
|
||||||
|
- 避免 `any`;必要时先收窄类型,再使用显式断言。
|
||||||
|
- 优先使用 `type`,仅在需要扩展或声明合并时使用 `interface`。
|
||||||
|
- 不要使用 `enum`,优先使用 literal union。
|
||||||
|
- 避免大型类,优先函数式与组合式设计。
|
||||||
|
- 公共 API 必须显式声明返回类型。
|
||||||
|
- 文件名使用 kebab-case。
|
||||||
|
- composables 使用 `useXxx` 命名。
|
||||||
|
- Vue 组件使用 PascalCase 命名。
|
||||||
|
- 避免默认导出,Nuxt 特殊约定除外。
|
||||||
|
- 保持 import 顺序稳定,依赖 ESLint + Prettier 自动格式化。
|
||||||
|
|
||||||
|
## Nuxt / Vue 约定
|
||||||
|
|
||||||
|
- composables 放在 `/composables`。
|
||||||
|
- server routes 放在 `/server/api`。
|
||||||
|
- shared types 放在 `/types`。
|
||||||
|
- 通用工具函数放在 `/utils`。
|
||||||
|
- 页面逻辑保持轻量,复杂业务下沉到 composables / server / utils。
|
||||||
|
- 避免在 components 中写复杂业务逻辑。
|
||||||
|
- 优先使用 `useFetch`、`useAsyncData` 与 Nuxt auto imports。
|
||||||
|
- Tailwind class 要保持可读性,避免过长 class chain。
|
||||||
|
- 优先使用语义化 wrapper components,而不是把样式逻辑散落在页面里。
|
||||||
|
|
||||||
|
## AI Agent 行为规则
|
||||||
|
|
||||||
|
- 修改代码前先阅读现有实现与相邻调用点。
|
||||||
|
- 修改前优先搜索已有 utility / composable / server helper,避免重复造轮子。
|
||||||
|
- 优先遵循现有代码风格,不要强行引入新的架构风格。
|
||||||
|
- 最小化修改范围,优先做局部且可验证的改动。
|
||||||
|
- 不要随意增加依赖;新增依赖必须说明原因。
|
||||||
|
- 不要破坏 SSR、hydration 或 Nuxt 自动导入约定。
|
||||||
|
- 不要绕过 TypeScript 类型系统。
|
||||||
|
- 不要通过关闭 lint、typecheck 或 build 来“修复”问题。
|
||||||
|
|
||||||
|
## 测试与质量
|
||||||
|
|
||||||
|
- 所有改动应尽量通过 typecheck、lint、build。
|
||||||
|
- 修改后优先运行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run lint
|
||||||
|
bun run typecheck
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
- 如果某个检查失败,先修复根因,再继续扩大修改。
|
||||||
|
|
||||||
|
## 维护原则
|
||||||
|
|
||||||
|
- 保持本文件短小、可执行、面向 AI Agent。
|
||||||
|
- 只记录仓库中不容易通过扫描直接发现、但会影响正确性的约定。
|
||||||
|
- 细节说明优先链接到其他文档,不在此处重复展开。
|
||||||
@@ -1,44 +1,47 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<header
|
||||||
class="my-4 mx-auto max-w-3xl w-full px-4 py-3 grid grid-cols-[auto_1fr_auto] gap-3 items-center"
|
class="page-switcher fixed left-1/2 z-50 mx-auto grid w-fit max-w-[calc(100%-2rem)] -translate-x-1/2 grid-cols-1 items-center justify-items-center rounded-2xl border border-white/10 bg-linear-to-br from-white/8 to-white/3 px-4 py-2 shadow-md-dark backdrop-blur-xl transition-[top,box-shadow,transform,background-color] duration-200 ease-out"
|
||||||
|
:style="headerStyle"
|
||||||
>
|
>
|
||||||
<button
|
<nav class="flex flex-nowrap gap-2 justify-center" aria-label="主导航">
|
||||||
:disabled="currentIndex <= 0"
|
|
||||||
class="bg-white/10 text-text-primary border border-white/15 rounded-2xl px-3 py-2 cursor-pointer transition-all duration-200 hover:bg-primary/20 hover:border-primary/40 hover:text-primary disabled:opacity-50 disabled:cursor-not-allowed"
|
|
||||||
@click="goPrev"
|
|
||||||
>
|
|
||||||
上一页
|
|
||||||
</button>
|
|
||||||
<div class="flex gap-2 flex-wrap justify-center">
|
|
||||||
<button
|
<button
|
||||||
v-for="item in pages"
|
v-for="item in pages"
|
||||||
:key="item.name"
|
:key="item.name"
|
||||||
:class="{
|
:class="{
|
||||||
'bg-primary/30 border-primary/60 text-primary shadow-lg shadow-primary/25':
|
'border-primary/40 bg-primary/10 text-primary shadow-lg shadow-primary/15':
|
||||||
item.name === route.name,
|
item.name === route.name,
|
||||||
}"
|
}"
|
||||||
class="px-2.5 py-2 bg-white/10 text-text-primary border border-white/15 rounded-2xl cursor-pointer transition-all duration-200 hover:bg-white/15 hover:border-primary/40"
|
class="rounded-2xl border border-white/10 bg-linear-to-br from-white/5 to-white/2 px-2.5 py-1.5 cursor-pointer text-text-primary shadow-md-dark transition-all duration-200 hover:-translate-y-0.5 hover:border-primary/40 hover:shadow-lg-dark hover:bg-linear-to-br hover:from-primary/6"
|
||||||
@click="router.push({ name: item.name })"
|
@click="router.push({ name: item.name })"
|
||||||
>
|
>
|
||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</nav>
|
||||||
<button
|
</header>
|
||||||
:disabled="currentIndex >= pages.length - 1"
|
|
||||||
class="bg-white/10 text-text-primary border border-white/15 rounded-2xl px-3 py-2 cursor-pointer transition-all duration-200 hover:bg-primary/20 hover:border-primary/40 hover:text-primary disabled:opacity-50 disabled:cursor-not-allowed"
|
|
||||||
@click="goNext"
|
|
||||||
>
|
|
||||||
下一页
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from "vue";
|
import { computed, onBeforeUnmount, onMounted, ref } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const scrollY = ref(0);
|
||||||
|
|
||||||
|
const updateScrollY = () => {
|
||||||
|
scrollY.value = window.scrollY || window.pageYOffset || 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
updateScrollY();
|
||||||
|
window.addEventListener("scroll", updateScrollY, { passive: true });
|
||||||
|
window.addEventListener("resize", updateScrollY, { passive: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener("scroll", updateScrollY);
|
||||||
|
window.removeEventListener("resize", updateScrollY);
|
||||||
|
});
|
||||||
|
|
||||||
const pages = [
|
const pages = [
|
||||||
{ name: "index", label: "首页" },
|
{ name: "index", label: "首页" },
|
||||||
@@ -49,17 +52,15 @@ const pages = [
|
|||||||
// { name: "comments", label: "留言" },
|
// { name: "comments", label: "留言" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const currentIndex = computed(() => pages.findIndex((item) => item.name === route.name));
|
const headerStyle = computed(() => {
|
||||||
|
const maxOffset = 16;
|
||||||
|
const minOffset = 4;
|
||||||
|
const settleDistance = 320;
|
||||||
|
const progress = Math.min(scrollY.value / settleDistance, 1);
|
||||||
|
const top = maxOffset - (maxOffset - minOffset) * progress;
|
||||||
|
|
||||||
const goPrev = () => {
|
return {
|
||||||
if (currentIndex.value > 0) {
|
top: `${top}px`,
|
||||||
router.push({ name: pages[currentIndex.value - 1].name });
|
};
|
||||||
}
|
});
|
||||||
};
|
|
||||||
|
|
||||||
const goNext = () => {
|
|
||||||
if (currentIndex.value < pages.length - 1) {
|
|
||||||
router.push({ name: pages[currentIndex.value + 1].name });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
<template v-for="link in links" :key="link.url">
|
<template v-for="link in links" :key="link.url">
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
:to="link.url"
|
:to="link.url"
|
||||||
class="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-white/10 backdrop-blur-sm border border-white/10 text-text-primary text-sm font-medium transition-all duration-200 hover:bg-primary/20 hover:border-primary/40 hover:text-primary hover:-translate-y-1"
|
class="social-link-chip inline-flex items-center gap-2 px-3 py-1.5 rounded-full text-sm font-medium transition-all duration-200 hover:-translate-y-1"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
v-if="iconFor(link)"
|
v-if="iconFor(link)"
|
||||||
@@ -44,6 +44,41 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="pgpInfo.publicKey"
|
||||||
|
class="mt-4 rounded-2xl border border-white/20 bg-white/10 p-4 backdrop-blur-xl"
|
||||||
|
>
|
||||||
|
<div class="flex flex-wrap items-start justify-between gap-3">
|
||||||
|
<div class="min-w-0">
|
||||||
|
<p class="m-0 text-sm font-semibold text-white">PGP 公钥</p>
|
||||||
|
<p class="m-0 mt-1 break-all text-xs text-text-muted">
|
||||||
|
指纹:{{ formatFingerprint(pgpInfo.fingerprint) || "未提供指纹" }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<a
|
||||||
|
v-if="pgpInfo.keyUrl"
|
||||||
|
:href="pgpInfo.keyUrl"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
class="social-link-chip inline-flex items-center gap-2 rounded-full px-3 py-1.5 text-xs font-medium"
|
||||||
|
>
|
||||||
|
查看公钥
|
||||||
|
</a>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="social-link-chip inline-flex items-center gap-2 rounded-full px-3 py-1.5 text-xs font-medium"
|
||||||
|
@click="copyPgpPublicKey"
|
||||||
|
>
|
||||||
|
复制公钥
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p v-if="copyFeedback" class="m-0 mt-2 text-xs text-text-muted">{{ copyFeedback }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- <button
|
<!-- <button
|
||||||
v-show="canScrollRight"
|
v-show="canScrollRight"
|
||||||
aria-label="向右滚动"
|
aria-label="向右滚动"
|
||||||
@@ -72,7 +107,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onBeforeUnmount } from "vue";
|
import { computed, ref, onMounted, onBeforeUnmount } from "vue";
|
||||||
|
import siteConfig from "~/config/siteConfig";
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
links: {
|
links: {
|
||||||
@@ -83,6 +119,16 @@ defineProps({
|
|||||||
|
|
||||||
const container = ref(null);
|
const container = ref(null);
|
||||||
const showOnlyIcons = ref(false);
|
const showOnlyIcons = ref(false);
|
||||||
|
const copyFeedback = ref("");
|
||||||
|
|
||||||
|
const pgpInfo = computed(() => {
|
||||||
|
const pgp = siteConfig.profile?.pgp || {};
|
||||||
|
return {
|
||||||
|
fingerprint: pgp.fingerprint || "",
|
||||||
|
publicKey: pgp.publicKey || "",
|
||||||
|
keyUrl: pgp.keyUrl || "",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const iconMap = {
|
const iconMap = {
|
||||||
bilibili: "simple-icons:bilibili",
|
bilibili: "simple-icons:bilibili",
|
||||||
@@ -114,6 +160,20 @@ const iconFor = (link) => {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const formatFingerprint = (fingerprint) => {
|
||||||
|
if (!fingerprint) return "";
|
||||||
|
return fingerprint.match(/.{1,4}/g)?.join(" ") || fingerprint;
|
||||||
|
};
|
||||||
|
|
||||||
|
async function copyPgpPublicKey() {
|
||||||
|
if (!pgpInfo.value.publicKey || !navigator.clipboard) return;
|
||||||
|
await navigator.clipboard.writeText(pgpInfo.value.publicKey);
|
||||||
|
copyFeedback.value = "已复制公钥";
|
||||||
|
window.setTimeout(() => {
|
||||||
|
copyFeedback.value = "";
|
||||||
|
}, 1600);
|
||||||
|
}
|
||||||
|
|
||||||
function updateScrollButtons() {
|
function updateScrollButtons() {
|
||||||
const el = container.value;
|
const el = container.value;
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
@@ -144,6 +204,26 @@ onBeforeUnmount(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.social-link-chip {
|
||||||
|
background: linear-gradient(135deg, rgba(255, 255, 255, 0.22), rgba(124, 193, 255, 0.12));
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
color: rgba(250, 253, 255, 0.98);
|
||||||
|
text-shadow: 0 1px 2px rgba(15, 22, 41, 0.4);
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.28),
|
||||||
|
0 10px 28px rgba(8, 14, 28, 0.16);
|
||||||
|
backdrop-filter: blur(12px) saturate(160%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link-chip:hover {
|
||||||
|
background: linear-gradient(135deg, rgba(255, 255, 255, 0.3), rgba(124, 193, 255, 0.2));
|
||||||
|
border-color: rgba(124, 193, 255, 0.58);
|
||||||
|
color: #f6fbff;
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.35),
|
||||||
|
0 14px 30px rgba(124, 193, 255, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
.social-links-scroll {
|
.social-links-scroll {
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
-ms-overflow-style: none; /* IE and Edge */
|
||||||
scrollbar-width: none; /* Firefox */
|
scrollbar-width: none; /* Firefox */
|
||||||
|
|||||||
@@ -5,6 +5,33 @@ const siteConfig = {
|
|||||||
avatar: "/avatar-1.webp", // public/avatar.webp
|
avatar: "/avatar-1.webp", // public/avatar.webp
|
||||||
bio: "趁世界还未重启之前 约一次爱恋",
|
bio: "趁世界还未重启之前 约一次爱恋",
|
||||||
email: "i@rhen.cloud",
|
email: "i@rhen.cloud",
|
||||||
|
pgp: {
|
||||||
|
fingerprint: "4A0D0DE4379AEB4562ED5EC0A574A617378C4E0B",
|
||||||
|
publicKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
mDMEaaqxVRYJKwYBBAHaRw8BAQdAGfMGv3ZrFvyC3aB69rrCe7hj19VXqfn+fxQ4
|
||||||
|
R1xxsK+0GFJoZW5DbG91ZCA8aUByaGVuLmNsb3VkPoiyBBMWCgBaGxSAAAAAAAQA
|
||||||
|
Dm1hbnUyLDIuNSsxLjExLDIsMQIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIX
|
||||||
|
gBYhBEoNDeQ3mutFYu1ewKV0phc3jE4LBQJpuBlSAhkBAAoJEKV0phc3jE4L3cYB
|
||||||
|
AOVr0OASfXF7fv7hE9u82CYtCB3o70bc+hF0cvqdHn+RAQCfEgw5iQo0GA2BfhPK
|
||||||
|
U1VKL71dm/QxGJ12n9Q2SsWwDrQgUmhlbkNsb3VkIDxyaGVuY2xvdWRAc2lpd2F5
|
||||||
|
Lm9yZz6IrwQTFgoAVxYhBEoNDeQ3mutFYu1ewKV0phc3jE4LBQJpuBjzGxSAAAAA
|
||||||
|
AAQADm1hbnUyLDIuNSsxLjExLDIsMQIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIe
|
||||||
|
BwIXgAAKCRCldKYXN4xOC+OtAP9UIlQwEBDKeOVvBTknykmrN2XfPH+9BBd5YUC+
|
||||||
|
l44rAQEAmjzieQWLCwz8D9Ythya+6rRE0eXa6Kd0cL8Stwe9wwq4MwRpqrFVFgkr
|
||||||
|
BgEEAdpHDwEBB0D7rYWSdRC5vUBQw1FgX83X0WZOSRPYhzi1o1PkEE0GxIiUBBgW
|
||||||
|
CgA8FiEESg0N5Dea60Vi7V7ApXSmFzeMTgsFAmmqsVUbFIAAAAAABAAObWFudTIs
|
||||||
|
Mi41KzEuMTEsMiwxAhsgAAoJEKV0phc3jE4LKp4BAIsaNWogAP0TxrRseS3zk+BE
|
||||||
|
/K5sdmIt4nJNYVC91keVAQC2PFhdfbVRIbisJ7k6atOPrjKSeUMKHhYbQWky0ptB
|
||||||
|
C7g4BGmqsVUSCisGAQQBl1UBBQEBB0CQAYihK+4Qeq0jMXhko5JFhztIcGM3muKb
|
||||||
|
tjY4KCPQYgMBCAeIlAQYFgoAPBYhBEoNDeQ3mutFYu1ewKV0phc3jE4LBQJpqrFV
|
||||||
|
GxSAAAAAAAQADm1hbnUyLDIuNSsxLjExLDIsMQIbDAAKCRCldKYXN4xOC1QLAQCx
|
||||||
|
e7ogTB50YVDIMF7A8iQMm9Kn29vjsLftSBsTDzUB4gD+NeGyST5c81RIbNf0eWUk
|
||||||
|
En5WfP0rfILKDkvm8jD0/AU=
|
||||||
|
=7KnD
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----`,
|
||||||
|
keyUrl: "/rhencloud.asc",
|
||||||
|
},
|
||||||
birthday: "2010-03-28",
|
birthday: "2010-03-28",
|
||||||
// gender: "女",
|
// gender: "女",
|
||||||
pronouns: "她",
|
pronouns: "她",
|
||||||
@@ -18,7 +45,7 @@ const siteConfig = {
|
|||||||
{ name: "Bilibili", url: "https://space.bilibili.com/1502883335" },
|
{ name: "Bilibili", url: "https://space.bilibili.com/1502883335" },
|
||||||
{ name: "Blog", url: "https://blog.rhen.cloud" },
|
{ name: "Blog", url: "https://blog.rhen.cloud" },
|
||||||
{ name: "Telegram", url: "https://t.me/RhenCloud" },
|
{ name: "Telegram", url: "https://t.me/RhenCloud" },
|
||||||
{ name: "Twitter", url: "https://x.com/RhenCloud75" },
|
// { name: "Twitter", url: "https://x.com/RhenCloud75" },
|
||||||
],
|
],
|
||||||
|
|
||||||
github: {
|
github: {
|
||||||
@@ -172,6 +199,18 @@ const siteConfig = {
|
|||||||
url: "https://blog.sakura.ink",
|
url: "https://blog.sakura.ink",
|
||||||
avatar: "https://q2.qlogo.cn/headimg_dl?dst_uin=2731443459&spec=5",
|
avatar: "https://q2.qlogo.cn/headimg_dl?dst_uin=2731443459&spec=5",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "雾小蒜の小窝",
|
||||||
|
desc: "共寻繁星,逐光前行!",
|
||||||
|
url: "https://ciallovo.top",
|
||||||
|
avatar: "https://ciallovo.top/assets/pic/icon.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "香草的日记",
|
||||||
|
desc: "与你的日常,便是奇迹!分享技术与日常。",
|
||||||
|
url: "https://www.xcnahida.cn",
|
||||||
|
avatar: "https://www.xcnahida.cn/favicon.ico",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
comments: {
|
comments: {
|
||||||
|
|||||||
@@ -82,6 +82,34 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
padding-top: 5.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.content-stack {
|
||||||
|
padding-top: 8.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-switcher {
|
||||||
|
width: calc(100% - 1rem);
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.5rem 0.65rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-switcher nav {
|
||||||
|
min-width: 0;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
overflow-x: auto;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-switcher nav::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-body {
|
.app-body {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify-json/fa6-brands": "^1.2.6",
|
"@iconify-json/fa6-brands": "^1.2.6",
|
||||||
|
"@iconify-json/fa6-solid": "^1.2.4",
|
||||||
"@iconify-json/simple-icons": "^1.2.66",
|
"@iconify-json/simple-icons": "^1.2.66",
|
||||||
"@nuxt/eslint": "1.12.1",
|
"@nuxt/eslint": "1.12.1",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
|
|||||||
4998
pnpm-lock.yaml
generated
4998
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,9 @@
|
|||||||
|
allowBuilds:
|
||||||
|
'@parcel/watcher': true
|
||||||
|
core-js: true
|
||||||
|
esbuild: true
|
||||||
|
sharp: true
|
||||||
|
unrs-resolver: true
|
||||||
|
vue-demi: true
|
||||||
ignoredBuiltDependencies:
|
ignoredBuiltDependencies:
|
||||||
- core-js
|
- core-js
|
||||||
|
|||||||
23
public/rhencloud.asc
Normal file
23
public/rhencloud.asc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
mDMEaaqxVRYJKwYBBAHaRw8BAQdAGfMGv3ZrFvyC3aB69rrCe7hj19VXqfn+fxQ4
|
||||||
|
R1xxsK+0GFJoZW5DbG91ZCA8aUByaGVuLmNsb3VkPoiyBBMWCgBaGxSAAAAAAAQA
|
||||||
|
Dm1hbnUyLDIuNSsxLjExLDIsMQIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIX
|
||||||
|
gBYhBEoNDeQ3mutFYu1ewKV0phc3jE4LBQJpuBlSAhkBAAoJEKV0phc3jE4L3cYB
|
||||||
|
AOVr0OASfXF7fv7hE9u82CYtCB3o70bc+hF0cvqdHn+RAQCfEgw5iQo0GA2BfhPK
|
||||||
|
U1VKL71dm/QxGJ12n9Q2SsWwDrQgUmhlbkNsb3VkIDxyaGVuY2xvdWRAc2lpd2F5
|
||||||
|
Lm9yZz6IrwQTFgoAVxYhBEoNDeQ3mutFYu1ewKV0phc3jE4LBQJpuBjzGxSAAAAA
|
||||||
|
AAQADm1hbnUyLDIuNSsxLjExLDIsMQIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIe
|
||||||
|
BwIXgAAKCRCldKYXN4xOC+OtAP9UIlQwEBDKeOVvBTknykmrN2XfPH+9BBd5YUC+
|
||||||
|
l44rAQEAmjzieQWLCwz8D9Ythya+6rRE0eXa6Kd0cL8Stwe9wwq4MwRpqrFVFgkr
|
||||||
|
BgEEAdpHDwEBB0D7rYWSdRC5vUBQw1FgX83X0WZOSRPYhzi1o1PkEE0GxIiUBBgW
|
||||||
|
CgA8FiEESg0N5Dea60Vi7V7ApXSmFzeMTgsFAmmqsVUbFIAAAAAABAAObWFudTIs
|
||||||
|
Mi41KzEuMTEsMiwxAhsgAAoJEKV0phc3jE4LKp4BAIsaNWogAP0TxrRseS3zk+BE
|
||||||
|
/K5sdmIt4nJNYVC91keVAQC2PFhdfbVRIbisJ7k6atOPrjKSeUMKHhYbQWky0ptB
|
||||||
|
C7g4BGmqsVUSCisGAQQBl1UBBQEBB0CQAYihK+4Qeq0jMXhko5JFhztIcGM3muKb
|
||||||
|
tjY4KCPQYgMBCAeIlAQYFgoAPBYhBEoNDeQ3mutFYu1ewKV0phc3jE4LBQJpqrFV
|
||||||
|
GxSAAAAAAAQADm1hbnUyLDIuNSsxLjExLDIsMQIbDAAKCRCldKYXN4xOC1QLAQCx
|
||||||
|
e7ogTB50YVDIMF7A8iQMm9Kn29vjsLftSBsTDzUB4gD+NeGyST5c81RIbNf0eWUk
|
||||||
|
En5WfP0rfILKDkvm8jD0/AU=
|
||||||
|
=7KnD
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
@@ -1,10 +1,18 @@
|
|||||||
{
|
{
|
||||||
"extends": "./.nuxt/tsconfig.json",
|
"extends": "./.nuxt/tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"types": ["node"]
|
"types": [
|
||||||
|
"node"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"vueCompilerOptions": {
|
"vueCompilerOptions": {
|
||||||
"globalTypesPath": "./node_modules/.vue-global-types"
|
"globalTypesPath": "./node_modules/.vue-global-types"
|
||||||
},
|
},
|
||||||
"include": ["nuxt.config.ts", "app/**/*.ts", "app/**/*.vue", "app/**/*.d.ts", "server/**/*.ts"]
|
"include": [
|
||||||
|
"nuxt.config.ts",
|
||||||
|
"app/**/*.ts",
|
||||||
|
"app/**/*.vue",
|
||||||
|
"app/**/*.d.ts",
|
||||||
|
"server/**/*.ts"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user