@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.
Files changed (53) hide show
  1. package/README.md +6 -3
  2. package/dist/{chunk-JDVN2QYW.js → chunk-FVKQPBPP.js} +643 -546
  3. package/dist/{chunk-NASIL5FY.js → chunk-SQVHJR2Z.js} +0 -4
  4. package/dist/cli/index.js +126 -126
  5. package/dist/index.js +1 -1
  6. package/dist/vitepress/config/index.js +229 -208
  7. package/package.json +16 -3
  8. package/types/shims.d.ts +3 -4
  9. package/vitepress/components/CodeBlockFullscreen/CodeBlockFullscreen.vue +2 -1
  10. package/vitepress/components/CodeBlockFullscreen/index.ts +2 -1
  11. package/vitepress/components/Discussions/Discussions.vue +3 -2
  12. package/vitepress/components/EnWordList/EnWordList.vue +2 -1
  13. package/vitepress/components/Layout/AboutModal.vue +1 -1
  14. package/vitepress/components/Layout/AboutPanel.vue +8 -3
  15. package/vitepress/components/Layout/ContentCollapse.vue +2 -1
  16. package/vitepress/components/Layout/CustomSidebar.vue +7 -4
  17. package/vitepress/components/Layout/DocBeforeControls.vue +4 -4
  18. package/vitepress/components/Layout/DocFooter.vue +2 -1
  19. package/vitepress/components/Layout/ImagePreview.vue +2 -1
  20. package/vitepress/components/Layout/Layout.vue +38 -20
  21. package/vitepress/components/Layout/NoteStatus.vue +2 -1
  22. package/vitepress/components/Layout/SidebarItems.vue +7 -2
  23. package/vitepress/components/Layout/SidebarNavBefore.vue +22 -0
  24. package/vitepress/components/Layout/ToggleFullContent.vue +2 -1
  25. package/vitepress/components/Layout/ToggleSidebar.vue +2 -1
  26. package/vitepress/components/Layout/composables/useCollapseControl.ts +1 -1
  27. package/vitepress/components/Layout/composables/useNoteConfig.ts +2 -4
  28. package/vitepress/components/Layout/composables/useNoteSave.ts +23 -18
  29. package/vitepress/components/Layout/composables/useRedirect.ts +8 -5
  30. package/vitepress/components/Layout/composables/useRenameOverlay.ts +33 -0
  31. package/vitepress/components/Layout/composables/useRenameRedirect.ts +59 -0
  32. package/vitepress/components/Layout/composables/useVSCodeIntegration.ts +7 -4
  33. package/vitepress/components/Layout/homeReadme.data.ts +1 -1
  34. package/vitepress/components/LoadingPage/LoadingPage.vue +84 -192
  35. package/vitepress/components/MarkMap/MarkMap.vue +5 -4
  36. package/vitepress/components/Mermaid/Mermaid.vue +4 -2
  37. package/vitepress/components/NotesTable/NotesTable.vue +2 -1
  38. package/vitepress/components/Settings/Settings.vue +2 -1
  39. package/vitepress/components/Settings/SettingsDialog.vue +243 -0
  40. package/vitepress/components/Settings/composables/useSettingsDialog.ts +35 -0
  41. package/vitepress/components/SidebarCard/MindMapView.vue +10 -9
  42. package/vitepress/components/SidebarCard/SidebarCard.vue +12 -14
  43. package/vitepress/config/index.ts +11 -4
  44. package/vitepress/configs/head.config.ts +2 -1
  45. package/vitepress/configs/markdown-it.d.ts +6 -3
  46. package/vitepress/configs/markdown.config.ts +6 -5
  47. package/vitepress/configs/theme.config.ts +1 -1
  48. package/vitepress/plugins/buildProgressPlugin.ts +2 -38
  49. package/vitepress/plugins/fileWatcherBridgePlugin.ts +49 -0
  50. package/vitepress/plugins/getNoteByConfigIdPlugin.ts +3 -2
  51. package/vitepress/plugins/renameNotePlugin.ts +9 -1
  52. package/vitepress/plugins/updateConfigPlugin.ts +2 -1
  53. package/vitepress/theme/index.ts +45 -3
@@ -4,8 +4,8 @@ import {
4
4
  UpdateNoteConfigCommand,
5
5
  generateAnchor,
6
6
  logger
7
- } from "../../chunk-JDVN2QYW.js";
8
- import "../../chunk-NASIL5FY.js";
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
- let params = {};
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
- let refRaw = refMatch[1].trim().replace(/^['"]|['"]$/g, "");
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.0.7",
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,5 +1,6 @@
1
1
  import { onMounted, onUnmounted } from 'vue'
2
- import { createApp } from 'vue'
2
+ import { createApp } from 'vue'
3
+
3
4
  import CodeBlockFullscreen from './CodeBlockFullscreen.vue'
4
5
 
5
6
  export function useCodeBlockFullscreen() {
@@ -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
  /**
@@ -1,6 +1,7 @@
1
1
  <script setup>
2
- import { computed, ref, onMounted, onUnmounted, nextTick } from 'vue'
3
2
  import { marked } from 'marked'
3
+ import { computed, ref, onMounted, onUnmounted, nextTick } from 'vue'
4
+
4
5
  import {
5
6
  EN_WORDS_REPO_BASE_URL,
6
7
  EN_WORDS_REPO_BASE_RAW_URL,
@@ -76,7 +76,7 @@ watch(
76
76
  if (open) {
77
77
  // small timeout to ensure element exists
78
78
  setTimeout(() => {
79
- if (modalRef.value) modalRef.value.focus && modalRef.value.focus()
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
- {{ formatDate(modalCreatedAt) }}
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
- {{ formatDate(modalUpdatedAt) }}
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()