@peaske7/readit 0.1.5 → 0.1.7

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 (52) hide show
  1. package/biome.json +1 -1
  2. package/bun.lock +86 -72
  3. package/docs/plans/2026-03-13-client-mode-design.md +86 -0
  4. package/docs/plans/2026-03-13-client-mode-plan.md +605 -0
  5. package/package.json +12 -11
  6. package/src/App.tsx +23 -6
  7. package/src/cli/index.ts +312 -25
  8. package/src/components/ActionsMenu.tsx +12 -10
  9. package/src/components/DocumentViewer/CodeBlock.tsx +131 -54
  10. package/src/components/DocumentViewer/DocumentViewer.tsx +6 -6
  11. package/src/components/DocumentViewer/InlineCode.tsx +60 -0
  12. package/src/components/FloatingTOC.tsx +4 -2
  13. package/src/components/Header.tsx +3 -1
  14. package/src/components/InlineEditor.tsx +4 -2
  15. package/src/components/MarginNote.tsx +17 -8
  16. package/src/components/RawModal.tsx +9 -7
  17. package/src/components/ReanchorConfirm.tsx +6 -3
  18. package/src/components/SettingsModal.tsx +112 -23
  19. package/src/components/ShortcutCapture.tsx +4 -1
  20. package/src/components/ShortcutList.tsx +50 -9
  21. package/src/components/comments/CommentBadge.tsx +7 -1
  22. package/src/components/comments/CommentInput.tsx +13 -18
  23. package/src/components/comments/CommentListItem.tsx +15 -5
  24. package/src/components/comments/CommentManager.tsx +14 -7
  25. package/src/components/comments/CommentNav.tsx +8 -3
  26. package/src/contexts/CommentContext.tsx +16 -9
  27. package/src/contexts/LayoutContext.tsx +17 -5
  28. package/src/contexts/LocaleContext.tsx +35 -0
  29. package/src/hooks/useClipboard.ts +11 -8
  30. package/src/hooks/useDocument.ts +35 -10
  31. package/src/hooks/useEditorScheme.ts +51 -0
  32. package/src/hooks/useFontPreference.ts +5 -22
  33. package/src/hooks/useKeybindings.ts +6 -18
  34. package/src/hooks/useLocalePreference.ts +42 -0
  35. package/src/index.css +87 -26
  36. package/src/lib/editor-links.ts +59 -0
  37. package/src/lib/highlight/dom.ts +126 -54
  38. package/src/lib/highlight/highlighter.ts +10 -10
  39. package/src/lib/i18n/completeness.test.ts +51 -0
  40. package/src/lib/i18n/en.ts +139 -0
  41. package/src/lib/i18n/index.ts +3 -0
  42. package/src/lib/i18n/ja.ts +141 -0
  43. package/src/lib/i18n/translations.test.ts +39 -0
  44. package/src/lib/i18n/translations.ts +27 -0
  45. package/src/lib/i18n/types.ts +145 -0
  46. package/src/lib/shortcut-registry.ts +1 -1
  47. package/src/lib/utils.ts +11 -0
  48. package/src/main.tsx +4 -1
  49. package/src/server/index.ts +263 -103
  50. package/src/store/index.test.ts +22 -0
  51. package/src/store/index.ts +24 -4
  52. package/src/types/index.ts +12 -0
