hexo-theme-gnix 1.1.0
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 +106 -0
- package/include/hexo/filter/locals.js +109 -0
- package/include/hexo/generator/categories.js +12 -0
- package/include/hexo/generator/category.js +52 -0
- package/include/hexo/generator/insight.js +50 -0
- package/include/hexo/generator/manifest.js +23 -0
- package/include/hexo/generator/tags.js +12 -0
- package/include/hexo/helper/cdn.js +21 -0
- package/include/hexo/helper/page.js +27 -0
- package/include/hexo/view.js +40 -0
- package/include/register.js +11 -0
- package/include/util/common.js +33 -0
- package/languages/en.yml +47 -0
- package/languages/fr.yml +46 -0
- package/languages/ja.yml +46 -0
- package/languages/zh-CN.yml +47 -0
- package/languages/zh-TW.yml +47 -0
- package/layout/archive.jsx +118 -0
- package/layout/categories.jsx +137 -0
- package/layout/category.jsx +38 -0
- package/layout/comment/disqus.jsx +79 -0
- package/layout/comment/disqusjs.jsx +127 -0
- package/layout/comment/giscus.jsx +193 -0
- package/layout/comment/gitalk.jsx +141 -0
- package/layout/comment/twikoo.jsx +63 -0
- package/layout/comment/utterances.jsx +86 -0
- package/layout/comment/valine.jsx +143 -0
- package/layout/comment/waline.jsx +156 -0
- package/layout/common/article.jsx +131 -0
- package/layout/common/article_cover.jsx +33 -0
- package/layout/common/article_media.jsx +34 -0
- package/layout/common/comment.jsx +38 -0
- package/layout/common/footer.jsx +228 -0
- package/layout/common/head.jsx +242 -0
- package/layout/common/navbar.jsx +219 -0
- package/layout/common/plugins.jsx +39 -0
- package/layout/common/scripts.jsx +49 -0
- package/layout/common/search.jsx +22 -0
- package/layout/common/theme_selector.jsx +79 -0
- package/layout/common/toc.jsx +53 -0
- package/layout/index.jsx +29 -0
- package/layout/layout.jsx +34 -0
- package/layout/misc/article_licensing.jsx +114 -0
- package/layout/misc/meta.jsx +61 -0
- package/layout/misc/open_graph.jsx +164 -0
- package/layout/misc/paginator.jsx +90 -0
- package/layout/misc/structured_data.jsx +110 -0
- package/layout/misc/web_app.jsx +106 -0
- package/layout/page.jsx +12 -0
- package/layout/plugin/bing_webmaster.jsx +47 -0
- package/layout/plugin/busuanzi.jsx +40 -0
- package/layout/plugin/clarity.jsx +22 -0
- package/layout/plugin/cookie_consent.jsx +136 -0
- package/layout/plugin/google_analytics.jsx +66 -0
- package/layout/plugin/google_tag_mamager.jsx +41 -0
- package/layout/plugin/netlify.jsx +39 -0
- package/layout/plugin/pjax.jsx +20 -0
- package/layout/plugin/statcounter.jsx +69 -0
- package/layout/plugin/twitter_conversion_tracking.jsx +51 -0
- package/layout/post.jsx +16 -0
- package/layout/search/insight.jsx +53 -0
- package/layout/tag.jsx +29 -0
- package/layout/tags.jsx +55 -0
- package/package.json +42 -0
- package/scripts/index.js +1 -0
- package/source/css/callout_blocks.css +204 -0
- package/source/css/default.css +1590 -0
- package/source/css/font/woff2/Futura-Book.woff2 +0 -0
- package/source/css/font/woff2/Paris2024-Variable.woff2 +0 -0
- package/source/css/font/woff2/doto.woff2 +0 -0
- package/source/css/optional/chinese.css +17 -0
- package/source/css/responsive/desktop.css +164 -0
- package/source/css/responsive/mobile.css +46 -0
- package/source/css/responsive/tablet.css +46 -0
- package/source/css/responsive/touch.css +254 -0
- package/source/css/shiki/shiki.min.css +1 -0
- package/source/css/twikoo.css +2143 -0
- package/source/img/avatar.webp +0 -0
- package/source/img/background.webp +0 -0
- package/source/img/favicon.svg +6 -0
- package/source/img/logo.svg +9 -0
- package/source/img/og_image.png +0 -0
- package/source/js/busuanzi.js +46 -0
- package/source/js/host/cookieconsent/3.1.1/build/cookieconsent.min.css +6 -0
- package/source/js/host/cookieconsent/3.1.1/build/cookieconsent.min.js +1 -0
- package/source/js/host/iconify-icon/3.0.2/iconify-icon.min.js +12 -0
- package/source/js/host/medium-zoom/dist/medium-zoom.min.js +2 -0
- package/source/js/host/mermaid/mermaid.min.js +2811 -0
- package/source/js/host/pjax/0.2.8/pjax.min.js +1 -0
- package/source/js/host/twikoo/1.6.41/dist/twikoo.all.min.js +2 -0
- package/source/js/insight.js +330 -0
- package/source/js/instant-page.min.js +1 -0
- package/source/js/live2d_Asoul/Model/Ava/Ava.4096/texture_00.webp +0 -0
- package/source/js/live2d_Asoul/Model/Ava/Ava.moc3 +0 -0
- package/source/js/live2d_Asoul/Model/Ava/Ava.model3.json +323 -0
- package/source/js/live2d_Asoul/Model/Ava/Ava.physics3.json +1225 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_idle.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_shake01.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_shake02.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap01.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap02.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap03.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap04.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap05.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap06.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap07.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap08.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap09.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap10.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/motions/Ava_tap11.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Ava/raw.ex.json +16 -0
- package/source/js/live2d_Asoul/Model/Ava/raw.model3.json +321 -0
- package/source/js/live2d_Asoul/Model/Diana/Diana.4096/texture_00.webp +0 -0
- package/source/js/live2d_Asoul/Model/Diana/Diana.moc3 +0 -0
- package/source/js/live2d_Asoul/Model/Diana/Diana.model3.json +212 -0
- package/source/js/live2d_Asoul/Model/Diana/Diana.physics3.json +764 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_idle.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap01.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap02.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap03.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap04.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap05.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap06.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap07.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap08.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap09.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap10.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/motions/Diana_tap11.motion3.json +1 -0
- package/source/js/live2d_Asoul/Model/Diana/raw.ex.json +16 -0
- package/source/js/live2d_Asoul/Model/Diana/raw.model3.json +210 -0
- package/source/js/live2d_Asoul/TweenLite.js +12 -0
- package/source/js/live2d_Asoul/cubism4.min.js +2 -0
- package/source/js/live2d_Asoul/live2dcubismcore.min.js +9 -0
- package/source/js/live2d_Asoul/load.js +231 -0
- package/source/js/live2d_Asoul/pio.css +161 -0
- package/source/js/live2d_Asoul/pio.js +296 -0
- package/source/js/live2d_Asoul/pio_sdk4.js +149 -0
- package/source/js/live2d_Asoul/pixi.min.js +9 -0
- package/source/js/main.js +218 -0
- package/source/js/pjax.js +29 -0
- package/source/js/shiki/shiki.js +191 -0
- package/source/js/theme-selector.js +206 -0
- package/util/cache.js +47 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
// biome-ignore lint/correctness/noUnusedVariables: Called in other files
|
|
2
|
+
function loadInsight(config, translation) {
|
|
3
|
+
const main = document.querySelector(".searchbox");
|
|
4
|
+
if (!main) return;
|
|
5
|
+
|
|
6
|
+
const input = main.querySelector(".searchbox-input");
|
|
7
|
+
const container = main.querySelector(".searchbox-body");
|
|
8
|
+
|
|
9
|
+
// 状态管理
|
|
10
|
+
let dataset = null; // 缓存 JSON 数据
|
|
11
|
+
let isLoading = false; // 加载锁
|
|
12
|
+
let searchTimer = null; // 防抖定时器
|
|
13
|
+
|
|
14
|
+
// 辅助:创建 DOM
|
|
15
|
+
function createElement(tag, className, text) {
|
|
16
|
+
const el = document.createElement(tag);
|
|
17
|
+
if (className) el.className = className;
|
|
18
|
+
if (text) el.textContent = text;
|
|
19
|
+
return el;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function section(title) {
|
|
23
|
+
const sectionEl = createElement("section", "searchbox-result-section");
|
|
24
|
+
const header = createElement("header", "", title);
|
|
25
|
+
sectionEl.appendChild(header);
|
|
26
|
+
return sectionEl;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// --- 核心逻辑优化区 ---
|
|
30
|
+
|
|
31
|
+
// 优化点:合并 ranges 的逻辑保持不变,这是高亮的核心算法
|
|
32
|
+
function merge(ranges) {
|
|
33
|
+
let last;
|
|
34
|
+
const result = [];
|
|
35
|
+
ranges.forEach((r) => {
|
|
36
|
+
if (!last || r[0] > last[1]) {
|
|
37
|
+
result.push((last = r));
|
|
38
|
+
} else if (r[1] > last[1]) {
|
|
39
|
+
last[1] = r[1];
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function findAndHighlight(text, matches, maxlen) {
|
|
46
|
+
if (!Array.isArray(matches) || !matches.length || !text) {
|
|
47
|
+
return maxlen ? text.slice(0, maxlen) : text;
|
|
48
|
+
}
|
|
49
|
+
const testText = text.toLowerCase();
|
|
50
|
+
|
|
51
|
+
// 性能优化:直接搜索索引,不再 map 后 filter
|
|
52
|
+
const indices = [];
|
|
53
|
+
for (const match of matches) {
|
|
54
|
+
const index = testText.indexOf(match.toLowerCase());
|
|
55
|
+
if (match && index !== -1) {
|
|
56
|
+
indices.push([index, index + match.length]);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 排序
|
|
61
|
+
indices.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
|
|
62
|
+
|
|
63
|
+
if (!indices.length) return maxlen ? text.slice(0, maxlen) : text;
|
|
64
|
+
|
|
65
|
+
let result = "";
|
|
66
|
+
let last = 0;
|
|
67
|
+
const ranges = merge(indices);
|
|
68
|
+
const sumRange = [ranges[0][0], ranges[ranges.length - 1][1]];
|
|
69
|
+
|
|
70
|
+
if (maxlen && maxlen < sumRange[1]) {
|
|
71
|
+
last = sumRange[0];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
75
|
+
const range = ranges[i];
|
|
76
|
+
result += text.slice(last, Math.min(range[0], sumRange[0] + maxlen));
|
|
77
|
+
if (maxlen && range[0] >= sumRange[0] + maxlen) break;
|
|
78
|
+
|
|
79
|
+
result += `<em>${text.slice(range[0], range[1])}</em>`;
|
|
80
|
+
last = range[1];
|
|
81
|
+
|
|
82
|
+
if (i === ranges.length - 1) {
|
|
83
|
+
if (maxlen) {
|
|
84
|
+
result += text.slice(range[1], Math.min(text.length, sumRange[0] + maxlen + 1));
|
|
85
|
+
} else {
|
|
86
|
+
result += text.slice(range[1]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function searchItem(title, preview, url) {
|
|
94
|
+
title = title || translation.untitled;
|
|
95
|
+
return `<a class="searchbox-result-item" href="${url}">
|
|
96
|
+
<span class="searchbox-result-content">
|
|
97
|
+
<span class="searchbox-result-title">${title}</span>
|
|
98
|
+
${preview ? `<span class="searchbox-result-preview">${preview}</span>` : ""}
|
|
99
|
+
</span>
|
|
100
|
+
</a>`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function sectionFactory(keywords, type, array) {
|
|
104
|
+
if (array.length === 0) return null;
|
|
105
|
+
const sectionTitle = translation[type.toLowerCase()];
|
|
106
|
+
|
|
107
|
+
// 优化点:使用 DocumentFragment 并不完全适用这里因为我们返回的是 element
|
|
108
|
+
// 但我们可以用 map + join 一次性生成 HTML 字符串
|
|
109
|
+
const isPostOrPage = type === "POSTS" || type === "PAGES";
|
|
110
|
+
|
|
111
|
+
const itemsHTML = array.map(item => {
|
|
112
|
+
if (isPostOrPage) {
|
|
113
|
+
const title = findAndHighlight(item.title, keywords);
|
|
114
|
+
const text = findAndHighlight(item.text, keywords, 100);
|
|
115
|
+
return searchItem(title, text, item.link);
|
|
116
|
+
} else {
|
|
117
|
+
// Categories / Tags
|
|
118
|
+
const name = findAndHighlight(item.name, keywords);
|
|
119
|
+
return searchItem(name, null, item.link);
|
|
120
|
+
}
|
|
121
|
+
}).join("");
|
|
122
|
+
|
|
123
|
+
const sectionEl = section(sectionTitle);
|
|
124
|
+
sectionEl.insertAdjacentHTML("beforeend", itemsHTML);
|
|
125
|
+
return sectionEl;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function parseKeywords(keywords) {
|
|
129
|
+
return keywords.split(" ").filter((k) => !!k).map((k) => k.toLowerCase());
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function search(json, keywordsStr) {
|
|
133
|
+
const keywords = parseKeywords(keywordsStr);
|
|
134
|
+
if (keywords.length === 0) return {};
|
|
135
|
+
|
|
136
|
+
// 把keywords中的特殊字符转义, 将转移后的关键词编译为正则表达式(忽略大小写,全局,多行)
|
|
137
|
+
// 后续在文章内容匹配时使用
|
|
138
|
+
const keywordRegexes = keywords.map(k => new RegExp(k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), "img"));
|
|
139
|
+
|
|
140
|
+
const calculateWeight = (obj, fields, weights) => {
|
|
141
|
+
let value = 0;
|
|
142
|
+
|
|
143
|
+
// 检查所有关键词
|
|
144
|
+
for (let i = 0; i < keywords.length; i++) {
|
|
145
|
+
const keyword = keywords[i];
|
|
146
|
+
const regex = keywordRegexes[i];
|
|
147
|
+
let keywordInFields = false;
|
|
148
|
+
|
|
149
|
+
for (let j = 0; j < fields.length; j++) {
|
|
150
|
+
const field = fields[j];
|
|
151
|
+
if (!obj[field]) continue;
|
|
152
|
+
|
|
153
|
+
// 1. 快速检查:如果都不包含这个词,直接跳过正则
|
|
154
|
+
if (obj[field].toLowerCase().indexOf(keyword) === -1) continue;
|
|
155
|
+
|
|
156
|
+
// 2. 权重计算
|
|
157
|
+
const matches = obj[field].match(regex);
|
|
158
|
+
if (matches) {
|
|
159
|
+
value += matches.length * weights[j];
|
|
160
|
+
keywordInFields = true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// 如果这个关键词在任何字段都没出现,那这个对象就不符合“包含所有关键词”的逻辑
|
|
165
|
+
// 原逻辑是 filter 必须包含所有关键词,这里保持一致
|
|
166
|
+
if (!keywordInFields) return 0;
|
|
167
|
+
}
|
|
168
|
+
return value;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// 通用搜索器
|
|
172
|
+
const executeSearch = (list, fields, weights) => {
|
|
173
|
+
const results = [];
|
|
174
|
+
for (const item of list) {
|
|
175
|
+
const w = calculateWeight(item, fields, weights);
|
|
176
|
+
if (w > 0) {
|
|
177
|
+
results.push({ item, weight: w });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// 排序并取 Top 5
|
|
181
|
+
return results
|
|
182
|
+
.sort((a, b) => b.weight - a.weight)
|
|
183
|
+
.map(r => r.item)
|
|
184
|
+
.slice(0, 5);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
posts: executeSearch(json.posts, ["title", "text"], [3, 1]),
|
|
189
|
+
pages: executeSearch(json.pages, ["title", "text"], [3, 1]),
|
|
190
|
+
categories: executeSearch(json.categories, ["name", "slug"], [1, 1]),
|
|
191
|
+
tags: executeSearch(json.tags, ["name", "slug"], [1, 1]),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function searchResultToDOM(keywords, searchResult) {
|
|
196
|
+
container.innerHTML = "";
|
|
197
|
+
const fragment = document.createDocumentFragment(); // 使用 Fragment 减少重排
|
|
198
|
+
|
|
199
|
+
for (const key in searchResult) {
|
|
200
|
+
const sectionNode = sectionFactory(
|
|
201
|
+
parseKeywords(keywords),
|
|
202
|
+
key.toUpperCase(),
|
|
203
|
+
searchResult[key]
|
|
204
|
+
);
|
|
205
|
+
if (sectionNode) {
|
|
206
|
+
fragment.appendChild(sectionNode);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
container.appendChild(fragment);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function scrollTo(item) {
|
|
213
|
+
if (!item) return;
|
|
214
|
+
const wrapperHeight = container.clientHeight;
|
|
215
|
+
const itemTop = item.offsetTop;
|
|
216
|
+
const itemHeight = item.clientHeight;
|
|
217
|
+
const scrollTop = container.scrollTop;
|
|
218
|
+
if (itemTop + itemHeight > scrollTop + wrapperHeight) {
|
|
219
|
+
container.scrollTop = itemTop + itemHeight - wrapperHeight;
|
|
220
|
+
}
|
|
221
|
+
if (itemTop < scrollTop) {
|
|
222
|
+
container.scrollTop = itemTop;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function selectItemByDiff(value) {
|
|
227
|
+
const items = Array.from(container.querySelectorAll(".searchbox-result-item"));
|
|
228
|
+
if (items.length === 0) return;
|
|
229
|
+
|
|
230
|
+
// 查找 active 索引
|
|
231
|
+
const prevPosition = items.findIndex(item => item.classList.contains("active"));
|
|
232
|
+
|
|
233
|
+
const nextPosition = (items.length + prevPosition + value) % items.length;
|
|
234
|
+
const finalPosition = nextPosition < 0 ? nextPosition + items.length : nextPosition;
|
|
235
|
+
|
|
236
|
+
if (prevPosition !== -1) items[prevPosition].classList.remove("active");
|
|
237
|
+
|
|
238
|
+
const nextItem = items[finalPosition];
|
|
239
|
+
nextItem.classList.add("active");
|
|
240
|
+
scrollTo(nextItem);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// --- 数据加载与事件 ---
|
|
244
|
+
|
|
245
|
+
// 优化点:提取 Fetch 逻辑,支持 Lazy Load
|
|
246
|
+
function fetchData() {
|
|
247
|
+
if (dataset || isLoading) return;
|
|
248
|
+
isLoading = true;
|
|
249
|
+
|
|
250
|
+
fetch(config.contentUrl)
|
|
251
|
+
.then((response) => response.json())
|
|
252
|
+
.then((json) => {
|
|
253
|
+
dataset = json;
|
|
254
|
+
isLoading = false;
|
|
255
|
+
// 如果加载完之后输入框里有字,立即触发一次搜索
|
|
256
|
+
if (input.value.trim()) {
|
|
257
|
+
input.dispatchEvent(new Event("input"));
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
.catch((err) => {
|
|
261
|
+
console.error("Insight Search: Failed to load content.json", err);
|
|
262
|
+
isLoading = false;
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// 监听输入
|
|
267
|
+
input.addEventListener("input", function () {
|
|
268
|
+
const keywords = this.value;
|
|
269
|
+
|
|
270
|
+
// 清除上一次的定时器
|
|
271
|
+
if (searchTimer) clearTimeout(searchTimer);
|
|
272
|
+
|
|
273
|
+
if (!dataset) {
|
|
274
|
+
fetchData(); // 兜底,防止万一没加载
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// 优化点:防抖 (Debounce) 300ms
|
|
279
|
+
searchTimer = setTimeout(() => {
|
|
280
|
+
searchResultToDOM(keywords, search(dataset, keywords));
|
|
281
|
+
}, 200);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
main.addEventListener("focusout", (e) => {
|
|
285
|
+
if (main.contains(e.relatedTarget)) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
// 当焦点移出 searchbox 时,关闭搜索框
|
|
289
|
+
main.classList.remove("show");
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// 监听打开搜索框的点击事件
|
|
293
|
+
document.addEventListener("click", (e) => {
|
|
294
|
+
if (e.target.closest(".navbar-main .search")) {
|
|
295
|
+
main.classList.add("show");
|
|
296
|
+
const inp = main.querySelector(".searchbox-input");
|
|
297
|
+
if (inp) inp.focus();
|
|
298
|
+
|
|
299
|
+
// 优化点:Lazy Load - 打开时再请求数据
|
|
300
|
+
fetchData();
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
document.addEventListener("keydown", (e) => {
|
|
306
|
+
if (!main.classList.contains("show")) return;
|
|
307
|
+
switch (e.key) {
|
|
308
|
+
case "ArrowUp":
|
|
309
|
+
selectItemByDiff(-1);
|
|
310
|
+
break;
|
|
311
|
+
case "ArrowDown":
|
|
312
|
+
selectItemByDiff(1);
|
|
313
|
+
break;
|
|
314
|
+
case "Enter": {
|
|
315
|
+
const activeItem = container.querySelector(".searchbox-result-item.active");
|
|
316
|
+
if (activeItem) location.href = activeItem.getAttribute("href");
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
document.addEventListener("touchstart", () => { touch = true; });
|
|
323
|
+
document.addEventListener("touchmove", () => { touch = false; });
|
|
324
|
+
|
|
325
|
+
// 处理 location.hash 自动打开的情况
|
|
326
|
+
if (location.hash.trim() === "#insight-search") {
|
|
327
|
+
main.classList.add("show");
|
|
328
|
+
fetchData();
|
|
329
|
+
}
|
|
330
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/*! instant.page v5.2.0 - (C) 2019-2023 Alexandre Dieulot - https://instant.page/license */let t,e,n,o,i,a=null,s=65,c=new Set;const r=1111;function d(e){o=performance.now();const t=e.target.closest("a");m(t)&&p(t.href,"high")}function u(e){if(performance.now()-o<r)return;if(!("closest"in e.target))return;const t=e.target.closest("a");m(t)&&(t.addEventListener("mouseout",f,{passive:!0}),i=setTimeout(()=>{p(t.href,"high"),i=0[0]},s))}function l(e){const t=e.target.closest("a");m(t)&&p(t.href,"high")}function f(e){e.relatedTarget&&e.target.closest("a")==e.relatedTarget.closest("a")||i&&(clearTimeout(i),i=0[0])}function h(e){if(performance.now()-o<r)return;const t=e.target.closest("a");if(e.which>1||e.metaKey||e.ctrlKey)return;if(!t)return;t.addEventListener("click",function(e){1337!=e.detail&&e.preventDefault()},{capture:!0,passive:!1,once:!0});const n=new MouseEvent("click",{view:window,bubbles:!0,cancelable:!1,detail:1337});t.dispatchEvent(n)}function m(s){if(s&&s.href&&(!n||"instant"in s.dataset)){if(s.origin!=location.origin&&(!(e||"instant"in s.dataset)||!a))return;if(["http:","https:"].includes(s.protocol)&&("http:"!=s.protocol||"https:"!=location.protocol)&&(t||!s.search||"instant"in s.dataset)&&!(s.hash&&s.pathname+s.search==location.pathname+location.search||"noInstant"in s.dataset))return!0}}function p(e,t="auto"){if(c.has(e))return;const n=document.createElement("link");n.rel="prefetch",n.href=e,n.fetchPriority=t,n.as="document",document.head.appendChild(n),c.add(e)}!function(){if(!document.createElement("link").relList.supports("prefetch"))return;const v="instantVaryAccept"in document.body.dataset||"Shopify"in window,r=navigator.userAgent.indexOf("Chrome/");if(r>-1&&(a=parseInt(navigator.userAgent.substring(r+"Chrome/".length))),v&&a&&a<110)return;const c="instantMousedownShortcut"in document.body.dataset;t="instantAllowQueryString"in document.body.dataset,e="instantAllowExternalLinks"in document.body.dataset,n="instantWhitelist"in document.body.dataset;const o={capture:!0,passive:!0};let f=!1,g=!1,i=!1;if("instantIntensity"in document.body.dataset){const e=document.body.dataset.instantIntensity;if(e.startsWith("mousedown"))f=!0,"mousedown-only"==e&&(g=!0);else if(e.startsWith("viewport")){const t=navigator.connection&&navigator.connection.saveData,n=navigator.connection&&navigator.connection.effectiveType&&navigator.connection.effectiveType.includes("2g");t||n||("viewport"==e?document.documentElement.clientWidth*document.documentElement.clientHeight<45e4&&(i=!0):"viewport-all"==e&&(i=!0))}else{const t=parseInt(e);isNaN(t)||(s=t)}}if(g||document.addEventListener("touchstart",d,o),f?c||document.addEventListener("mousedown",l,o):document.addEventListener("mouseover",u,o),c&&document.addEventListener("mousedown",h,o),i){let e=window.requestIdleCallback;e||(e=e=>{e()}),e(function(){const e=new IntersectionObserver(t=>{t.forEach(t=>{if(t.isIntersecting){const n=t.target;e.unobserve(n),p(n.href)}})});document.querySelectorAll("a").forEach(t=>{m(t)&&e.observe(t)})},{timeout:1500})}}()
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Version": 3,
|
|
3
|
+
"Bounds": {
|
|
4
|
+
"Width": 9.772043,
|
|
5
|
+
"Height": 11.08606,
|
|
6
|
+
"CenterX": 0.1069689,
|
|
7
|
+
"CenterY": -1.404058
|
|
8
|
+
},
|
|
9
|
+
"FileReferences": {
|
|
10
|
+
"Moc": "Ava.moc3",
|
|
11
|
+
"Textures": [
|
|
12
|
+
"Ava.4096/texture_00.webp"
|
|
13
|
+
],
|
|
14
|
+
"Physics": "Ava.physics3.json",
|
|
15
|
+
"PhysicsV2": {
|
|
16
|
+
"File": "Ava.physics3.json"
|
|
17
|
+
},
|
|
18
|
+
"Motions": {
|
|
19
|
+
"Idle": [{
|
|
20
|
+
"Name": "待机",
|
|
21
|
+
"File": "motions/Ava_idle.motion3.json"
|
|
22
|
+
}],
|
|
23
|
+
"Shake": [{
|
|
24
|
+
"Name": "晕",
|
|
25
|
+
"File": "motions/Ava_shake01.motion3.json",
|
|
26
|
+
"Text": "啊呜...",
|
|
27
|
+
"TextDuration": 2000
|
|
28
|
+
}, {
|
|
29
|
+
"File": "motions/Ava_shake02.motion3.json"
|
|
30
|
+
}],
|
|
31
|
+
"Tap左手": [{
|
|
32
|
+
"Name": "吉他",
|
|
33
|
+
"File": "motions/Ava_tap01.motion3.json",
|
|
34
|
+
"Text": "可爱的鸽子鸽子~我喜欢你~",
|
|
35
|
+
"TextDelay": 1200,
|
|
36
|
+
"TextDuration": 5600
|
|
37
|
+
}],
|
|
38
|
+
"Tap右手": [{
|
|
39
|
+
"Name": "游戏",
|
|
40
|
+
"File": "motions/Ava_tap02.motion3.json",
|
|
41
|
+
"Text": "来陪我玩游戏!",
|
|
42
|
+
"TextDelay": 600,
|
|
43
|
+
"TextDuration": 2500
|
|
44
|
+
}],
|
|
45
|
+
"Tap腰": [{
|
|
46
|
+
"Name": "傲娇",
|
|
47
|
+
"File": "motions/Ava_tap03.motion3.json",
|
|
48
|
+
"Text": "哼,才不是傲娇大小姐",
|
|
49
|
+
"TextDelay": 500,
|
|
50
|
+
"TextDuration": 3000
|
|
51
|
+
}],
|
|
52
|
+
"Tap中间刘海": [{
|
|
53
|
+
"Name": "害羞",
|
|
54
|
+
"File": "motions/Ava_tap04.motion3.json",
|
|
55
|
+
"Text": "好...好兄弟之间喜欢很正常啦",
|
|
56
|
+
"TextDelay": 1500,
|
|
57
|
+
"TextDuration": 3000
|
|
58
|
+
}, {
|
|
59
|
+
"Name": "害羞2",
|
|
60
|
+
"File": "motions/Ava_tap04.motion3.json",
|
|
61
|
+
"Text": "也...也不是不可以",
|
|
62
|
+
"TextDelay": 2000,
|
|
63
|
+
"TextDuration": 3000
|
|
64
|
+
}],
|
|
65
|
+
"Tap嘴": [{
|
|
66
|
+
"Name": "傲娇",
|
|
67
|
+
"File": "motions/Ava_tap03.motion3.json",
|
|
68
|
+
"Text": "什么傲娇啦,我才没有",
|
|
69
|
+
"TextDelay": 500,
|
|
70
|
+
"TextDuration": 2200
|
|
71
|
+
}],
|
|
72
|
+
"Tap胸口项链": [{
|
|
73
|
+
"Name": "笑",
|
|
74
|
+
"File": "motions/Ava_tap05.motion3.json"
|
|
75
|
+
}],
|
|
76
|
+
"Tap脖子": [{
|
|
77
|
+
"Name": "监督",
|
|
78
|
+
"File": "motions/Ava_tap06.motion3.json",
|
|
79
|
+
"Text": "嗯?老戳我干嘛,快去干正事啦 ",
|
|
80
|
+
"TextDelay": 550,
|
|
81
|
+
"TextDuration": 4000
|
|
82
|
+
}],
|
|
83
|
+
"Tap 右边头饰小花": [{
|
|
84
|
+
"Name": "懒羊羊",
|
|
85
|
+
"File": "motions/Ava_tap07.motion3.json",
|
|
86
|
+
"Text": "顶晚人...顶晚人在哪里...",
|
|
87
|
+
"TextDelay": 800,
|
|
88
|
+
"TextDuration": 6000
|
|
89
|
+
}],
|
|
90
|
+
"Tap右头饰": [{
|
|
91
|
+
"Name": "猫",
|
|
92
|
+
"File": "motions/Ava_tap08.motion3.json",
|
|
93
|
+
"Text": "neko panch!",
|
|
94
|
+
"TextDelay": 500,
|
|
95
|
+
"TextDuration": 2000
|
|
96
|
+
}],
|
|
97
|
+
"Tap右眼": [{
|
|
98
|
+
"Name": "惊讶",
|
|
99
|
+
"File": "motions/Ava_tap09.motion3.json",
|
|
100
|
+
"Text": "啊",
|
|
101
|
+
"TextDelay": 200,
|
|
102
|
+
"TextDuration": 1000
|
|
103
|
+
}],
|
|
104
|
+
"Tap左眼": [{
|
|
105
|
+
"Name": "墨镜",
|
|
106
|
+
"File": "motions/Ava_tap10.motion3.json",
|
|
107
|
+
"Text": "嗯哼~我超帅的",
|
|
108
|
+
"TextDelay": 700,
|
|
109
|
+
"TextDuration": 2000
|
|
110
|
+
}],
|
|
111
|
+
"Tap右马尾 ": [{
|
|
112
|
+
"Name": "水母",
|
|
113
|
+
"File": "motions/Ava_tap11.motion3.json"
|
|
114
|
+
}],
|
|
115
|
+
"Tap左马尾": [{
|
|
116
|
+
"Name": "><",
|
|
117
|
+
"File": "motions/Ava_shake02.motion3.json",
|
|
118
|
+
"Text": "头发摸乱了啦~",
|
|
119
|
+
"TextDelay": 500,
|
|
120
|
+
"TextDuration": 2000
|
|
121
|
+
}],
|
|
122
|
+
"Tap右手臂": [{
|
|
123
|
+
"File": "motions/Ava_tap06.motion3.json",
|
|
124
|
+
"Text": "嗯?老戳我干嘛,快去干正事啦 ",
|
|
125
|
+
"TextDelay": 550,
|
|
126
|
+
"TextDuration": 4000
|
|
127
|
+
}],
|
|
128
|
+
"Tap左中马尾": [{
|
|
129
|
+
"File": "motions/Ava_tap11.motion3.json"
|
|
130
|
+
}]
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"Controllers": {
|
|
134
|
+
"ParamHit": {},
|
|
135
|
+
"ParamLoop": {},
|
|
136
|
+
"KeyTrigger": {},
|
|
137
|
+
"EyeBlink": {
|
|
138
|
+
"MinInterval": 500,
|
|
139
|
+
"MaxInterval": 6000,
|
|
140
|
+
"Items": [{
|
|
141
|
+
"Id": "ParamEyeLOpen",
|
|
142
|
+
"Min": 0.0,
|
|
143
|
+
"Max": 1.0,
|
|
144
|
+
"BlendMode": 2,
|
|
145
|
+
"Input": 0
|
|
146
|
+
}, {
|
|
147
|
+
"Id": "ParamEyeROpen",
|
|
148
|
+
"Min": 0.0,
|
|
149
|
+
"Max": 1.0,
|
|
150
|
+
"BlendMode": 2,
|
|
151
|
+
"Input": 0
|
|
152
|
+
}, {
|
|
153
|
+
"Id": "Param7",
|
|
154
|
+
"Min": 0.0,
|
|
155
|
+
"Max": 1.0,
|
|
156
|
+
"BlendMode": 2,
|
|
157
|
+
"Input": 0
|
|
158
|
+
}, {
|
|
159
|
+
"Id": "Param8",
|
|
160
|
+
"Min": 0.0,
|
|
161
|
+
"Max": 1.0,
|
|
162
|
+
"BlendMode": 2,
|
|
163
|
+
"Input": 0
|
|
164
|
+
}],
|
|
165
|
+
"Enabled": true
|
|
166
|
+
},
|
|
167
|
+
"LipSync": {
|
|
168
|
+
"Gain": 5.0
|
|
169
|
+
},
|
|
170
|
+
"MouseTracking": {
|
|
171
|
+
"SmoothTime": 0.15,
|
|
172
|
+
"Items": [{
|
|
173
|
+
"Id": "ParamAngleX",
|
|
174
|
+
"Min": -30.0,
|
|
175
|
+
"Max": 30.0,
|
|
176
|
+
"DefaultValue": 0.0,
|
|
177
|
+
"Weight": 0.359834284,
|
|
178
|
+
"BlendMode": 1,
|
|
179
|
+
"Input": 1
|
|
180
|
+
}, {
|
|
181
|
+
"Id": "ParamAngleY",
|
|
182
|
+
"Min": -30.0,
|
|
183
|
+
"Max": 30.0,
|
|
184
|
+
"DefaultValue": 0.0,
|
|
185
|
+
"Weight": 0.3398514,
|
|
186
|
+
"BlendMode": 1,
|
|
187
|
+
"Axis": 1,
|
|
188
|
+
"Input": 2
|
|
189
|
+
}, {
|
|
190
|
+
"Id": "ParamAngleZ",
|
|
191
|
+
"Min": -15.0,
|
|
192
|
+
"Max": 15.0,
|
|
193
|
+
"DefaultValue": 0.0,
|
|
194
|
+
"Weight": 0.199971348,
|
|
195
|
+
"BlendMode": 1,
|
|
196
|
+
"Axis": 2,
|
|
197
|
+
"Input": 1
|
|
198
|
+
}, {
|
|
199
|
+
"Id": "ParamBodyAngleX",
|
|
200
|
+
"Min": -10.0,
|
|
201
|
+
"Max": 10.0,
|
|
202
|
+
"DefaultValue": 0.0,
|
|
203
|
+
"Weight": 0.376962453,
|
|
204
|
+
"BlendMode": 1,
|
|
205
|
+
"Input": 1
|
|
206
|
+
}, {
|
|
207
|
+
"Id": "ParamBodyAngleZ",
|
|
208
|
+
"Min": -10.0,
|
|
209
|
+
"Max": 10.0,
|
|
210
|
+
"DefaultValue": 0.0,
|
|
211
|
+
"Weight": 0.365543664,
|
|
212
|
+
"BlendMode": 1,
|
|
213
|
+
"Axis": 2,
|
|
214
|
+
"Input": 1
|
|
215
|
+
}, {
|
|
216
|
+
"Id": "Param46",
|
|
217
|
+
"Min": -30.0,
|
|
218
|
+
"Max": 30.0,
|
|
219
|
+
"DefaultValue": 0.0,
|
|
220
|
+
"Weight": 0.411218822,
|
|
221
|
+
"BlendMode": 1,
|
|
222
|
+
"Axis": 1,
|
|
223
|
+
"Input": 2
|
|
224
|
+
}, {
|
|
225
|
+
"Id": "ParamEyeBallX",
|
|
226
|
+
"Min": -1.0,
|
|
227
|
+
"Max": 1.0,
|
|
228
|
+
"DefaultValue": 0.0,
|
|
229
|
+
"BlendMode": 1,
|
|
230
|
+
"Input": 1
|
|
231
|
+
}, {
|
|
232
|
+
"Id": "ParamEyeBallY",
|
|
233
|
+
"Min": -1.0,
|
|
234
|
+
"Max": 1.0,
|
|
235
|
+
"DefaultValue": 0.0,
|
|
236
|
+
"BlendMode": 1,
|
|
237
|
+
"Axis": 1,
|
|
238
|
+
"Input": 2
|
|
239
|
+
}],
|
|
240
|
+
"Enabled": true
|
|
241
|
+
},
|
|
242
|
+
"AutoBreath": {
|
|
243
|
+
"Enabled": true
|
|
244
|
+
},
|
|
245
|
+
"ExtraMotion": {
|
|
246
|
+
"Enabled": true
|
|
247
|
+
},
|
|
248
|
+
"Accelerometer": {
|
|
249
|
+
"Enabled": true
|
|
250
|
+
},
|
|
251
|
+
"Microphone": {},
|
|
252
|
+
"Transform": {},
|
|
253
|
+
"FaceTracking": {
|
|
254
|
+
"Enabled": true
|
|
255
|
+
},
|
|
256
|
+
"ParamValue": {},
|
|
257
|
+
"PartOpacity": {
|
|
258
|
+
"Items": [{
|
|
259
|
+
"Name": "猫耳",
|
|
260
|
+
"Ids": ["Part23", "weiba_Skinning"]
|
|
261
|
+
}, {
|
|
262
|
+
"Name": "墨镜",
|
|
263
|
+
"Ids": ["Part26"]
|
|
264
|
+
}],
|
|
265
|
+
"Enabled": true
|
|
266
|
+
},
|
|
267
|
+
"ArtmeshOpacity": {},
|
|
268
|
+
"ArtmeshColor": {},
|
|
269
|
+
"ArtmeshCulling": {
|
|
270
|
+
"DefaultMode": 0
|
|
271
|
+
},
|
|
272
|
+
"IntimacySystem": {}
|
|
273
|
+
},
|
|
274
|
+
"HitAreas": [{
|
|
275
|
+
"Name": "左手",
|
|
276
|
+
"Id": "ArtMesh2"
|
|
277
|
+
}, {
|
|
278
|
+
"Name": "右手",
|
|
279
|
+
"Id": "ArtMesh87"
|
|
280
|
+
}, {
|
|
281
|
+
"Name": "腰",
|
|
282
|
+
"Id": "yao"
|
|
283
|
+
}, {
|
|
284
|
+
"Name": "中间刘海",
|
|
285
|
+
"Id": "ArtMesh26"
|
|
286
|
+
}, {
|
|
287
|
+
"Name": "嘴",
|
|
288
|
+
"Id": "ArtMesh35"
|
|
289
|
+
}, {
|
|
290
|
+
"Name": "胸口项链",
|
|
291
|
+
"Id": "ArtMesh45"
|
|
292
|
+
}, {
|
|
293
|
+
"Name": "脖子",
|
|
294
|
+
"Id": "ArtMesh52"
|
|
295
|
+
}, {
|
|
296
|
+
"Name": " 右边头饰小花",
|
|
297
|
+
"Id": "hua2"
|
|
298
|
+
}, {
|
|
299
|
+
"Name": "右头饰",
|
|
300
|
+
"Id": "ArtMesh19"
|
|
301
|
+
}, {
|
|
302
|
+
"Name": "右眼",
|
|
303
|
+
"Id": "qiu"
|
|
304
|
+
}, {
|
|
305
|
+
"Name": "左眼",
|
|
306
|
+
"Id": "ArtMesh42"
|
|
307
|
+
}, {
|
|
308
|
+
"Name": "右马尾 ",
|
|
309
|
+
"Id": "R8"
|
|
310
|
+
}, {
|
|
311
|
+
"Name": "左马尾",
|
|
312
|
+
"Id": "L4"
|
|
313
|
+
}, {
|
|
314
|
+
"Name": "右手臂",
|
|
315
|
+
"Id": "ArtMesh48"
|
|
316
|
+
}, {
|
|
317
|
+
"Name": "左中马尾",
|
|
318
|
+
"Id": "L6"
|
|
319
|
+
}],
|
|
320
|
+
"Options": {
|
|
321
|
+
"TexFixed": true
|
|
322
|
+
}
|
|
323
|
+
}
|