@hyacine/site-uptime 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -0
- package/package.json +35 -0
- package/src/index.ts +44 -0
- package/src/runtime.ts +111 -0
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# @hyacine/site-uptime
|
|
2
|
+
|
|
3
|
+
一个用于在页脚显示站点运行时间的 Hyacine 插件。
|
|
4
|
+
|
|
5
|
+
## 功能
|
|
6
|
+
|
|
7
|
+
- 📊 实时显示站点已运行的时间(精确到秒)
|
|
8
|
+
- 🎨 自动计算年、月、日、小时、分钟、秒
|
|
9
|
+
- 🔄 每秒自动更新
|
|
10
|
+
- 🌐 Runtime-only 插件,无需服务器端渲染
|
|
11
|
+
- ⚙️ 可自定义前缀文本
|
|
12
|
+
|
|
13
|
+
## 安装
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun add @hyacine/site-uptime
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 使用方法
|
|
20
|
+
|
|
21
|
+
### 基础配置
|
|
22
|
+
|
|
23
|
+
在你的 `hyacine.plugin.ts` 或 `hyacine.plugin.mjs` 文件中配置插件:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { defineConfig } from "@hyacine/core";
|
|
27
|
+
import siteUptime from "@hyacine/site-uptime";
|
|
28
|
+
|
|
29
|
+
export default defineConfig({
|
|
30
|
+
injectPoints: {
|
|
31
|
+
"footer-status": ".footer-status", // 你的页脚状态区域选择器
|
|
32
|
+
// ... 其他注入点
|
|
33
|
+
},
|
|
34
|
+
plugins: [
|
|
35
|
+
{
|
|
36
|
+
plugin: siteUptime,
|
|
37
|
+
options: {
|
|
38
|
+
siteCreatedAt: "2024-01-01T00:00:00Z",
|
|
39
|
+
prefixText: "本站已持续运行", // 自定义前缀
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 配置选项
|
|
47
|
+
|
|
48
|
+
#### `SiteUptimeOptions`
|
|
49
|
+
|
|
50
|
+
| 选项 | 类型 | 必填 | 默认值 | 说明 |
|
|
51
|
+
| --------------- | -------- | ---- | -------------------- | ----------------------------------------------------------------------------------------- |
|
|
52
|
+
| `siteCreatedAt` | `string` | ✅ | - | 建站时间,必须是合法的 Date 字符串表达式(如 `"2024-01-01"` 或 `"2024-01-01T00:00:00Z"`) |
|
|
53
|
+
| `prefixText` | `string` | ❌ | `"该站点已经存在了"` | 显示在时间前的文本 |
|
|
54
|
+
|
|
55
|
+
## 显示效果
|
|
56
|
+
|
|
57
|
+
根据站点运行时间,插件会显示类似以下格式的文本:
|
|
58
|
+
|
|
59
|
+
- 短期运行:`该站点已经存在了 5日12小时30分钟45秒`
|
|
60
|
+
- 中期运行:`该站点已经存在了 2月15日8小时20分钟10秒`
|
|
61
|
+
- 长期运行:`该站点已经存在了 1年3月22日16小时45分钟30秒`
|
|
62
|
+
|
|
63
|
+
## 注入点
|
|
64
|
+
|
|
65
|
+
此插件默认注入到 `footer-status` 注入点。你需要在你的布局模板中确保该注入点存在。
|
|
66
|
+
|
|
67
|
+
### Astro 示例
|
|
68
|
+
|
|
69
|
+
```astro
|
|
70
|
+
<!-- 在你的 Layout.astro 中 -->
|
|
71
|
+
<footer>
|
|
72
|
+
<div class="footer-status">
|
|
73
|
+
<!-- 插件内容将注入到这里 -->
|
|
74
|
+
</div>
|
|
75
|
+
</footer>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 技术细节
|
|
79
|
+
|
|
80
|
+
- **插件类型**:Runtime-only
|
|
81
|
+
- **注入点**:footer-status
|
|
82
|
+
- **更新频率**:每秒更新一次
|
|
83
|
+
- **时间计算**:基于客户端时间,自动处理时区
|
|
84
|
+
|
|
85
|
+
## 注意事项
|
|
86
|
+
|
|
87
|
+
1. **日期格式**:`siteCreatedAt` 必须是合法的日期字符串,建议使用 ISO 8601 格式(如 `"2024-01-01T00:00:00Z"`)
|
|
88
|
+
2. **时区处理**:时间计算基于用户的本地时间,确保建站时间使用合适的时区
|
|
89
|
+
3. **性能优化**:定时器在元素从 DOM 移除时会自动清理,避免内存泄漏
|
|
90
|
+
|
|
91
|
+
## 开发
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# 格式化代码
|
|
95
|
+
bun run format
|
|
96
|
+
|
|
97
|
+
# 检查代码质量
|
|
98
|
+
bun run lint
|
|
99
|
+
|
|
100
|
+
# 构建
|
|
101
|
+
bun run build
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## 许可证
|
|
105
|
+
|
|
106
|
+
MIT
|
|
107
|
+
|
|
108
|
+
## 贡献
|
|
109
|
+
|
|
110
|
+
欢迎提交 Issue 和 Pull Request!
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hyacine/site-uptime",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A Hyacine plugin that displays site uptime in footer-status",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"footer",
|
|
7
|
+
"hyacine",
|
|
8
|
+
"plugin",
|
|
9
|
+
"uptime"
|
|
10
|
+
],
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"src"
|
|
14
|
+
],
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./src/index.ts",
|
|
19
|
+
"default": "./src/index.ts"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"lint": "bunx --bun oxlint --type-aware --type-check . --fix",
|
|
25
|
+
"format": "bunx oxfmt ."
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@hyacine/core": "workspace:*",
|
|
29
|
+
"@hyacine/helper": "workspace:*"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/bun": "latest",
|
|
33
|
+
"typescript": "^5"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { PluginManifest } from "@hyacine/core";
|
|
2
|
+
|
|
3
|
+
export interface SiteUptimeOptions {
|
|
4
|
+
/**
|
|
5
|
+
* 建站时间,合法的 Date 字符串表达式
|
|
6
|
+
* @example "2024-01-01T00:00:00Z"
|
|
7
|
+
* @example "2024-01-01"
|
|
8
|
+
*/
|
|
9
|
+
siteCreatedAt: string;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 自定义前缀文本,默认为 "该站点已经存在了"
|
|
13
|
+
* @default "该站点已经存在了"
|
|
14
|
+
*/
|
|
15
|
+
prefixText?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default (options: SiteUptimeOptions): PluginManifest => {
|
|
19
|
+
// 验证 siteCreatedAt 是否为合法的日期字符串
|
|
20
|
+
const createdDate = new Date(options.siteCreatedAt);
|
|
21
|
+
if (Number.isNaN(createdDate.getTime())) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`[site-uptime] Invalid siteCreatedAt: "${options.siteCreatedAt}". Please provide a valid date string.`,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
name: "@hyacine/site-uptime",
|
|
29
|
+
version: "0.0.1",
|
|
30
|
+
minRenderCapability: "runtime-only",
|
|
31
|
+
entry: [
|
|
32
|
+
{
|
|
33
|
+
type: "runtime-only",
|
|
34
|
+
injectPoint: "footer-status",
|
|
35
|
+
path: new URL("./runtime.ts", import.meta.url).href,
|
|
36
|
+
name: "site-uptime-runtime",
|
|
37
|
+
options: {
|
|
38
|
+
siteCreatedAt: options.siteCreatedAt,
|
|
39
|
+
prefixText: options.prefixText || "该站点已经存在了",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
};
|
package/src/runtime.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { PluginInitFunction } from "@hyacine/helper/runtime";
|
|
2
|
+
import { getInjectPointSelector } from "@hyacine/helper/runtime";
|
|
3
|
+
|
|
4
|
+
interface SiteUptimeRuntimeOptions {
|
|
5
|
+
siteCreatedAt: string;
|
|
6
|
+
prefixText: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 计算站点存在时间并格式化输出
|
|
11
|
+
* @param createdAt 建站时间
|
|
12
|
+
* @param prefixText 前缀文本
|
|
13
|
+
* @returns 格式化的时间字符串,例如 "该站点已经存在了 1年2月3日4小时5分钟6秒"
|
|
14
|
+
*/
|
|
15
|
+
function calculateUptime(createdAt: Date, prefixText: string): string {
|
|
16
|
+
const now = new Date();
|
|
17
|
+
const diff = now.getTime() - createdAt.getTime();
|
|
18
|
+
|
|
19
|
+
if (diff < 0) {
|
|
20
|
+
return `${prefixText} 0秒`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 计算各个时间单位
|
|
24
|
+
const seconds = Math.floor(diff / 1000);
|
|
25
|
+
const minutes = Math.floor(seconds / 60);
|
|
26
|
+
const hours = Math.floor(minutes / 60);
|
|
27
|
+
const days = Math.floor(hours / 24);
|
|
28
|
+
const months = Math.floor(days / 30);
|
|
29
|
+
const years = Math.floor(months / 12);
|
|
30
|
+
|
|
31
|
+
// 计算余数
|
|
32
|
+
const remainingMonths = months % 12;
|
|
33
|
+
const remainingDays = days % 30;
|
|
34
|
+
const remainingHours = hours % 24;
|
|
35
|
+
const remainingMinutes = minutes % 60;
|
|
36
|
+
const remainingSeconds = seconds % 60;
|
|
37
|
+
|
|
38
|
+
// 构建时间字符串
|
|
39
|
+
const parts: string[] = [];
|
|
40
|
+
|
|
41
|
+
if (years > 0) parts.push(`${years}年`);
|
|
42
|
+
if (remainingMonths > 0) parts.push(`${remainingMonths}月`);
|
|
43
|
+
if (remainingDays > 0) parts.push(`${remainingDays}日`);
|
|
44
|
+
if (remainingHours > 0) parts.push(`${remainingHours}小时`);
|
|
45
|
+
if (remainingMinutes > 0) parts.push(`${remainingMinutes}分钟`);
|
|
46
|
+
if (remainingSeconds > 0 || parts.length === 0) parts.push(`${remainingSeconds}秒`);
|
|
47
|
+
|
|
48
|
+
return `${prefixText} ${parts.join("")}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 创建并插入站点运行时间显示元素
|
|
53
|
+
*/
|
|
54
|
+
function createUptimeElement(options: SiteUptimeRuntimeOptions): HTMLElement {
|
|
55
|
+
const container = document.createElement("div");
|
|
56
|
+
container.className = "site-uptime";
|
|
57
|
+
container.style.cssText = "margin: 0.5rem 0; font-size: 0.9em;";
|
|
58
|
+
|
|
59
|
+
const createdAt = new Date(options.siteCreatedAt);
|
|
60
|
+
|
|
61
|
+
// 初始渲染
|
|
62
|
+
container.textContent = calculateUptime(createdAt, options.prefixText);
|
|
63
|
+
|
|
64
|
+
// 每秒更新一次
|
|
65
|
+
const intervalId = setInterval(() => {
|
|
66
|
+
container.textContent = calculateUptime(createdAt, options.prefixText);
|
|
67
|
+
}, 1000);
|
|
68
|
+
|
|
69
|
+
// 清理函数:当元素从 DOM 中移除时清除定时器
|
|
70
|
+
const observer = new MutationObserver((mutations) => {
|
|
71
|
+
for (const mutation of mutations) {
|
|
72
|
+
for (const node of mutation.removedNodes) {
|
|
73
|
+
if (node === container) {
|
|
74
|
+
clearInterval(intervalId);
|
|
75
|
+
observer.disconnect();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// 观察父节点的变化
|
|
82
|
+
if (container.parentNode) {
|
|
83
|
+
observer.observe(container.parentNode, { childList: true });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return container;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Runtime-only 插件初始化函数
|
|
91
|
+
*/
|
|
92
|
+
export const init: PluginInitFunction<SiteUptimeRuntimeOptions> = (options) => {
|
|
93
|
+
// 等待 DOM 加载完成
|
|
94
|
+
if (document.readyState === "loading") {
|
|
95
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
96
|
+
const element = createUptimeElement(options);
|
|
97
|
+
const selector = getInjectPointSelector("footer-status");
|
|
98
|
+
const targetElement = document.querySelector(selector);
|
|
99
|
+
if (targetElement) {
|
|
100
|
+
targetElement.appendChild(element);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
} else {
|
|
104
|
+
const element = createUptimeElement(options);
|
|
105
|
+
const selector = getInjectPointSelector("footer-status");
|
|
106
|
+
const targetElement = document.querySelector(selector);
|
|
107
|
+
if (targetElement) {
|
|
108
|
+
targetElement.appendChild(element);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|