@@ -0,0 +1,139 @@
1
+ import type { Translations } from "./types";
2
+
3
+ export const en: Translations = {
4
+ // App
5
+ "app.loading": "Loading...",
6
+ "app.noDocuments": "No documents open.",
7
+ "app.noDocumentsHintPrefix": "Run",
8
+ "app.noDocumentsHintSuffix": "to add a file.",
9
+ "app.footer": "Made with ❤️ by Jay and Claude",
10
+
11
+ // Header
12
+ "header.selectTextToReanchor": "Select text to re-anchor",
13
+
14
+ // Actions menu
15
+ "actions.ariaLabel": "Actions menu",
16
+ "actions.centered": "Centered",
17
+ "actions.fullscreen": "Fullscreen",
18
+ "actions.settings": "Settings",
19
+ "actions.reload": "Reload",
20
+ "actions.copyAllAI": "Copy All (AI)",
21
+ "actions.copyAllAITitle": "Copy in prompt format for AI assistants",
22
+ "actions.copyAllRaw": "Copy All (Raw)",
23
+ "actions.copyAllRawTitle": "Copy as plain text",
24
+ "actions.exportJson": "Export JSON",
25
+ "actions.viewRaw": "View Raw",
26
+
27
+ // Settings
28
+ "settings.title": "Settings",
29
+ "settings.theme": "Theme",
30
+ "settings.font": "Font",
31
+ "settings.language": "Language",
32
+ "settings.keyboardShortcuts": "Keyboard Shortcuts",
33
+ "settings.clickToRebind": "Click a key to rebind",
34
+ "settings.theme.system": "System",
35
+ "settings.theme.light": "Light",
36
+ "settings.theme.dark": "Dark",
37
+ "settings.font.serif": "Serif",
38
+ "settings.font.sansSerif": "Sans-serif",
39
+ "settings.editor": "Editor",
40
+ "settings.editor.none": "None",
41
+ "settings.editor.vscode": "VS Code",
42
+ "settings.editor.vscodeInsiders": "VS Code Insiders",
43
+ "settings.editor.cursor": "Cursor",
44
+
45
+ // Comment input
46
+ "comment.placeholder": "Add your comment...",
47
+ "comment.cancel": "Cancel",
48
+ "comment.addNote": "Add Note",
49
+ "comment.highlight": "Highlight",
50
+ "comment.copyRawTitle": "Copy raw text (⌘C)",
51
+ "comment.copyRawLabel": "Copy raw text",
52
+ "comment.copyLLMTitle": "Copy with context for LLM (⌘⇧C)",
53
+ "comment.copyLLMLabel": "Copy for LLM",
54
+
55
+ // Margin note
56
+ "marginNote.addNote": "Add note",
57
+ "marginNote.delete": "Delete",
58
+ "marginNote.edit": "Edit",
59
+ "marginNote.copy": "Copy",
60
+ "marginNote.copyTitle": "Copy raw text (⌘C)",
61
+ "marginNote.llm": "LLM",
62
+ "marginNote.llmTitle": "Copy with context for LLM (⌘⇧C)",
63
+
64
+ // Comment manager
65
+ "commentManager.unresolved": "unresolved",
66
+ "commentManager.deleteAllConfirm": "Delete all {{count}} comments?",
67
+ "commentManager.delete": "Delete",
68
+ "commentManager.cancel": "Cancel",
69
+ "commentManager.copyAllTitle": "Copy all comments",
70
+ "commentManager.deleteAllTitle": "Delete all comments",
71
+ "commentManager.noComments": "No comments yet",
72
+
73
+ // Comment list item
74
+ "commentList.edit": "Edit",
75
+ "commentList.delete": "Delete",
76
+ "commentList.goTo": "Go to",
77
+ "commentList.reanchor": "Re-anchor",
78
+ "commentList.unresolved": "unresolved",
79
+
80
+ // Comment nav
81
+ "commentNav.previous": "Previous comment (Alt+↑)",
82
+ "commentNav.next": "Next comment (Alt+↓)",
83
+ "commentNav.of": "{{current}} of {{total}}",
84
+
85
+ // Inline editor
86
+ "editor.save": "Save",
87
+ "editor.cancel": "Cancel",
88
+
89
+ // Reanchor confirm
90
+ "reanchor.question": "Re-anchor to this selection?",
91
+ "reanchor.confirm": "Confirm",
92
+ "reanchor.cancel": "Cancel",
93
+
94
+ // Raw comments modal
95
+ "rawModal.title": "Raw Comments",
96
+ "rawModal.copyTitle": "Copy to clipboard",
97
+ "rawModal.loading": "Loading...",
98
+ "rawModal.noComments": "No comments file yet. Add comments to create one.",
99
+ "rawModal.copiedToClipboard": "Copied to clipboard",
100
+ "rawModal.failedToCopy": "Failed to copy",
101
+
102
+ // Shortcut groups
103
+ "shortcutGroup.copy": "Copy",
104
+ "shortcutGroup.navigate": "Navigate",
105
+ "shortcutGroup.other": "Other",
106
+ "shortcuts.resetToDefaults": "Reset to defaults",
107
+ "shortcuts.enableDisable": "Enable/disable shortcut",
108
+ "shortcutCapture.pressKeys": "Press keys...",
109
+
110
+ // Shortcut labels
111
+ "shortcut.copyAll.label": "Copy All (AI)",
112
+ "shortcut.copyAll.description": "Copy all comments in AI prompt format",
113
+ "shortcut.copyAllRaw.label": "Copy All (Raw)",
114
+ "shortcut.copyAllRaw.description": "Copy all comments as raw text",
115
+ "shortcut.navigateNext.label": "Next Comment",
116
+ "shortcut.navigateNext.description": "Navigate to next comment",
117
+ "shortcut.navigatePrevious.label": "Previous Comment",
118
+ "shortcut.navigatePrevious.description": "Navigate to previous comment",
119
+ "shortcut.copySelectionRaw.label": "Copy Selection",
120
+ "shortcut.copySelectionRaw.description": "Copy selected text",
121
+ "shortcut.copySelectionLLM.label": "Copy Selection (LLM)",
122
+ "shortcut.copySelectionLLM.description":
123
+ "Copy selected text with context for LLM",
124
+ "shortcut.clearSelection.label": "Clear Selection",
125
+ "shortcut.clearSelection.description": "Clear text selection",
126
+
127
+ // Toast messages
128
+ "toast.copied": 'Copied: "{{text}}"',
129
+ "toast.copiedForLLM": 'Copied for LLM: "{{text}}"',
130
+ "toast.copiedAllComments": "Copied all comments",
131
+ "toast.copiedAllRaw": "Copied all comments as raw text",
132
+
133
+ // Floating TOC
134
+ "floatingTOC.label": "Table of Contents",
135
+
136
+ // Comment badge
137
+ "commentBadge.title": "{{count}} comment",
138
+ "commentBadge.titlePlural": "{{count}} comments",
139
+ };
@@ -0,0 +1,3 @@
1
+ export { createT } from "./translations";
2
+ export type { Locale, TranslationKey } from "./types";
3
+ export { Locales } from "./types";
@@ -0,0 +1,141 @@
1
+ import type { Translations } from "./types";
2
+
3
+ export const ja: Translations = {
4
+ // App
5
+ "app.loading": "読み込み中...",
6
+ "app.noDocuments": "開いているドキュメントがありません。",
7
+ "app.noDocumentsHintPrefix": "",
8
+ "app.noDocumentsHintSuffix": "を実行してファイルを追加してください。",
9
+ "app.footer": "Made with ❤️ by Jay and Claude",
10
+
11
+ // Header
12
+ "header.selectTextToReanchor": "テキストを選択して再アンカー",
13
+
14
+ // Actions menu
15
+ "actions.ariaLabel": "操作メニュー",
16
+ "actions.centered": "中央揃え",
17
+ "actions.fullscreen": "全画面",
18
+ "actions.settings": "設定",
19
+ "actions.reload": "再読み込み",
20
+ "actions.copyAllAI": "全てコピー (AI)",
21
+ "actions.copyAllAITitle": "AIアシスタント用プロンプト形式でコピー",
22
+ "actions.copyAllRaw": "全てコピー (テキスト)",
23
+ "actions.copyAllRawTitle": "プレーンテキストとしてコピー",
24
+ "actions.exportJson": "JSONエクスポート",
25
+ "actions.viewRaw": "生データを表示",
26
+
27
+ // Settings
28
+ "settings.title": "設定",
29
+ "settings.theme": "テーマ",
30
+ "settings.font": "フォント",
31
+ "settings.language": "言語",
32
+ "settings.keyboardShortcuts": "キーボードショートカット",
33
+ "settings.clickToRebind": "キーをクリックして変更",
34
+ "settings.theme.system": "システム",
35
+ "settings.theme.light": "ライト",
36
+ "settings.theme.dark": "ダーク",
37
+ "settings.font.serif": "明朝体",
38
+ "settings.font.sansSerif": "ゴシック体",
39
+ "settings.editor": "エディター",
40
+ "settings.editor.none": "なし",
41
+ "settings.editor.vscode": "VS Code",
42
+ "settings.editor.vscodeInsiders": "VS Code Insiders",
43
+ "settings.editor.cursor": "Cursor",
44
+
45
+ // Comment input
46
+ "comment.placeholder": "コメントを入力...",
47
+ "comment.cancel": "キャンセル",
48
+ "comment.addNote": "メモを追加",
49
+ "comment.highlight": "ハイライト",
50
+ "comment.copyRawTitle": "テキストをコピー (⌘C)",
51
+ "comment.copyRawLabel": "テキストをコピー",
52
+ "comment.copyLLMTitle": "LLM用にコンテキスト付きでコピー (⌘⇧C)",
53
+ "comment.copyLLMLabel": "LLM用にコピー",
54
+
55
+ // Margin note
56
+ "marginNote.addNote": "メモを追加",
57
+ "marginNote.delete": "削除",
58
+ "marginNote.edit": "編集",
59
+ "marginNote.copy": "コピー",
60
+ "marginNote.copyTitle": "テキストをコピー (⌘C)",
61
+ "marginNote.llm": "LLM",
62
+ "marginNote.llmTitle": "LLM用にコンテキスト付きでコピー (⌘⇧C)",
63
+
64
+ // Comment manager
65
+ "commentManager.unresolved": "未解決",
66
+ "commentManager.deleteAllConfirm":
67
+ "{{count}}件のコメントを全て削除しますか?",
68
+ "commentManager.delete": "削除",
69
+ "commentManager.cancel": "キャンセル",
70
+ "commentManager.copyAllTitle": "全てのコメントをコピー",
71
+ "commentManager.deleteAllTitle": "全てのコメントを削除",
72
+ "commentManager.noComments": "コメントはまだありません",
73
+
74
+ // Comment list item
75
+ "commentList.edit": "編集",
76
+ "commentList.delete": "削除",
77
+ "commentList.goTo": "移動",
78
+ "commentList.reanchor": "再アンカー",
79
+ "commentList.unresolved": "未解決",
80
+
81
+ // Comment nav
82
+ "commentNav.previous": "前のコメント (Alt+↑)",
83
+ "commentNav.next": "次のコメント (Alt+↓)",
84
+ "commentNav.of": "{{current}} / {{total}}",
85
+
86
+ // Inline editor
87
+ "editor.save": "保存",
88
+ "editor.cancel": "キャンセル",
89
+
90
+ // Reanchor confirm
91
+ "reanchor.question": "この選択範囲に再アンカーしますか?",
92
+ "reanchor.confirm": "確認",
93
+ "reanchor.cancel": "キャンセル",
94
+
95
+ // Raw comments modal
96
+ "rawModal.title": "コメント生データ",
97
+ "rawModal.copyTitle": "クリップボードにコピー",
98
+ "rawModal.loading": "読み込み中...",
99
+ "rawModal.noComments":
100
+ "コメントファイルはまだありません。コメントを追加して作成してください。",
101
+ "rawModal.copiedToClipboard": "クリップボードにコピーしました",
102
+ "rawModal.failedToCopy": "コピーに失敗しました",
103
+
104
+ // Shortcut groups
105
+ "shortcutGroup.copy": "コピー",
106
+ "shortcutGroup.navigate": "ナビゲーション",
107
+ "shortcutGroup.other": "その他",
108
+ "shortcuts.resetToDefaults": "初期設定に戻す",
109
+ "shortcuts.enableDisable": "ショートカットの有効/無効",
110
+ "shortcutCapture.pressKeys": "キーを入力...",
111
+
112
+ // Shortcut labels
113
+ "shortcut.copyAll.label": "全てコピー (AI)",
114
+ "shortcut.copyAll.description": "全コメントをAIプロンプト形式でコピー",
115
+ "shortcut.copyAllRaw.label": "全てコピー (テキスト)",
116
+ "shortcut.copyAllRaw.description": "全コメントをテキストとしてコピー",
117
+ "shortcut.navigateNext.label": "次のコメント",
118
+ "shortcut.navigateNext.description": "次のコメントに移動",
119
+ "shortcut.navigatePrevious.label": "前のコメント",
120
+ "shortcut.navigatePrevious.description": "前のコメントに移動",
121
+ "shortcut.copySelectionRaw.label": "選択をコピー",
122
+ "shortcut.copySelectionRaw.description": "選択テキストをコピー",
123
+ "shortcut.copySelectionLLM.label": "選択をコピー (LLM)",
124
+ "shortcut.copySelectionLLM.description":
125
+ "選択テキストをLLM用コンテキスト付きでコピー",
126
+ "shortcut.clearSelection.label": "選択を解除",
127
+ "shortcut.clearSelection.description": "テキスト選択を解除",
128
+
129
+ // Toast messages
130
+ "toast.copied": 'コピーしました: "{{text}}"',
131
+ "toast.copiedForLLM": 'LLM用にコピーしました: "{{text}}"',
132
+ "toast.copiedAllComments": "全てのコメントをコピーしました",
133
+ "toast.copiedAllRaw": "全てのコメントをテキストとしてコピーしました",
134
+
135
+ // Floating TOC
136
+ "floatingTOC.label": "目次",
137
+
138
+ // Comment badge
139
+ "commentBadge.title": "{{count}}件のコメント",
140
+ "commentBadge.titlePlural": "{{count}}件のコメント",
141
+ };
@@ -0,0 +1,39 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createT } from "./translations";
3
+ import { Locales } from "./types";
4
+
5
+ describe("createT", () => {
6
+ it("returns English strings for en locale", () => {
7
+ const t = createT(Locales.EN);
8
+ expect(t("app.loading")).toBe("Loading...");
9
+ expect(t("settings.title")).toBe("Settings");
10
+ expect(t("comment.placeholder")).toBe("Add your comment...");
11
+ });
12
+
13
+ it("returns Japanese strings for ja locale", () => {
14
+ const t = createT(Locales.JA);
15
+ expect(t("app.loading")).toBe("読み込み中...");
16
+ expect(t("settings.title")).toBe("設定");
17
+ expect(t("comment.placeholder")).toBe("コメントを入力...");
18
+ });
19
+
20
+ it("interpolates {{placeholder}} params", () => {
21
+ const tEn = createT(Locales.EN);
22
+ expect(tEn("commentNav.of", { current: 1, total: 5 })).toBe("1 of 5");
23
+
24
+ const tJa = createT(Locales.JA);
25
+ expect(tJa("commentNav.of", { current: 1, total: 5 })).toBe("1 / 5");
26
+ });
27
+
28
+ it("interpolates multiple params", () => {
29
+ const t = createT(Locales.EN);
30
+ expect(t("commentManager.deleteAllConfirm", { count: 3 })).toBe(
31
+ "Delete all 3 comments?",
32
+ );
33
+ });
34
+
35
+ it("returns string unchanged when no params provided", () => {
36
+ const t = createT(Locales.EN);
37
+ expect(t("app.footer")).toBe("Made with ❤️ by Jay and Claude");
38
+ });
39
+ });
@@ -0,0 +1,27 @@
1
+ import { en } from "./en";
2
+ import { ja } from "./ja";
3
+ import type { Locale, TranslationKey, Translations } from "./types";
4
+ import { Locales } from "./types";
5
+
6
+ const translationMap: Record<Locale, Translations> = {
7
+ [Locales.JA]: ja,
8
+ [Locales.EN]: en,
9
+ };
10
+
11
+ export function createT(locale: Locale) {
12
+ const translations = translationMap[locale];
13
+
14
+ return function t(
15
+ key: TranslationKey,
16
+ params?: Record<string, string | number>,
17
+ ): string {
18
+ let value = translations[key];
19
+ if (!params) return value;
20
+
21
+ for (const [param, replacement] of Object.entries(params)) {
22
+ value = value.replaceAll(`{{${param}}}`, String(replacement));
23
+ }
24
+
25
+ return value;
26
+ };
27
+ }
@@ -0,0 +1,145 @@
1
+ export const Locales = {
2
+ JA: "ja",
3
+ EN: "en",
4
+ } as const;
5
+
6
+ export type Locale = (typeof Locales)[keyof typeof Locales];
7
+
8
+ export interface Translations {
9
+ // App
10
+ "app.loading": string;
11
+ "app.noDocuments": string;
12
+ "app.noDocumentsHintPrefix": string;
13
+ "app.noDocumentsHintSuffix": string;
14
+ "app.footer": string;
15
+
16
+ // Header
17
+ "header.selectTextToReanchor": string;
18
+
19
+ // Actions menu
20
+ "actions.ariaLabel": string;
21
+ "actions.centered": string;
22
+ "actions.fullscreen": string;
23
+ "actions.settings": string;
24
+ "actions.reload": string;
25
+ "actions.copyAllAI": string;
26
+ "actions.copyAllAITitle": string;
27
+ "actions.copyAllRaw": string;
28
+ "actions.copyAllRawTitle": string;
29
+ "actions.exportJson": string;
30
+ "actions.viewRaw": string;
31
+
32
+ // Settings
33
+ "settings.title": string;
34
+ "settings.theme": string;
35
+ "settings.font": string;
36
+ "settings.language": string;
37
+ "settings.keyboardShortcuts": string;
38
+ "settings.clickToRebind": string;
39
+ "settings.theme.system": string;
40
+ "settings.theme.light": string;
41
+ "settings.theme.dark": string;
42
+ "settings.font.serif": string;
43
+ "settings.font.sansSerif": string;
44
+ "settings.editor": string;
45
+ "settings.editor.none": string;
46
+ "settings.editor.vscode": string;
47
+ "settings.editor.vscodeInsiders": string;
48
+ "settings.editor.cursor": string;
49
+
50
+ // Comment input
51
+ "comment.placeholder": string;
52
+ "comment.cancel": string;
53
+ "comment.addNote": string;
54
+ "comment.highlight": string;
55
+ "comment.copyRawTitle": string;
56
+ "comment.copyRawLabel": string;
57
+ "comment.copyLLMTitle": string;
58
+ "comment.copyLLMLabel": string;
59
+
60
+ // Margin note
61
+ "marginNote.addNote": string;
62
+ "marginNote.delete": string;
63
+ "marginNote.edit": string;
64
+ "marginNote.copy": string;
65
+ "marginNote.copyTitle": string;
66
+ "marginNote.llm": string;
67
+ "marginNote.llmTitle": string;
68
+
69
+ // Comment manager
70
+ "commentManager.unresolved": string;
71
+ "commentManager.deleteAllConfirm": string;
72
+ "commentManager.delete": string;
73
+ "commentManager.cancel": string;
74
+ "commentManager.copyAllTitle": string;
75
+ "commentManager.deleteAllTitle": string;
76
+ "commentManager.noComments": string;
77
+
78
+ // Comment list item
79
+ "commentList.edit": string;
80
+ "commentList.delete": string;
81
+ "commentList.goTo": string;
82
+ "commentList.reanchor": string;
83
+ "commentList.unresolved": string;
84
+
85
+ // Comment nav
86
+ "commentNav.previous": string;
87
+ "commentNav.next": string;
88
+ "commentNav.of": string;
89
+
90
+ // Inline editor
91
+ "editor.save": string;
92
+ "editor.cancel": string;
93
+
94
+ // Reanchor confirm
95
+ "reanchor.question": string;
96
+ "reanchor.confirm": string;
97
+ "reanchor.cancel": string;
98
+
99
+ // Raw comments modal
100
+ "rawModal.title": string;
101
+ "rawModal.copyTitle": string;
102
+ "rawModal.loading": string;
103
+ "rawModal.noComments": string;
104
+ "rawModal.copiedToClipboard": string;
105
+ "rawModal.failedToCopy": string;
106
+
107
+ // Shortcut groups
108
+ "shortcutGroup.copy": string;
109
+ "shortcutGroup.navigate": string;
110
+ "shortcutGroup.other": string;
111
+ "shortcuts.resetToDefaults": string;
112
+ "shortcuts.enableDisable": string;
113
+ "shortcutCapture.pressKeys": string;
114
+
115
+ // Shortcut labels (rendered in ShortcutList)
116
+ "shortcut.copyAll.label": string;
117
+ "shortcut.copyAll.description": string;
118
+ "shortcut.copyAllRaw.label": string;
119
+ "shortcut.copyAllRaw.description": string;
120
+ "shortcut.navigateNext.label": string;
121
+ "shortcut.navigateNext.description": string;
122
+ "shortcut.navigatePrevious.label": string;
123
+ "shortcut.navigatePrevious.description": string;
124
+ "shortcut.copySelectionRaw.label": string;
125
+ "shortcut.copySelectionRaw.description": string;
126
+ "shortcut.copySelectionLLM.label": string;
127
+ "shortcut.copySelectionLLM.description": string;
128
+ "shortcut.clearSelection.label": string;
129
+ "shortcut.clearSelection.description": string;
130
+
131
+ // Toast messages
132
+ "toast.copied": string;
133
+ "toast.copiedForLLM": string;
134
+ "toast.copiedAllComments": string;
135
+ "toast.copiedAllRaw": string;
136
+
137
+ // Floating TOC
138
+ "floatingTOC.label": string;
139
+
140
+ // Comment badge
141
+ "commentBadge.title": string;
142
+ "commentBadge.titlePlural": string;
143
+ }
144
+
145
+ export type TranslationKey = keyof Translations;
@@ -1,6 +1,6 @@
1
1
  import type { KeybindingOverride, ShortcutBinding } from "../types";
