@tnotesjs/core 0.0.7 → 0.1.14
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 +6 -3
- package/dist/{chunk-JDVN2QYW.js → chunk-FVKQPBPP.js} +643 -546
- package/dist/{chunk-NASIL5FY.js → chunk-SQVHJR2Z.js} +0 -4
- package/dist/cli/index.js +126 -126
- package/dist/index.js +1 -1
- package/dist/vitepress/config/index.js +229 -208
- package/package.json +16 -3
- package/types/shims.d.ts +3 -4
- package/vitepress/components/CodeBlockFullscreen/CodeBlockFullscreen.vue +2 -1
- package/vitepress/components/CodeBlockFullscreen/index.ts +2 -1
- package/vitepress/components/Discussions/Discussions.vue +3 -2
- package/vitepress/components/EnWordList/EnWordList.vue +2 -1
- package/vitepress/components/Layout/AboutModal.vue +1 -1
- package/vitepress/components/Layout/AboutPanel.vue +8 -3
- package/vitepress/components/Layout/ContentCollapse.vue +2 -1
- package/vitepress/components/Layout/CustomSidebar.vue +7 -4
- package/vitepress/components/Layout/DocBeforeControls.vue +4 -4
- package/vitepress/components/Layout/DocFooter.vue +2 -1
- package/vitepress/components/Layout/ImagePreview.vue +2 -1
- package/vitepress/components/Layout/Layout.vue +38 -20
- package/vitepress/components/Layout/NoteStatus.vue +2 -1
- package/vitepress/components/Layout/SidebarItems.vue +7 -2
- package/vitepress/components/Layout/SidebarNavBefore.vue +22 -0
- package/vitepress/components/Layout/ToggleFullContent.vue +2 -1
- package/vitepress/components/Layout/ToggleSidebar.vue +2 -1
- package/vitepress/components/Layout/composables/useCollapseControl.ts +1 -1
- package/vitepress/components/Layout/composables/useNoteConfig.ts +2 -4
- package/vitepress/components/Layout/composables/useNoteSave.ts +23 -18
- package/vitepress/components/Layout/composables/useRedirect.ts +8 -5
- package/vitepress/components/Layout/composables/useRenameOverlay.ts +33 -0
- package/vitepress/components/Layout/composables/useRenameRedirect.ts +59 -0
- package/vitepress/components/Layout/composables/useVSCodeIntegration.ts +7 -4
- package/vitepress/components/Layout/homeReadme.data.ts +1 -1
- package/vitepress/components/LoadingPage/LoadingPage.vue +84 -192
- package/vitepress/components/MarkMap/MarkMap.vue +5 -4
- package/vitepress/components/Mermaid/Mermaid.vue +4 -2
- package/vitepress/components/NotesTable/NotesTable.vue +2 -1
- package/vitepress/components/Settings/Settings.vue +2 -1
- package/vitepress/components/Settings/SettingsDialog.vue +243 -0
- package/vitepress/components/Settings/composables/useSettingsDialog.ts +35 -0
- package/vitepress/components/SidebarCard/MindMapView.vue +10 -9
- package/vitepress/components/SidebarCard/SidebarCard.vue +12 -14
- package/vitepress/config/index.ts +11 -4
- package/vitepress/configs/head.config.ts +2 -1
- package/vitepress/configs/markdown-it.d.ts +6 -3
- package/vitepress/configs/markdown.config.ts +6 -5
- package/vitepress/configs/theme.config.ts +1 -1
- package/vitepress/plugins/buildProgressPlugin.ts +2 -38
- package/vitepress/plugins/fileWatcherBridgePlugin.ts +49 -0
- package/vitepress/plugins/getNoteByConfigIdPlugin.ts +3 -2
- package/vitepress/plugins/renameNotePlugin.ts +9 -1
- package/vitepress/plugins/updateConfigPlugin.ts +2 -1
- package/vitepress/theme/index.ts +45 -3
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
UpdateNoteConfigCommand,
|
|
5
5
|
generateAnchor,
|
|
6
6
|
logger
|
|
7
|
-
} from "../../chunk-
|
|
8
|
-
import "../../chunk-
|
|
7
|
+
} from "../../chunk-FVKQPBPP.js";
|
|
8
|
+
import "../../chunk-SQVHJR2Z.js";
|
|
9
9
|
|
|
10
10
|
// vitepress/config/index.ts
|
|
11
11
|
import fs2 from "fs";
|
|
@@ -39,10 +39,10 @@ function getHeadConfig(config, githubPageUrl) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// vitepress/configs/markdown.config.ts
|
|
42
|
+
import fs from "fs";
|
|
42
43
|
import markdownItContainer from "markdown-it-container";
|
|
43
44
|
import mila from "markdown-it-link-attributes";
|
|
44
45
|
import markdownItTaskLists from "markdown-it-task-lists";
|
|
45
|
-
import fs from "fs";
|
|
46
46
|
import path from "path";
|
|
47
47
|
function esc(s = "") {
|
|
48
48
|
return s.replace(
|
|
@@ -100,7 +100,7 @@ function configureMarkMapContainer(md) {
|
|
|
100
100
|
const open = t;
|
|
101
101
|
const startLine = open.map ? open.map[0] + 1 : null;
|
|
102
102
|
const endLine = open.map ? open.map[1] - 1 : null;
|
|
103
|
-
|
|
103
|
+
const params = {};
|
|
104
104
|
if (open.map && typeof open.map[0] === "number") {
|
|
105
105
|
const openLine = (lines[open.map[0]] || "").trim();
|
|
106
106
|
let paramPart = "";
|
|
@@ -150,7 +150,7 @@ function configureMarkMapContainer(md) {
|
|
|
150
150
|
const firstNonEmptyLine = (content || "").split("\n").find((ln) => ln.trim() !== "") || "";
|
|
151
151
|
const refMatch = firstNonEmptyLine.trim().match(/^<<<\s*(.+)$/);
|
|
152
152
|
if (refMatch) {
|
|
153
|
-
|
|
153
|
+
const refRaw = refMatch[1].trim().replace(/^['"]|['"]$/g, "");
|
|
154
154
|
try {
|
|
155
155
|
const env = state.env || {};
|
|
156
156
|
const possibleRel = env.relativePath || env.path || env.filePath || env.file || "";
|
|
@@ -383,190 +383,12 @@ function getThemeConfig(config) {
|
|
|
383
383
|
return themeConfig;
|
|
384
384
|
}
|
|
385
385
|
|
|
386
|
-
// vitepress/plugins/updateConfigPlugin.ts
|
|
387
|
-
function updateConfigPlugin() {
|
|
388
|
-
let updateCommand;
|
|
389
|
-
return {
|
|
390
|
-
name: "tnotes-update-config",
|
|
391
|
-
configureServer(server) {
|
|
392
|
-
updateCommand = new UpdateNoteConfigCommand();
|
|
393
|
-
server.middlewares.use(async (req, res, next) => {
|
|
394
|
-
if (req.url === "/__tnotes_update_config" && req.method === "POST") {
|
|
395
|
-
let body = "";
|
|
396
|
-
req.on("data", (chunk) => {
|
|
397
|
-
body += chunk.toString();
|
|
398
|
-
});
|
|
399
|
-
req.on("end", async () => {
|
|
400
|
-
try {
|
|
401
|
-
const data = JSON.parse(body);
|
|
402
|
-
const { noteIndex, config } = data;
|
|
403
|
-
if (!noteIndex || !config) {
|
|
404
|
-
res.statusCode = 400;
|
|
405
|
-
res.end("Missing noteIndex or config");
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
await updateCommand.updateConfig({
|
|
409
|
-
noteIndex,
|
|
410
|
-
config: {
|
|
411
|
-
done: config.done,
|
|
412
|
-
enableDiscussions: config.enableDiscussions,
|
|
413
|
-
description: config.description
|
|
414
|
-
}
|
|
415
|
-
});
|
|
416
|
-
res.statusCode = 200;
|
|
417
|
-
res.setHeader("Content-Type", "application/json");
|
|
418
|
-
res.end(JSON.stringify({ success: true }));
|
|
419
|
-
} catch (error) {
|
|
420
|
-
console.error("\u66F4\u65B0\u914D\u7F6E\u5931\u8D25:", error);
|
|
421
|
-
res.statusCode = 500;
|
|
422
|
-
res.end(error instanceof Error ? error.message : String(error));
|
|
423
|
-
}
|
|
424
|
-
});
|
|
425
|
-
} else {
|
|
426
|
-
next();
|
|
427
|
-
}
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// vitepress/plugins/renameNotePlugin.ts
|
|
434
|
-
function renameNotePlugin() {
|
|
435
|
-
const renameCommand = new RenameNoteCommand();
|
|
436
|
-
return {
|
|
437
|
-
name: "tnotes-rename-note",
|
|
438
|
-
configureServer(server) {
|
|
439
|
-
server.middlewares.use(async (req, res, next) => {
|
|
440
|
-
if (req.url === "/__tnotes_rename_note" && req.method === "POST") {
|
|
441
|
-
let body = "";
|
|
442
|
-
req.on("data", (chunk) => {
|
|
443
|
-
body += chunk.toString();
|
|
444
|
-
});
|
|
445
|
-
req.on("end", async () => {
|
|
446
|
-
try {
|
|
447
|
-
const { noteIndex, newTitle } = JSON.parse(body);
|
|
448
|
-
if (!noteIndex || !newTitle) {
|
|
449
|
-
res.statusCode = 400;
|
|
450
|
-
res.end("Missing noteIndex or newTitle");
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
const startTime = Date.now();
|
|
454
|
-
await renameCommand.renameNote({ noteIndex, newTitle });
|
|
455
|
-
const duration = Date.now() - startTime;
|
|
456
|
-
res.statusCode = 200;
|
|
457
|
-
res.setHeader("Content-Type", "application/json");
|
|
458
|
-
res.end(
|
|
459
|
-
JSON.stringify({
|
|
460
|
-
success: true,
|
|
461
|
-
duration,
|
|
462
|
-
newTitle,
|
|
463
|
-
message: "\u91CD\u547D\u540D\u5B8C\u6210"
|
|
464
|
-
})
|
|
465
|
-
);
|
|
466
|
-
} catch (error) {
|
|
467
|
-
res.statusCode = 500;
|
|
468
|
-
res.end(error instanceof Error ? error.message : "Rename failed");
|
|
469
|
-
}
|
|
470
|
-
});
|
|
471
|
-
} else {
|
|
472
|
-
next();
|
|
473
|
-
}
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// vitepress/plugins/getNoteByConfigIdPlugin.ts
|
|
480
|
-
function getNoteByConfigIdPlugin() {
|
|
481
|
-
return {
|
|
482
|
-
name: "tnotes-get-note-by-config-id",
|
|
483
|
-
configureServer(server) {
|
|
484
|
-
server.middlewares.use(async (req, res, next) => {
|
|
485
|
-
if (req.url?.startsWith("/__tnotes_get_note?") && req.method === "GET") {
|
|
486
|
-
try {
|
|
487
|
-
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
488
|
-
const configId = url.searchParams.get("configId");
|
|
489
|
-
if (!configId) {
|
|
490
|
-
res.statusCode = 400;
|
|
491
|
-
res.setHeader("Content-Type", "application/json");
|
|
492
|
-
res.end(
|
|
493
|
-
JSON.stringify({
|
|
494
|
-
success: false,
|
|
495
|
-
error: "Missing configId parameter"
|
|
496
|
-
})
|
|
497
|
-
);
|
|
498
|
-
return;
|
|
499
|
-
}
|
|
500
|
-
const noteIndexCache = NoteIndexCache.getInstance();
|
|
501
|
-
if (!noteIndexCache.isInitialized()) {
|
|
502
|
-
res.statusCode = 503;
|
|
503
|
-
res.setHeader("Content-Type", "application/json");
|
|
504
|
-
res.end(
|
|
505
|
-
JSON.stringify({
|
|
506
|
-
success: false,
|
|
507
|
-
error: "Service not initialized"
|
|
508
|
-
})
|
|
509
|
-
);
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
|
-
const noteItem = noteIndexCache.getByConfigId(configId);
|
|
513
|
-
if (!noteItem) {
|
|
514
|
-
res.statusCode = 200;
|
|
515
|
-
res.setHeader("Content-Type", "application/json");
|
|
516
|
-
res.end(
|
|
517
|
-
JSON.stringify({
|
|
518
|
-
success: true,
|
|
519
|
-
found: false,
|
|
520
|
-
data: null
|
|
521
|
-
})
|
|
522
|
-
);
|
|
523
|
-
return;
|
|
524
|
-
}
|
|
525
|
-
res.statusCode = 200;
|
|
526
|
-
res.setHeader("Content-Type", "application/json");
|
|
527
|
-
res.end(
|
|
528
|
-
JSON.stringify({
|
|
529
|
-
success: true,
|
|
530
|
-
found: true,
|
|
531
|
-
data: {
|
|
532
|
-
noteIndex: noteItem.noteIndex,
|
|
533
|
-
folderName: noteItem.folderName,
|
|
534
|
-
// 构建笔记的完整 URL(包含 README)
|
|
535
|
-
url: `/notes/${encodeURIComponent(
|
|
536
|
-
noteItem.folderName
|
|
537
|
-
)}/README`
|
|
538
|
-
}
|
|
539
|
-
})
|
|
540
|
-
);
|
|
541
|
-
logger.debug(
|
|
542
|
-
`\u67E5\u8BE2\u7B14\u8BB0: configId=${configId}, noteIndex=${noteItem.noteIndex}`
|
|
543
|
-
);
|
|
544
|
-
} catch (error) {
|
|
545
|
-
logger.error("\u67E5\u8BE2\u7B14\u8BB0\u5931\u8D25:", error);
|
|
546
|
-
res.statusCode = 500;
|
|
547
|
-
res.setHeader("Content-Type", "application/json");
|
|
548
|
-
res.end(
|
|
549
|
-
JSON.stringify({
|
|
550
|
-
success: false,
|
|
551
|
-
error: error instanceof Error ? error.message : String(error)
|
|
552
|
-
})
|
|
553
|
-
);
|
|
554
|
-
}
|
|
555
|
-
} else {
|
|
556
|
-
next();
|
|
557
|
-
}
|
|
558
|
-
});
|
|
559
|
-
}
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
|
|
563
386
|
// vitepress/plugins/buildProgressPlugin.ts
|
|
564
387
|
import {
|
|
565
388
|
existsSync,
|
|
566
389
|
readFileSync,
|
|
567
390
|
writeFileSync,
|
|
568
|
-
mkdirSync
|
|
569
|
-
readdirSync
|
|
391
|
+
mkdirSync
|
|
570
392
|
} from "fs";
|
|
571
393
|
import { join } from "path";
|
|
572
394
|
var CACHE_DIR = join(process.cwd(), "node_modules", ".tnotes-progress");
|
|
@@ -589,26 +411,6 @@ function setCacheData(data) {
|
|
|
589
411
|
} catch {
|
|
590
412
|
}
|
|
591
413
|
}
|
|
592
|
-
function countSourceFiles(srcDir) {
|
|
593
|
-
let count = 0;
|
|
594
|
-
const extensions = /\.(vue|ts|js|jsx|tsx|css|scss|sass|styl|less|md)$/i;
|
|
595
|
-
const scan = (dir) => {
|
|
596
|
-
try {
|
|
597
|
-
const entries = readdirSync(dir, { withFileTypes: true });
|
|
598
|
-
for (const entry of entries) {
|
|
599
|
-
const fullPath = join(dir, entry.name);
|
|
600
|
-
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
601
|
-
scan(fullPath);
|
|
602
|
-
} else if (entry.isFile() && extensions.test(entry.name)) {
|
|
603
|
-
count++;
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
} catch {
|
|
607
|
-
}
|
|
608
|
-
};
|
|
609
|
-
scan(srcDir);
|
|
610
|
-
return count;
|
|
611
|
-
}
|
|
612
414
|
var globalStartTime = 0;
|
|
613
415
|
var globalTransformCount = 0;
|
|
614
416
|
var globalChunkCount = 0;
|
|
@@ -616,7 +418,6 @@ var globalHasError = false;
|
|
|
616
418
|
var globalIsBuilding = false;
|
|
617
419
|
var globalOutDir = "";
|
|
618
420
|
var globalLastPercent = 0;
|
|
619
|
-
var globalFileCount = 0;
|
|
620
421
|
var globalLastLoggedPercent = -1;
|
|
621
422
|
var globalLastOutputTime = 0;
|
|
622
423
|
var globalTransformEndTime = 0;
|
|
@@ -708,9 +509,6 @@ function buildProgressPlugin(options = {}) {
|
|
|
708
509
|
globalTransformEndTime = 0;
|
|
709
510
|
globalLastHookTime = Date.now();
|
|
710
511
|
globalOutDir = config.build?.outDir || "dist";
|
|
711
|
-
if (!hasCache) {
|
|
712
|
-
globalFileCount = countSourceFiles(process.cwd());
|
|
713
|
-
}
|
|
714
512
|
interceptOutput();
|
|
715
513
|
globalStallTimer = setInterval(() => {
|
|
716
514
|
if (!globalIsBuilding || globalLastPercent <= 0 || globalLastPercent >= 0.98)
|
|
@@ -841,6 +639,225 @@ function buildProgressPlugin(options = {}) {
|
|
|
841
639
|
};
|
|
842
640
|
}
|
|
843
641
|
|
|
642
|
+
// vitepress/plugins/fileWatcherBridgePlugin.ts
|
|
643
|
+
var RENAME_EVENT = "tnotes:note-renamed";
|
|
644
|
+
var BROADCAST_PATH = "/__tnotes_broadcast_rename";
|
|
645
|
+
function fileWatcherBridgePlugin() {
|
|
646
|
+
return {
|
|
647
|
+
name: "tnotes-file-watcher-bridge",
|
|
648
|
+
apply: "serve",
|
|
649
|
+
configureServer(server) {
|
|
650
|
+
server.middlewares.use((req, res, next) => {
|
|
651
|
+
const url = req.url ?? "";
|
|
652
|
+
const isBroadcast = url === BROADCAST_PATH || url.endsWith(BROADCAST_PATH);
|
|
653
|
+
if (!isBroadcast || req.method !== "POST") {
|
|
654
|
+
return next();
|
|
655
|
+
}
|
|
656
|
+
let body = "";
|
|
657
|
+
req.on("data", (chunk) => {
|
|
658
|
+
body += chunk.toString();
|
|
659
|
+
});
|
|
660
|
+
req.on("end", () => {
|
|
661
|
+
try {
|
|
662
|
+
const data = JSON.parse(body || "{}");
|
|
663
|
+
server.ws.send({ type: "custom", event: RENAME_EVENT, data });
|
|
664
|
+
res.statusCode = 204;
|
|
665
|
+
res.end();
|
|
666
|
+
} catch (error) {
|
|
667
|
+
res.statusCode = 400;
|
|
668
|
+
res.end(
|
|
669
|
+
error instanceof Error ? error.message : "Bad rename payload"
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// vitepress/plugins/getNoteByConfigIdPlugin.ts
|
|
679
|
+
function getNoteByConfigIdPlugin() {
|
|
680
|
+
return {
|
|
681
|
+
name: "tnotes-get-note-by-config-id",
|
|
682
|
+
configureServer(server) {
|
|
683
|
+
server.middlewares.use(async (req, res, next) => {
|
|
684
|
+
if (req.url?.startsWith("/__tnotes_get_note?") && req.method === "GET") {
|
|
685
|
+
try {
|
|
686
|
+
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
687
|
+
const configId = url.searchParams.get("configId");
|
|
688
|
+
if (!configId) {
|
|
689
|
+
res.statusCode = 400;
|
|
690
|
+
res.setHeader("Content-Type", "application/json");
|
|
691
|
+
res.end(
|
|
692
|
+
JSON.stringify({
|
|
693
|
+
success: false,
|
|
694
|
+
error: "Missing configId parameter"
|
|
695
|
+
})
|
|
696
|
+
);
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
const noteIndexCache = NoteIndexCache.getInstance();
|
|
700
|
+
if (!noteIndexCache.isInitialized()) {
|
|
701
|
+
res.statusCode = 503;
|
|
702
|
+
res.setHeader("Content-Type", "application/json");
|
|
703
|
+
res.end(
|
|
704
|
+
JSON.stringify({
|
|
705
|
+
success: false,
|
|
706
|
+
error: "Service not initialized"
|
|
707
|
+
})
|
|
708
|
+
);
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
const noteItem = noteIndexCache.getByConfigId(configId);
|
|
712
|
+
if (!noteItem) {
|
|
713
|
+
res.statusCode = 200;
|
|
714
|
+
res.setHeader("Content-Type", "application/json");
|
|
715
|
+
res.end(
|
|
716
|
+
JSON.stringify({
|
|
717
|
+
success: true,
|
|
718
|
+
found: false,
|
|
719
|
+
data: null
|
|
720
|
+
})
|
|
721
|
+
);
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
res.statusCode = 200;
|
|
725
|
+
res.setHeader("Content-Type", "application/json");
|
|
726
|
+
res.end(
|
|
727
|
+
JSON.stringify({
|
|
728
|
+
success: true,
|
|
729
|
+
found: true,
|
|
730
|
+
data: {
|
|
731
|
+
noteIndex: noteItem.noteIndex,
|
|
732
|
+
folderName: noteItem.folderName,
|
|
733
|
+
// 构建笔记的完整 URL(包含 README)
|
|
734
|
+
url: `/notes/${encodeURIComponent(
|
|
735
|
+
noteItem.folderName
|
|
736
|
+
)}/README`
|
|
737
|
+
}
|
|
738
|
+
})
|
|
739
|
+
);
|
|
740
|
+
logger.debug(
|
|
741
|
+
`\u67E5\u8BE2\u7B14\u8BB0: configId=${configId}, noteIndex=${noteItem.noteIndex}`
|
|
742
|
+
);
|
|
743
|
+
} catch (error) {
|
|
744
|
+
logger.error("\u67E5\u8BE2\u7B14\u8BB0\u5931\u8D25:", error);
|
|
745
|
+
res.statusCode = 500;
|
|
746
|
+
res.setHeader("Content-Type", "application/json");
|
|
747
|
+
res.end(
|
|
748
|
+
JSON.stringify({
|
|
749
|
+
success: false,
|
|
750
|
+
error: error instanceof Error ? error.message : String(error)
|
|
751
|
+
})
|
|
752
|
+
);
|
|
753
|
+
}
|
|
754
|
+
} else {
|
|
755
|
+
next();
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// vitepress/plugins/renameNotePlugin.ts
|
|
763
|
+
function renameNotePlugin() {
|
|
764
|
+
const renameCommand = new RenameNoteCommand();
|
|
765
|
+
return {
|
|
766
|
+
name: "tnotes-rename-note",
|
|
767
|
+
configureServer(server) {
|
|
768
|
+
server.middlewares.use(async (req, res, next) => {
|
|
769
|
+
if (req.url === "/__tnotes_rename_note" && req.method === "POST") {
|
|
770
|
+
let body = "";
|
|
771
|
+
req.on("data", (chunk) => {
|
|
772
|
+
body += chunk.toString();
|
|
773
|
+
});
|
|
774
|
+
req.on("end", async () => {
|
|
775
|
+
try {
|
|
776
|
+
const { noteIndex, newTitle } = JSON.parse(body);
|
|
777
|
+
if (!noteIndex || !newTitle) {
|
|
778
|
+
res.statusCode = 400;
|
|
779
|
+
res.end("Missing noteIndex or newTitle");
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
const startTime = Date.now();
|
|
783
|
+
await renameCommand.renameNote({ noteIndex, newTitle });
|
|
784
|
+
const duration = Date.now() - startTime;
|
|
785
|
+
const newFolderName = `${noteIndex}. ${newTitle.trim()}`;
|
|
786
|
+
const newUrl = `/notes/${encodeURIComponent(
|
|
787
|
+
newFolderName
|
|
788
|
+
)}/README`;
|
|
789
|
+
res.statusCode = 200;
|
|
790
|
+
res.setHeader("Content-Type", "application/json");
|
|
791
|
+
res.end(
|
|
792
|
+
JSON.stringify({
|
|
793
|
+
success: true,
|
|
794
|
+
duration,
|
|
795
|
+
newTitle,
|
|
796
|
+
newFolderName,
|
|
797
|
+
newUrl,
|
|
798
|
+
message: "\u91CD\u547D\u540D\u5B8C\u6210"
|
|
799
|
+
})
|
|
800
|
+
);
|
|
801
|
+
} catch (error) {
|
|
802
|
+
res.statusCode = 500;
|
|
803
|
+
res.end(error instanceof Error ? error.message : "Rename failed");
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
} else {
|
|
807
|
+
next();
|
|
808
|
+
}
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// vitepress/plugins/updateConfigPlugin.ts
|
|
815
|
+
function updateConfigPlugin() {
|
|
816
|
+
let updateCommand;
|
|
817
|
+
return {
|
|
818
|
+
name: "tnotes-update-config",
|
|
819
|
+
configureServer(server) {
|
|
820
|
+
updateCommand = new UpdateNoteConfigCommand();
|
|
821
|
+
server.middlewares.use(async (req, res, next) => {
|
|
822
|
+
if (req.url === "/__tnotes_update_config" && req.method === "POST") {
|
|
823
|
+
let body = "";
|
|
824
|
+
req.on("data", (chunk) => {
|
|
825
|
+
body += chunk.toString();
|
|
826
|
+
});
|
|
827
|
+
req.on("end", async () => {
|
|
828
|
+
try {
|
|
829
|
+
const data = JSON.parse(body);
|
|
830
|
+
const { noteIndex, config } = data;
|
|
831
|
+
if (!noteIndex || !config) {
|
|
832
|
+
res.statusCode = 400;
|
|
833
|
+
res.end("Missing noteIndex or config");
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
await updateCommand.updateConfig({
|
|
837
|
+
noteIndex,
|
|
838
|
+
config: {
|
|
839
|
+
done: config.done,
|
|
840
|
+
enableDiscussions: config.enableDiscussions,
|
|
841
|
+
description: config.description
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
res.statusCode = 200;
|
|
845
|
+
res.setHeader("Content-Type", "application/json");
|
|
846
|
+
res.end(JSON.stringify({ success: true }));
|
|
847
|
+
} catch (error) {
|
|
848
|
+
console.error("\u66F4\u65B0\u914D\u7F6E\u5931\u8D25:", error);
|
|
849
|
+
res.statusCode = 500;
|
|
850
|
+
res.end(error instanceof Error ? error.message : String(error));
|
|
851
|
+
}
|
|
852
|
+
});
|
|
853
|
+
} else {
|
|
854
|
+
next();
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
|
|
844
861
|
// vitepress/config/index.ts
|
|
845
862
|
function loadTNotesConfig(rootPath) {
|
|
846
863
|
const configPath = path2.resolve(rootPath, ".tnotes.json");
|
|
@@ -881,9 +898,13 @@ function defineNotesConfig(overrides = {}) {
|
|
|
881
898
|
updateConfigPlugin(),
|
|
882
899
|
renameNotePlugin(),
|
|
883
900
|
getNoteByConfigIdPlugin(),
|
|
901
|
+
fileWatcherBridgePlugin(),
|
|
884
902
|
...overrideVite?.plugins || []
|
|
885
903
|
],
|
|
886
904
|
server: {
|
|
905
|
+
// 显式同时监听 IPv4 / IPv6,避免 Node 18+ 在 Windows 下偶发只绑定 ::1
|
|
906
|
+
// 导致 Chrome 解析 localhost → 127.0.0.1 时连接被拒、页面一直 pending。
|
|
907
|
+
// host: true,
|
|
887
908
|
watch: {
|
|
888
909
|
ignored: IGNORE_LIST
|
|
889
910
|
},
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tnotesjs/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "TNotes 知识库核心框架 —— 基于 VitePress 的笔记管理系统",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"packageManager": "pnpm@10.17.1",
|
|
6
7
|
"bin": {
|
|
7
8
|
"tnotes": "./dist/cli/index.js"
|
|
8
9
|
},
|
|
@@ -28,8 +29,11 @@
|
|
|
28
29
|
"scripts": {
|
|
29
30
|
"build": "tsup",
|
|
30
31
|
"build:check": "tsc --noEmit -p tsconfig.build.json",
|
|
32
|
+
"typecheck": "vue-tsc --noEmit -p tsconfig.build.json",
|
|
31
33
|
"dev": "tsup --watch",
|
|
32
|
-
"release": "node scripts/release.mjs"
|
|
34
|
+
"release": "node scripts/release.mjs",
|
|
35
|
+
"lint": "eslint . --max-warnings=0",
|
|
36
|
+
"lint:fix": "eslint . --fix"
|
|
33
37
|
},
|
|
34
38
|
"peerDependencies": {
|
|
35
39
|
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
|
|
@@ -55,10 +59,19 @@
|
|
|
55
59
|
"vue-echarts": "^8.0.1"
|
|
56
60
|
},
|
|
57
61
|
"devDependencies": {
|
|
62
|
+
"@eslint/js": "^9.39.4",
|
|
58
63
|
"@types/markdown-it": "^14.1.2",
|
|
59
64
|
"@types/node": "^24.6.2",
|
|
65
|
+
"@typescript-eslint/parser": "^8.59.0",
|
|
66
|
+
"eslint": "^9.39.4",
|
|
67
|
+
"eslint-plugin-import": "^2.32.0",
|
|
68
|
+
"eslint-plugin-vue": "^10.9.0",
|
|
69
|
+
"globals": "^17.5.0",
|
|
60
70
|
"tsup": "^8.5.1",
|
|
61
|
-
"typescript": "^5.9.3"
|
|
71
|
+
"typescript": "^5.9.3",
|
|
72
|
+
"typescript-eslint": "^8.59.0",
|
|
73
|
+
"vue-eslint-parser": "^10.4.0",
|
|
74
|
+
"vue-tsc": "^3.2.7"
|
|
62
75
|
},
|
|
63
76
|
"engines": {
|
|
64
77
|
"node": ">=18.0.0"
|
package/types/shims.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
|
|
1
3
|
declare module '*.vue' {
|
|
2
4
|
import type { DefineComponent } from 'vue'
|
|
5
|
+
|
|
3
6
|
const component: DefineComponent<{}, {}, any>
|
|
4
7
|
export default component
|
|
5
8
|
}
|
|
6
9
|
|
|
7
|
-
declare module '*.svg' {
|
|
8
|
-
const content: string
|
|
9
|
-
export default content
|
|
10
|
-
}
|
|
@@ -54,7 +54,8 @@
|
|
|
54
54
|
</template>
|
|
55
55
|
|
|
56
56
|
<script setup lang="ts">
|
|
57
|
-
import { ref, watch, onMounted, onUnmounted } from 'vue'
|
|
57
|
+
import { ref, watch, onMounted, onUnmounted } from 'vue'
|
|
58
|
+
|
|
58
59
|
import { icon__copy, icon__check, icon__close, icon__rotate } from '../../assets/icons'
|
|
59
60
|
|
|
60
61
|
const ORIENTATION_KEY = 'code-fullscreen-orientation'
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useData } from 'vitepress/client'
|
|
3
|
-
import { onMounted, onUnmounted, watch, computed } from 'vue'
|
|
3
|
+
import { onMounted, onUnmounted, watch, computed } from 'vue'
|
|
4
|
+
|
|
5
|
+
import { icon__github } from '../../assets/icons'
|
|
4
6
|
import { REPO_NAME, AUTHOR } from '../constants'
|
|
5
7
|
import Tooltip from '../Tooltip/Tooltip.vue'
|
|
6
|
-
import { icon__github } from '../../assets/icons'
|
|
7
8
|
|
|
8
9
|
const props = defineProps({
|
|
9
10
|
/**
|
|
@@ -76,7 +76,7 @@ watch(
|
|
|
76
76
|
if (open) {
|
|
77
77
|
// small timeout to ensure element exists
|
|
78
78
|
setTimeout(() => {
|
|
79
|
-
|
|
79
|
+
modalRef.value?.focus?.()
|
|
80
80
|
}, 0)
|
|
81
81
|
document.addEventListener('keydown', onKeyDown)
|
|
82
82
|
// prevent body scroll
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
<div :class="$style.timeLine" title="首次提交时间">
|
|
111
111
|
<div :class="$style.timeLabel"><strong>⌛️ 首次提交</strong></div>
|
|
112
112
|
<div :class="$style.timeValue">
|
|
113
|
-
{{
|
|
113
|
+
{{ formatOptionalDate(modalCreatedAt) }}
|
|
114
114
|
</div>
|
|
115
115
|
</div>
|
|
116
116
|
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
<div :class="$style.timeLine" title="最近提交时间">
|
|
119
119
|
<div :class="$style.timeLabel"><strong>⌛️ 最近提交</strong></div>
|
|
120
120
|
<div :class="$style.timeValue">
|
|
121
|
-
{{
|
|
121
|
+
{{ formatOptionalDate(modalUpdatedAt) }}
|
|
122
122
|
</div>
|
|
123
123
|
</div>
|
|
124
124
|
|
|
@@ -193,7 +193,8 @@
|
|
|
193
193
|
</template>
|
|
194
194
|
|
|
195
195
|
<script setup lang="ts">
|
|
196
|
-
import { computed } from 'vue'
|
|
196
|
+
import { computed } from 'vue'
|
|
197
|
+
|
|
197
198
|
import { formatDate } from '../utils'
|
|
198
199
|
|
|
199
200
|
const props = defineProps<{
|
|
@@ -261,6 +262,10 @@ function onDescriptionInput() {
|
|
|
261
262
|
function onConfigChange() {
|
|
262
263
|
emit('configChange')
|
|
263
264
|
}
|
|
265
|
+
|
|
266
|
+
function formatOptionalDate(timestamp: number | undefined) {
|
|
267
|
+
return timestamp === undefined ? '-' : formatDate(timestamp)
|
|
268
|
+
}
|
|
264
269
|
</script>
|
|
265
270
|
|
|
266
271
|
<style module src="./Layout.module.scss"></style>
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script setup lang="ts">
|
|
6
|
-
import { onMounted, onUnmounted } from 'vue'
|
|
7
6
|
import { useRoute, onContentUpdated } from 'vitepress'
|
|
7
|
+
import { onMounted, onUnmounted } from 'vue'
|
|
8
|
+
|
|
8
9
|
import { icon__collapse } from '../../assets/icons'
|
|
9
10
|
|
|
10
11
|
const route = useRoute()
|