@tnotesjs/core 0.2.2 → 0.3.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 +0 -1
- package/config/defaultConfig.ts +33 -4
- package/config/index.ts +6 -0
- package/core/NoteIndexCache.ts +7 -1
- package/core/NoteManager.ts +18 -30
- package/dist/{chunk-5Y5IYS6C.js → chunk-UJG3UU5X.js} +21 -5
- package/dist/{chunk-5QN44ES5.js → chunk-XCWFZLER.js} +48 -368
- package/dist/cli/index.js +26 -78
- package/dist/index.js +1 -1
- package/dist/vitepress/config/index.js +2 -2
- package/package.json +1 -1
- package/services/index.ts +0 -1
- package/services/init-sub-repo/initSubRepoLogic.ts +0 -1
- package/services/note/service.ts +0 -1
- package/types/config.ts +0 -3
- package/types/note.ts +0 -2
- package/vitepress/assets/icons/icon__cursor.svg +4 -0
- package/vitepress/assets/icons/index.ts +1 -0
- package/vitepress/components/Layout/AboutPanel.vue +0 -24
- package/vitepress/components/Layout/DocBeforeControls.vue +6 -14
- package/vitepress/components/Layout/DocFooter.vue +3 -3
- package/vitepress/components/Layout/Layout.vue +0 -30
- package/vitepress/components/Layout/composables/useVSCodeIntegration.ts +20 -11
- package/vitepress/components/Layout/homeReadme.data.ts +0 -48
- package/vitepress/components/MarkMap/MarkMap.vue +6 -13
- package/vitepress/components/Settings/Settings.vue +76 -73
- package/vitepress/components/SidebarCard/FolderTreeItems.vue +16 -6
- package/vitepress/components/SidebarCard/SidebarCard.vue +21 -27
- package/vitepress/components/composables/useLocalIde.ts +83 -0
- package/vitepress/components/constants.ts +5 -6
- package/vitepress/components/utils/vscodePaths.test.ts +22 -0
- package/vitepress/components/utils/vscodePaths.ts +24 -2
- package/vitepress/theme/styles/doc-layout.scss +4 -4
- package/services/timestamp/index.ts +0 -7
- package/services/timestamp/service.ts +0 -465
package/dist/cli/index.js
CHANGED
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
ROOT_TOC_PATH,
|
|
20
20
|
ReadmeService,
|
|
21
21
|
RenameNoteCommand,
|
|
22
|
-
TimestampService,
|
|
23
22
|
TocService,
|
|
24
23
|
UpdateNoteConfigCommand,
|
|
25
24
|
VitepressService,
|
|
@@ -42,11 +41,12 @@ import {
|
|
|
42
41
|
runCommand,
|
|
43
42
|
validatePort,
|
|
44
43
|
validateTopic
|
|
45
|
-
} from "../chunk-
|
|
44
|
+
} from "../chunk-XCWFZLER.js";
|
|
46
45
|
import {
|
|
47
46
|
ConfigManager,
|
|
48
|
-
getConfigManager
|
|
49
|
-
|
|
47
|
+
getConfigManager,
|
|
48
|
+
stripDeprecatedRootItemFields
|
|
49
|
+
} from "../chunk-UJG3UU5X.js";
|
|
50
50
|
|
|
51
51
|
// commands/update/UpdateCommand.ts
|
|
52
52
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -121,6 +121,9 @@ var UpdateCommand = class extends BaseCommand {
|
|
|
121
121
|
completed_notes_count: fixed
|
|
122
122
|
};
|
|
123
123
|
delete config.root_item.completed_notes_count_last_month;
|
|
124
|
+
stripDeprecatedRootItemFields(
|
|
125
|
+
config.root_item
|
|
126
|
+
);
|
|
124
127
|
writeFileSync(ROOT_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
|
|
125
128
|
if (!this.quiet) {
|
|
126
129
|
const filledCount = Object.keys(fixed).length - _countsBeforeFix;
|
|
@@ -192,7 +195,6 @@ var PushCommand = class extends BaseCommand {
|
|
|
192
195
|
super("push");
|
|
193
196
|
this.gitManager = new GitManager(ROOT_DIR_PATH);
|
|
194
197
|
this.gitService = new GitService();
|
|
195
|
-
this.timestampService = new TimestampService();
|
|
196
198
|
}
|
|
197
199
|
async run() {
|
|
198
200
|
try {
|
|
@@ -214,18 +216,6 @@ var PushCommand = class extends BaseCommand {
|
|
|
214
216
|
const commitMessage = this.gitService.generateCommitMessage();
|
|
215
217
|
await runCommand("git add -A", ROOT_DIR_PATH);
|
|
216
218
|
await runCommand(`git commit -m "${commitMessage}"`, ROOT_DIR_PATH);
|
|
217
|
-
this.logger.info("\u4FEE\u590D\u7B14\u8BB0\u65F6\u95F4\u6233...");
|
|
218
|
-
await this.timestampService.fixAllTimestamps(false);
|
|
219
|
-
const afterFixStatus = await runCommand(
|
|
220
|
-
"git -c core.quotePath=false status --porcelain",
|
|
221
|
-
ROOT_DIR_PATH
|
|
222
|
-
);
|
|
223
|
-
const hasTimestampChanges = afterFixStatus.split(/\r?\n/).filter(Boolean).some((line) => line.includes(".tnotes.json"));
|
|
224
|
-
if (hasTimestampChanges) {
|
|
225
|
-
this.logger.info("\u5C06\u65F6\u95F4\u6233\u53D8\u66F4\u5408\u5E76\u5230 commit...");
|
|
226
|
-
await runCommand("git add -u", ROOT_DIR_PATH);
|
|
227
|
-
await runCommand("git commit --amend --no-edit", ROOT_DIR_PATH);
|
|
228
|
-
}
|
|
229
219
|
} else {
|
|
230
220
|
this.logger.info(`\u68C0\u6D4B\u5230 ${status.ahead} \u4E2A\u672A\u63A8\u9001\u7684\u63D0\u4EA4\uFF0C\u76F4\u63A5\u63A8\u9001...`);
|
|
231
221
|
}
|
|
@@ -539,37 +529,6 @@ var InitTocCommand = class extends BaseCommand {
|
|
|
539
529
|
}
|
|
540
530
|
};
|
|
541
531
|
|
|
542
|
-
// commands/maintenance/FixTimestampsCommand.ts
|
|
543
|
-
var FixTimestampsCommand = class extends BaseCommand {
|
|
544
|
-
constructor() {
|
|
545
|
-
super("fix-timestamps");
|
|
546
|
-
this.timestampService = new TimestampService();
|
|
547
|
-
}
|
|
548
|
-
async run() {
|
|
549
|
-
this.logger.info("\u5F00\u59CB\u4FEE\u590D\u6240\u6709\u7B14\u8BB0\u7684\u65F6\u95F4\u6233...");
|
|
550
|
-
this.logger.info("\u{1F4CC} \u6B64\u64CD\u4F5C\u4F1A\u5C06\u6240\u6709\u65F6\u95F4\u6233\u66F4\u65B0\u4E3A git \u771F\u5B9E\u65F6\u95F4");
|
|
551
|
-
this.logger.info("");
|
|
552
|
-
const result = await this.timestampService.fixAllTimestamps(true);
|
|
553
|
-
this.logger.info("");
|
|
554
|
-
this.logger.info("\u{1F4CA} \u4FEE\u590D\u7EDF\u8BA1:");
|
|
555
|
-
this.logger.info(
|
|
556
|
-
` - \u6839\u914D\u7F6E\u6587\u4EF6: ${result.rootConfigFixed ? "\u5DF2\u4FEE\u590D" : "\u65E0\u9700\u4FEE\u590D"}`
|
|
557
|
-
);
|
|
558
|
-
this.logger.info(` - \u603B\u7B14\u8BB0\u6570: ${result.total}`);
|
|
559
|
-
this.logger.info(` - \u5DF2\u4FEE\u590D: ${result.fixed}`);
|
|
560
|
-
this.logger.info(` - \u8DF3\u8FC7: ${result.skipped}`);
|
|
561
|
-
this.logger.info("");
|
|
562
|
-
if (result.fixed > 0 || result.rootConfigFixed) {
|
|
563
|
-
this.logger.success(
|
|
564
|
-
`\u2705 \u6210\u529F\u4FEE\u590D ${result.fixed} \u4E2A\u7B14\u8BB0${result.rootConfigFixed ? " + \u6839\u914D\u7F6E\u6587\u4EF6" : ""}\u7684\u65F6\u95F4\u6233\uFF01`
|
|
565
|
-
);
|
|
566
|
-
this.logger.info("\u{1F4A1} \u63D0\u793A: \u8FD0\u884C pnpm tn:push \u63D0\u4EA4\u66F4\u6539");
|
|
567
|
-
} else {
|
|
568
|
-
this.logger.success("\u2705 \u6240\u6709\u65F6\u95F4\u6233\u5747\u5DF2\u6B63\u786E\uFF01");
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
};
|
|
572
|
-
|
|
573
532
|
// commands/misc/HelpCommand.ts
|
|
574
533
|
var COMMAND_CATEGORIES = {
|
|
575
534
|
\u5F00\u53D1\u548C\u6784\u5EFA: [COMMAND_NAMES.DEV, COMMAND_NAMES.BUILD, COMMAND_NAMES.PREVIEW],
|
|
@@ -581,7 +540,7 @@ var COMMAND_CATEGORIES = {
|
|
|
581
540
|
"Git \u64CD\u4F5C": [COMMAND_NAMES.PUSH, COMMAND_NAMES.PULL],
|
|
582
541
|
"\u8FC1\u79FB\uFF08v0.2.x \u8FC7\u6E21\uFF09": [COMMAND_NAMES.INIT_TOC],
|
|
583
542
|
\u521D\u59CB\u5316: [COMMAND_NAMES.INIT_SUB_REPO],
|
|
584
|
-
\u5176\u4ED6: [COMMAND_NAMES.
|
|
543
|
+
\u5176\u4ED6: [COMMAND_NAMES.HELP]
|
|
585
544
|
};
|
|
586
545
|
var COMMAND_OPTIONS_INFO = {
|
|
587
546
|
[COMMAND_OPTIONS.QUIET]: {
|
|
@@ -783,13 +742,14 @@ var UpdateCompletedCountCommand = class extends BaseCommand {
|
|
|
783
742
|
const configContent = readFileSync4(ROOT_CONFIG_PATH, "utf-8");
|
|
784
743
|
const config = JSON.parse(configContent);
|
|
785
744
|
this.logger.info("\u5F00\u59CB\u66F4\u65B0\u5B8C\u6210\u7B14\u8BB0\u6570\u91CF\u5386\u53F2\u8BB0\u5F55...");
|
|
786
|
-
const completedNotesCountHistory = await this.getCompletedNotesCountHistory(
|
|
787
|
-
config.root_item.created_at ?? Date.now()
|
|
788
|
-
);
|
|
745
|
+
const completedNotesCountHistory = await this.getCompletedNotesCountHistory();
|
|
789
746
|
config.root_item = {
|
|
790
747
|
...config.root_item,
|
|
791
748
|
completed_notes_count: completedNotesCountHistory
|
|
792
749
|
};
|
|
750
|
+
stripDeprecatedRootItemFields(
|
|
751
|
+
config.root_item
|
|
752
|
+
);
|
|
793
753
|
writeFileSync3(ROOT_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
|
|
794
754
|
const duration = Date.now() - startTime;
|
|
795
755
|
const monthKeys = Object.keys(completedNotesCountHistory);
|
|
@@ -812,10 +772,9 @@ var UpdateCompletedCountCommand = class extends BaseCommand {
|
|
|
812
772
|
* 1. 计算最近12个月的范围(当前月份往前推11个月)
|
|
813
773
|
* 2. 遍历这12个月,从 Git 历史中读取 TOC.md(回退 README.md)
|
|
814
774
|
* 3. 解析获取完成笔记数量
|
|
815
|
-
* 4.
|
|
816
|
-
* 5. 返回对象 { '25.01': 0, '25.02': 1, ..., '25.12': 15 }
|
|
775
|
+
* 4. 返回对象 { '25.01': 0, '25.02': 1, ..., '25.12': 15 }
|
|
817
776
|
*/
|
|
818
|
-
async getCompletedNotesCountHistory(
|
|
777
|
+
async getCompletedNotesCountHistory() {
|
|
819
778
|
try {
|
|
820
779
|
const now = /* @__PURE__ */ new Date();
|
|
821
780
|
const currentYear = now.getFullYear();
|
|
@@ -826,9 +785,6 @@ var UpdateCompletedCountCommand = class extends BaseCommand {
|
|
|
826
785
|
firstYear = currentYear - 1;
|
|
827
786
|
firstMonth = 12 + firstMonth;
|
|
828
787
|
}
|
|
829
|
-
const createdDate = new Date(createdAt);
|
|
830
|
-
const createdYear = createdDate.getFullYear();
|
|
831
|
-
const createdMonth = createdDate.getMonth();
|
|
832
788
|
const result = {};
|
|
833
789
|
let prevCount = 0;
|
|
834
790
|
for (let i = 0; i < 12; i++) {
|
|
@@ -837,25 +793,18 @@ var UpdateCompletedCountCommand = class extends BaseCommand {
|
|
|
837
793
|
const yearShort = String(targetYear).slice(-2);
|
|
838
794
|
const monthStr = String(targetMonth + 1).padStart(2, "0");
|
|
839
795
|
const key = `${yearShort}.${monthStr}`;
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
result[key] = count;
|
|
853
|
-
prevCount = count;
|
|
854
|
-
this.logger.info(`\u2713 ${key}: ${count} \u7BC7`);
|
|
855
|
-
} catch (error) {
|
|
856
|
-
result[key] = prevCount;
|
|
857
|
-
this.logger.warn(`${key}: \u65E0\u6570\u636E\uFF0C\u4F7F\u7528 ${prevCount}\uFF08\u4E0A\u6708\u503C\uFF09`);
|
|
858
|
-
}
|
|
796
|
+
try {
|
|
797
|
+
const count = await this.getMonthCompletedCount(
|
|
798
|
+
targetYear,
|
|
799
|
+
targetMonth,
|
|
800
|
+
prevCount
|
|
801
|
+
);
|
|
802
|
+
result[key] = count;
|
|
803
|
+
prevCount = count;
|
|
804
|
+
this.logger.info(`\u2713 ${key}: ${count} \u7BC7`);
|
|
805
|
+
} catch (error) {
|
|
806
|
+
result[key] = prevCount;
|
|
807
|
+
this.logger.warn(`${key}: \u65E0\u6570\u636E\uFF0C\u4F7F\u7528 ${prevCount}\uFF08\u4E0A\u6708\u503C\uFF09`);
|
|
859
808
|
}
|
|
860
809
|
}
|
|
861
810
|
return result;
|
|
@@ -919,7 +868,6 @@ var commandFactories = {
|
|
|
919
868
|
"build": () => new BuildCommand(),
|
|
920
869
|
"create-notes": () => new CreateNoteCommand(),
|
|
921
870
|
"dev": () => new DevCommand(),
|
|
922
|
-
"fix-timestamps": () => new FixTimestampsCommand(),
|
|
923
871
|
"init-sub-repo": () => new InitSubRepoCommand(),
|
|
924
872
|
"init-toc": () => new InitTocCommand(),
|
|
925
873
|
"help": () => new HelpCommand(),
|
package/dist/index.js
CHANGED
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
UpdateNoteConfigCommand,
|
|
8
8
|
generateAnchor,
|
|
9
9
|
logger
|
|
10
|
-
} from "../../chunk-
|
|
10
|
+
} from "../../chunk-XCWFZLER.js";
|
|
11
11
|
import {
|
|
12
12
|
ConfigManager
|
|
13
|
-
} from "../../chunk-
|
|
13
|
+
} from "../../chunk-UJG3UU5X.js";
|
|
14
14
|
|
|
15
15
|
// vitepress/config/index.ts
|
|
16
16
|
import fs3 from "fs";
|
package/package.json
CHANGED
package/services/index.ts
CHANGED
|
@@ -9,7 +9,6 @@ export { GitService } from './git'
|
|
|
9
9
|
export { NoteService } from './note'
|
|
10
10
|
export { ReadmeService } from './readme'
|
|
11
11
|
export { TocService } from './toc'
|
|
12
|
-
export { TimestampService } from './timestamp'
|
|
13
12
|
export { VitepressService } from './vitepress'
|
|
14
13
|
export { InitSubRepoService } from './init-sub-repo'
|
|
15
14
|
export * from './init-sub-repo/initSubRepoLogic'
|
|
@@ -189,7 +189,6 @@ export function buildPackageJsonTemplate(
|
|
|
189
189
|
'tn:build': 'tnotes --build',
|
|
190
190
|
'tn:create-notes': 'tnotes --create-notes',
|
|
191
191
|
'tn:dev': 'tnotes --dev',
|
|
192
|
-
'tn:fix-timestamps': 'tnotes --fix-timestamps',
|
|
193
192
|
'tn:help': 'tnotes --help',
|
|
194
193
|
'tn:init-sub-repo': 'tnotes --init-sub-repo',
|
|
195
194
|
'tn:preview': 'tnotes --preview',
|
package/services/note/service.ts
CHANGED
package/types/config.ts
CHANGED
package/types/note.ts
CHANGED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 128 128">
|
|
2
|
+
<path d="M0 0h128v128H0z" fill="none" />
|
|
3
|
+
<path fill="#656cff" fill-rule="evenodd" d="M117.9 30.289L66.664.713a5.32 5.32 0 0 0-5.323 0L10.09 30.29a4.48 4.48 0 0 0-2.234 3.872v59.663c0 1.6.853 3.077 2.24 3.878l51.24 29.586a5.33 5.33 0 0 0 5.324 0l51.246-29.586a4.48 4.48 0 0 0 2.24-3.878V34.166a4.48 4.48 0 0 0-2.24-3.872zm-3.216 6.272l-49.47 85.681c-.337.576-1.217.341-1.217-.325V65.81a3.15 3.15 0 0 0-1.573-2.72l-48.59-28.055c-.571-.331-.336-1.216.33-1.216h98.94c1.409 0 2.284 1.525 1.58 2.741" />
|
|
4
|
+
</svg>
|
|
@@ -14,6 +14,7 @@ export { default as icon__close } from './icon__close.svg'
|
|
|
14
14
|
export { default as icon__collapse } from './icon__collapse.svg'
|
|
15
15
|
export { default as icon__confirm } from './icon__confirm.svg'
|
|
16
16
|
export { default as icon__copy } from './icon__copy.svg'
|
|
17
|
+
export { default as icon__cursor } from './icon__cursor.svg'
|
|
17
18
|
export { default as icon__focus } from './icon__focus.svg'
|
|
18
19
|
export { default as icon__fold } from './icon__fold.svg'
|
|
19
20
|
export { default as icon__folder } from './icon__folder.svg'
|
|
@@ -107,22 +107,6 @@ vitepress/components/Layout/AboutPanel.vue
|
|
|
107
107
|
</div>
|
|
108
108
|
</div>
|
|
109
109
|
|
|
110
|
-
<!-- 首次提交时间 -->
|
|
111
|
-
<div class="timeLine" title="首次提交时间">
|
|
112
|
-
<div class="timeLabel"><strong>⌛️ 首次提交</strong></div>
|
|
113
|
-
<div class="timeValue">
|
|
114
|
-
{{ formatOptionalDate(modalCreatedAt) }}
|
|
115
|
-
</div>
|
|
116
|
-
</div>
|
|
117
|
-
|
|
118
|
-
<!-- 最近提交时间 -->
|
|
119
|
-
<div class="timeLine" title="最近提交时间">
|
|
120
|
-
<div class="timeLabel"><strong>⌛️ 最近提交</strong></div>
|
|
121
|
-
<div class="timeValue">
|
|
122
|
-
{{ formatOptionalDate(modalUpdatedAt) }}
|
|
123
|
-
</div>
|
|
124
|
-
</div>
|
|
125
|
-
|
|
126
110
|
<!-- GitHub -->
|
|
127
111
|
<div
|
|
128
112
|
class="timeLine"
|
|
@@ -196,8 +180,6 @@ vitepress/components/Layout/AboutPanel.vue
|
|
|
196
180
|
<script setup lang="ts">
|
|
197
181
|
import { computed } from 'vue'
|
|
198
182
|
|
|
199
|
-
import { formatDate } from '../utils'
|
|
200
|
-
|
|
201
183
|
const props = defineProps<{
|
|
202
184
|
isHomeReadme: boolean
|
|
203
185
|
currentNoteId: string | null
|
|
@@ -207,8 +189,6 @@ const props = defineProps<{
|
|
|
207
189
|
editableNoteStatus: boolean
|
|
208
190
|
editableDiscussionsEnabled: boolean
|
|
209
191
|
titleError: string
|
|
210
|
-
modalCreatedAt: number | undefined
|
|
211
|
-
modalUpdatedAt: number | undefined
|
|
212
192
|
modalGithubUrl: string
|
|
213
193
|
modalGithubPageUrl: string
|
|
214
194
|
completionPercentage: number | null
|
|
@@ -263,10 +243,6 @@ function onDescriptionInput() {
|
|
|
263
243
|
function onConfigChange() {
|
|
264
244
|
emit('configChange')
|
|
265
245
|
}
|
|
266
|
-
|
|
267
|
-
function formatOptionalDate(timestamp: number | undefined) {
|
|
268
|
-
return timestamp === undefined ? '-' : formatDate(timestamp)
|
|
269
|
-
}
|
|
270
246
|
</script>
|
|
271
247
|
|
|
272
248
|
<style scoped lang="scss">
|
|
@@ -14,10 +14,10 @@ vitepress/components/Layout/DocBeforeControls.vue
|
|
|
14
14
|
<div class="vscodeBox pcOnly" v-show="vscodeNotesDir">
|
|
15
15
|
<a
|
|
16
16
|
:href="vscodeNotesDir"
|
|
17
|
-
title="
|
|
17
|
+
:title="openCurrentTitle"
|
|
18
18
|
target="_blank"
|
|
19
19
|
>
|
|
20
|
-
<img :src="
|
|
20
|
+
<img :src="localIdeIcon" :alt="openCurrentTitle" />
|
|
21
21
|
</a>
|
|
22
22
|
</div>
|
|
23
23
|
<div class="contentToggleBox pcOnly">
|
|
@@ -65,13 +65,7 @@ vitepress/components/Layout/DocBeforeControls.vue
|
|
|
65
65
|
</button>
|
|
66
66
|
</div>
|
|
67
67
|
<!-- 单个图标,点击打开 modal,只在有笔记数据的页面显示 -->
|
|
68
|
-
<div
|
|
69
|
-
class="aboutBtn"
|
|
70
|
-
v-show="
|
|
71
|
-
(currentNoteId && created_at && updated_at) ||
|
|
72
|
-
(isHomeReadme && homeReadmeCreatedAt && homeReadmeUpdatedAt)
|
|
73
|
-
"
|
|
74
|
-
>
|
|
68
|
+
<div class="aboutBtn" v-show="currentNoteId || isHomeReadme">
|
|
75
69
|
<button
|
|
76
70
|
class="aboutIconButton"
|
|
77
71
|
@click="$emit('open-time-modal')"
|
|
@@ -93,24 +87,22 @@ import ToggleFullContent from './ToggleFullContent.vue'
|
|
|
93
87
|
import ToggleSidebar from './ToggleSidebar.vue'
|
|
94
88
|
import {
|
|
95
89
|
icon__github,
|
|
96
|
-
icon__vscode,
|
|
97
90
|
icon__fold,
|
|
98
91
|
icon__clipboard,
|
|
99
92
|
} from '../../assets/icons'
|
|
93
|
+
import { useLocalIde } from '../composables/useLocalIde'
|
|
100
94
|
|
|
101
95
|
const props = defineProps<{
|
|
102
96
|
isFullContentMode: boolean
|
|
103
97
|
vscodeNotesDir: string
|
|
104
98
|
isHomeReadme: boolean
|
|
105
99
|
currentNoteId: string | null
|
|
106
|
-
created_at: string | undefined
|
|
107
|
-
updated_at: string | undefined
|
|
108
|
-
homeReadmeCreatedAt: string | undefined
|
|
109
|
-
homeReadmeUpdatedAt: string | undefined
|
|
110
100
|
timeModalOpen: boolean
|
|
111
101
|
allCollapsed: boolean
|
|
112
102
|
}>()
|
|
113
103
|
|
|
104
|
+
const { icon: localIdeIcon, openCurrentTitle } = useLocalIde()
|
|
105
|
+
|
|
114
106
|
const showCopyToast = ref(false)
|
|
115
107
|
let copyToastTimer: ReturnType<typeof setTimeout> | null = null
|
|
116
108
|
|
|
@@ -4,7 +4,7 @@ vitepress/components/Layout/DocFooter.vue
|
|
|
4
4
|
|
|
5
5
|
<template>
|
|
6
6
|
<nav class="custom-doc-footer" v-if="prev || next">
|
|
7
|
-
<div class="container">
|
|
7
|
+
<div class="pager-container">
|
|
8
8
|
<div class="prev">
|
|
9
9
|
<a v-if="prev" :href="prev.link" class="pager-link prev-link">
|
|
10
10
|
<span class="desc">上一篇</span>
|
|
@@ -147,7 +147,7 @@ const next = computed(() => {
|
|
|
147
147
|
padding-top: 32px;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
.container {
|
|
150
|
+
.pager-container {
|
|
151
151
|
display: flex;
|
|
152
152
|
gap: 16px;
|
|
153
153
|
}
|
|
@@ -219,7 +219,7 @@ const next = computed(() => {
|
|
|
219
219
|
|
|
220
220
|
/* 响应式调整 */
|
|
221
221
|
@media (max-width: 768px) {
|
|
222
|
-
.container {
|
|
222
|
+
.pager-container {
|
|
223
223
|
flex-direction: column;
|
|
224
224
|
gap: 12px;
|
|
225
225
|
}
|
|
@@ -32,10 +32,6 @@ vitepress/components/Layout/Layout.vue
|
|
|
32
32
|
:vscode-notes-dir="vscodeNotesDir"
|
|
33
33
|
:is-home-readme="isHomeReadme"
|
|
34
34
|
:current-note-id="currentNoteId"
|
|
35
|
-
:created_at="created_at"
|
|
36
|
-
:updated_at="updated_at"
|
|
37
|
-
:home-readme-created-at="homeReadmeCreatedAt"
|
|
38
|
-
:home-readme-updated-at="homeReadmeUpdatedAt"
|
|
39
35
|
:time-modal-open="timeModalOpen"
|
|
40
36
|
:all-collapsed="allCollapsed"
|
|
41
37
|
@open-time-modal="openTimeModal"
|
|
@@ -65,8 +61,6 @@ vitepress/components/Layout/Layout.vue
|
|
|
65
61
|
v-model:editable-note-status="editableNoteStatus"
|
|
66
62
|
v-model:editable-discussions-enabled="editableDiscussionsEnabled"
|
|
67
63
|
v-model:title-error="titleError"
|
|
68
|
-
:modal-created-at="modalCreatedAt"
|
|
69
|
-
:modal-updated-at="modalUpdatedAt"
|
|
70
64
|
:modal-github-url="modalGithubUrl"
|
|
71
65
|
:modal-github-page-url="modalGithubPageUrl"
|
|
72
66
|
:completion-percentage="completionPercentage"
|
|
@@ -116,10 +110,6 @@ vitepress/components/Layout/Layout.vue
|
|
|
116
110
|
</AboutModal>
|
|
117
111
|
</template>
|
|
118
112
|
<template #doc-footer-before>
|
|
119
|
-
<!-- <div class="footer-time-info">
|
|
120
|
-
<p title="首次提交时间">首次提交时间:{{ formatDate(created_at) }}</p>
|
|
121
|
-
<p title="最近提交时间">最近提交时间:{{ formatDate(updated_at) }}</p>
|
|
122
|
-
</div> -->
|
|
123
113
|
</template>
|
|
124
114
|
<template #doc-after>
|
|
125
115
|
<!-- 自定义 DocFooter -->
|
|
@@ -335,8 +325,6 @@ function getEmptyNoteConfig() {
|
|
|
335
325
|
const isDiscussionsVisible = computed(
|
|
336
326
|
() => currentNoteConfig.value.enableDiscussions,
|
|
337
327
|
);
|
|
338
|
-
const updated_at = computed(() => currentNoteConfig.value.updated_at);
|
|
339
|
-
const created_at = computed(() => currentNoteConfig.value.created_at);
|
|
340
328
|
|
|
341
329
|
// 判断是否为首页 README.md
|
|
342
330
|
const isHomeReadme = computed(() => vpData.page.value.filePath === "README.md");
|
|
@@ -349,10 +337,6 @@ const completionPercentage = computed(() => {
|
|
|
349
337
|
return Math.round((doneNotesLen.value / totalNotesLen.value) * 100);
|
|
350
338
|
});
|
|
351
339
|
|
|
352
|
-
// 首页 README.md 的时间戳
|
|
353
|
-
const homeReadmeCreatedAt = computed(() => readmeData?.created_at);
|
|
354
|
-
const homeReadmeUpdatedAt = computed(() => readmeData?.updated_at);
|
|
355
|
-
|
|
356
340
|
// #region - Composables
|
|
357
341
|
// 404 重定向
|
|
358
342
|
const { showNotFound, decodedCurrentPath, initRedirectCheck } =
|
|
@@ -509,20 +493,6 @@ const modalGithubPageUrl = computed(() => {
|
|
|
509
493
|
return "";
|
|
510
494
|
});
|
|
511
495
|
|
|
512
|
-
// modal 中显示的创建时间
|
|
513
|
-
const modalCreatedAt = computed(() => {
|
|
514
|
-
return modalIsHomeReadme.value
|
|
515
|
-
? homeReadmeCreatedAt.value
|
|
516
|
-
: modalNoteConfig.value.created_at;
|
|
517
|
-
});
|
|
518
|
-
|
|
519
|
-
// modal 中显示的更新时间
|
|
520
|
-
const modalUpdatedAt = computed(() => {
|
|
521
|
-
return modalIsHomeReadme.value
|
|
522
|
-
? homeReadmeUpdatedAt.value
|
|
523
|
-
: modalNoteConfig.value.updated_at;
|
|
524
|
-
});
|
|
525
|
-
|
|
526
496
|
function openTimeModal() {
|
|
527
497
|
sidebarAboutNoteId.value = null;
|
|
528
498
|
timeModalOpen.value = true;
|
|
@@ -1,40 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* vitepress/components/Layout/composables/useVSCodeIntegration.ts
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 本地 IDE 集成和 GitHub 链接拦截
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { useData } from 'vitepress'
|
|
8
|
-
import { ref } from 'vue'
|
|
8
|
+
import { computed, ref, watch } from 'vue'
|
|
9
9
|
|
|
10
|
+
import { useLocalIde } from '../../composables/useLocalIde'
|
|
10
11
|
import { NOTES_DIR_KEY } from '../../constants'
|
|
11
|
-
import {
|
|
12
|
-
resolveNoteReadmePath,
|
|
13
|
-
toVscodeFileUrl,
|
|
14
|
-
} from '../../utils/vscodePaths'
|
|
12
|
+
import { resolveNoteReadmePath, toIdeFileUrl } from '../../utils/vscodePaths'
|
|
15
13
|
|
|
16
14
|
import type { Router } from 'vitepress'
|
|
17
15
|
import type { Ref, ComputedRef } from 'vue'
|
|
18
16
|
|
|
19
|
-
|
|
20
17
|
/**
|
|
21
|
-
*
|
|
18
|
+
* 本地 IDE 集成和 GitHub 链接拦截
|
|
22
19
|
*/
|
|
23
20
|
export function useVSCodeIntegration() {
|
|
24
21
|
const vpData = useData()
|
|
25
|
-
const
|
|
22
|
+
const { ide } = useLocalIde()
|
|
23
|
+
const noteLocalPath = ref('')
|
|
24
|
+
|
|
25
|
+
const vscodeNotesDir = computed(() => {
|
|
26
|
+
if (!noteLocalPath.value) return ''
|
|
27
|
+
// 显式依赖 ide,确保切换 IDE 后 href 更新
|
|
28
|
+
return toIdeFileUrl(noteLocalPath.value, ide.value)
|
|
29
|
+
})
|
|
26
30
|
|
|
27
|
-
//
|
|
31
|
+
// 更新当前页面对应的本地笔记路径
|
|
28
32
|
const updateVscodeNoteDir = () => {
|
|
29
33
|
if (typeof window !== 'undefined') {
|
|
30
34
|
const notesDir = localStorage.getItem(NOTES_DIR_KEY)
|
|
31
35
|
const notePath = notesDir
|
|
32
36
|
? resolveNoteReadmePath(notesDir, vpData.page.value.relativePath)
|
|
33
37
|
: null
|
|
34
|
-
|
|
38
|
+
noteLocalPath.value = notePath || ''
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
41
|
|
|
42
|
+
watch(ide, () => {
|
|
43
|
+
// IDE 切换后重新解析路径(无需刷新页面)
|
|
44
|
+
updateVscodeNoteDir()
|
|
45
|
+
})
|
|
46
|
+
|
|
38
47
|
// 拦截 home README 中的笔记链接,将 GitHub 链接转换为站点内跳转
|
|
39
48
|
const interceptHomeReadmeLinks = (
|
|
40
49
|
isHomeReadme: Ref<boolean> | ComputedRef<boolean>,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* vitepress/components/Layout/homeReadme.data.ts
|
|
3
3
|
*/
|
|
4
|
-
import { execSync } from 'node:child_process'
|
|
5
4
|
import fs from 'node:fs'
|
|
6
5
|
import path from 'node:path'
|
|
7
6
|
|
|
@@ -12,8 +11,6 @@ interface ReadmeData {
|
|
|
12
11
|
doneNotesID: string[]
|
|
13
12
|
doneNotesLen: number
|
|
14
13
|
totalNotesLen: number
|
|
15
|
-
created_at?: number
|
|
16
|
-
updated_at?: number
|
|
17
14
|
}
|
|
18
15
|
|
|
19
16
|
export default {
|
|
@@ -28,15 +25,10 @@ export default {
|
|
|
28
25
|
|
|
29
26
|
watchedFiles.forEach((file) => {
|
|
30
27
|
if (file.endsWith('README.md')) {
|
|
31
|
-
// console.log('file:', file) // => file: README.md
|
|
32
|
-
|
|
33
28
|
const fileContent = fs.readFileSync(file, 'utf-8')
|
|
34
29
|
const doneNotesID = getDoneNotesID(fileContent)
|
|
35
30
|
const doneNotesLen = doneNotesID.length
|
|
36
31
|
|
|
37
|
-
// 获取 git 仓库的时间戳
|
|
38
|
-
const timestamps = getGitTimestamps()
|
|
39
|
-
|
|
40
32
|
// 计算总笔记数
|
|
41
33
|
const notesDir = path.join(path.dirname(file), 'notes')
|
|
42
34
|
const totalNotesLen = getTotalNotesCount(notesDir)
|
|
@@ -46,7 +38,6 @@ export default {
|
|
|
46
38
|
doneNotesID,
|
|
47
39
|
doneNotesLen,
|
|
48
40
|
totalNotesLen,
|
|
49
|
-
...timestamps,
|
|
50
41
|
}
|
|
51
42
|
}
|
|
52
43
|
})
|
|
@@ -74,45 +65,6 @@ function getTotalNotesCount(notesDir: string): number {
|
|
|
74
65
|
}
|
|
75
66
|
}
|
|
76
67
|
|
|
77
|
-
/**
|
|
78
|
-
* 获取 git 仓库的时间戳
|
|
79
|
-
* @returns 包含 created_at 和 updated_at 的对象
|
|
80
|
-
*/
|
|
81
|
-
function getGitTimestamps(): {
|
|
82
|
-
created_at?: number
|
|
83
|
-
updated_at?: number
|
|
84
|
-
} {
|
|
85
|
-
const now = Date.now()
|
|
86
|
-
let created_at = now
|
|
87
|
-
let updated_at = now
|
|
88
|
-
|
|
89
|
-
try {
|
|
90
|
-
// 仓库的首次提交时间(最早的提交)
|
|
91
|
-
// 先获取所有提交,然后取第一行
|
|
92
|
-
const createdStdout = execSync(`git log --reverse --format=%ct`, {
|
|
93
|
-
encoding: 'utf-8',
|
|
94
|
-
})
|
|
95
|
-
const createdTs = createdStdout.toString().trim().split('\n')[0]
|
|
96
|
-
if (createdTs) {
|
|
97
|
-
created_at = parseInt(createdTs, 10) * 1000
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// 仓库的最近一次提交时间
|
|
101
|
-
const updatedStdout = execSync(`git log -1 --format=%ct`, {
|
|
102
|
-
encoding: 'utf-8',
|
|
103
|
-
})
|
|
104
|
-
const updatedTs = updatedStdout.toString().trim()
|
|
105
|
-
if (updatedTs) {
|
|
106
|
-
updated_at = parseInt(updatedTs, 10) * 1000
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return { created_at, updated_at }
|
|
110
|
-
} catch (error) {
|
|
111
|
-
console.error(`获取 git 仓库时间戳失败:`, error)
|
|
112
|
-
return { created_at, updated_at }
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
68
|
/**
|
|
117
69
|
* 返回已完成的笔记的 ID 列表
|
|
118
70
|
* @param fileContent 文件内容
|