2
2
 
3
- export type { ShortcutBinding, KeybindingOverride };
3
+ export type { KeybindingOverride, ShortcutBinding };
4
4
 
5
5
  export const ShortcutActions = {
6
6
  COPY_ALL: "copyAll",
package/src/lib/utils.ts CHANGED
@@ -1,6 +1,17 @@
1
1
  import { type ClassValue, clsx } from "clsx";
2
2
  import type { ReactNode } from "react";
3
3
  import { twMerge } from "tailwind-merge";
4
+ import type { DocumentType } from "../types";
5
+
6
+ export function getFileType(filePath: string): DocumentType | null {
7
+ if (filePath.endsWith(".md") || filePath.endsWith(".markdown")) {
8
+ return "markdown";
9
+ }
10
+ if (filePath.endsWith(".html") || filePath.endsWith(".htm")) {
11
+ return "html";
12
+ }
13
+ return null;
14
+ }
4
15
 
5
16
  export function cn(...inputs: ReadonlyArray<ClassValue>) {
6
17
  return twMerge(clsx(inputs));
package/src/main.tsx CHANGED
@@ -1,10 +1,13 @@
1
1
  import React from "react";
2
2
  import ReactDOM from "react-dom/client";
3
3
  import App from "./App";
4
+ import { LocaleProvider } from "./contexts/LocaleContext";
4
5
  import "./index.css";
5
6
 
6
7
  ReactDOM.createRoot(document.getElementById("root")!).render(
7
8
  <React.StrictMode>
8
- <App />
9
+ <LocaleProvider>
10
+ <App />
11
+ </LocaleProvider>
9
12
  </React.StrictMode>,
10
13
  );