diff --git a/.eslintrc b/.eslintrc index a2626d31..a9438bea 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,15 +2,16 @@ "root": true, "parser": "@typescript-eslint/parser", "env": { "node": true }, - "plugins": ["@typescript-eslint"], + "plugins": ["@typescript-eslint", "tailwindcss"], "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:react/recommended", - "plugin:react-hooks/recommended" + "plugin:react-hooks/recommended", + "plugin:tailwindcss/recommended", ], "parserOptions": { - "sourceType": "module" + "sourceType": "module", }, "rules": { "no-unused-vars": "off", @@ -20,20 +21,32 @@ "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-explicit-any": "off", "react/prop-types": "off", - "react-hooks/exhaustive-deps": "error" + "react-hooks/exhaustive-deps": "error", + "tailwindcss/classnames-order": "error", + "tailwindcss/enforces-negative-arbitrary-values": "error", + "tailwindcss/enforces-shorthand": "error", + "tailwindcss/migration-from-tailwind-2": "error", + "tailwindcss/no-arbitrary-value": "off", + "tailwindcss/no-custom-classname": ["error"], + "tailwindcss/no-contradicting-classname": "error", }, "overrides": [ { "files": ["*.json", "*.jsonc", ".eslintrc"], "parser": "jsonc-eslint-parser", "rules": { - "jsonc/auto": "error" - } - } + "jsonc/auto": "error", + }, + }, ], "settings": { "react": { - "version": "detect" - } - } + "version": "detect", + }, + "tailwindcss": { + "callees": ["classnames", "clsx", "ctl", "cn", "cva"], + "config": "./tailwind.config.js", + "cssFiles": ["**/*.css", "!**/node_modules", "!**/.*", "!**/dist", "!**/build"], + }, + }, } diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 8019d06f..0e883c85 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -15,7 +15,7 @@ jobs: strategy: matrix: - node-version: [20.x] + node-version: [22.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: diff --git a/components.json b/components.json index de54c7ba..0f0ccfbd 100644 --- a/components.json +++ b/components.json @@ -8,7 +8,7 @@ "css": "src/styles/tailwind.css", "baseColor": "zinc", "cssVariables": true, - "prefix": "" + "prefix": "tw" }, "aliases": { "components": "@/components", diff --git a/package-lock.json b/package-lock.json index d2301736..51324b64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -96,6 +96,7 @@ "eslint-plugin-json": "^4.0.1", "eslint-plugin-react": "^7.37.3", "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-tailwindcss": "^3.18.0", "husky": "^9.1.5", "jest": "^29.7.0", "jest-environment-jsdom": "^29.5.0", @@ -11699,6 +11700,22 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-tailwindcss": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-tailwindcss/-/eslint-plugin-tailwindcss-3.18.0.tgz", + "integrity": "sha512-PQDU4ZMzFH0eb2DrfHPpbgo87Zgg2EXSMOj1NSfzdZm+aJzpuwGerfowMIaVehSREEa0idbf/eoNYAOHSJoDAQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.5", + "postcss": "^8.4.4" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "tailwindcss": "^3.4.0" + } + }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", @@ -18176,7 +18193,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", diff --git a/package.json b/package.json index a728cbaf..1a2bb0b5 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "eslint-plugin-json": "^4.0.1", "eslint-plugin-react": "^7.37.3", "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-tailwindcss": "^3.18.0", "husky": "^9.1.5", "jest": "^29.7.0", "jest-environment-jsdom": "^29.5.0", diff --git a/src/components/Chat.tsx b/src/components/Chat.tsx index eec69efc..773a61c0 100644 --- a/src/components/Chat.tsx +++ b/src/components/Chat.tsx @@ -275,11 +275,11 @@ const Chat: React.FC = ({ // Get the first 10 words from the first user message and sanitize them const firstTenWords = firstUserMessage ? firstUserMessage.message - .split(/\s+/) - .slice(0, 10) - .join(" ") - .replace(/[\\/:*?"<>|]/g, "") // Remove invalid filename characters - .trim() + .split(/\s+/) + .slice(0, 10) + .join(" ") + .replace(/[\\/:*?"<>|]/g, "") // Remove invalid filename characters + .trim() : "Untitled Chat"; // Parse the custom format and replace variables @@ -644,7 +644,7 @@ ${chatContent}`; const renderChatComponents = () => ( <> -
+
-
-
+
+
+
{selectedChain === ChainType.PROJECT_CHAIN && ( -
+
+
  • - {"{}"} represents the selected text. + {"{}"} represents the selected text.
  • - {`{[[Note Title]]}`} represents a note. -
  • -
  • - {`{activeNote}`} represents the active + {`{[[Note Title]]}`} represents a note.
  • - {`{#tag1, #tag2}`} represents ALL notes - with ANY of the specified tags in their property (an OR operation). + {`{activeNote}`} represents the + active note. +
  • +
  • + {`{#tag1, #tag2}`} represents ALL + notes with ANY of the specified tags in their property (an OR operation).
); diff --git a/src/components/TruncatedText.tsx b/src/components/TruncatedText.tsx index 70e79b1f..58242795 100644 --- a/src/components/TruncatedText.tsx +++ b/src/components/TruncatedText.tsx @@ -23,9 +23,9 @@ export function isEllipsesActive( function getLineClampClass(lineClamp: number): string { switch (lineClamp) { case 2: - return "line-clamp-2"; + return "tw-line-clamp-2"; case 3: - return "line-clamp-3"; + return "tw-line-clamp-3"; default: return ""; } @@ -81,8 +81,8 @@ export const TruncatedText = ({ {...props} ref={textRef} className={cn( - "max-w-full text-normal", - (!lineClamp || lineClamp <= 1) && "truncate", + "tw-max-w-full tw-text-normal", + (!lineClamp || lineClamp <= 1) && "tw-truncate", lineClamp && getLineClampClass(lineClamp), className )} @@ -91,7 +91,7 @@ export const TruncatedText = ({ {children}
- + {tooltipContent ?? children} diff --git a/src/components/chat-components/ChatButtons.tsx b/src/components/chat-components/ChatButtons.tsx index a0a3ef44..4a647f5c 100644 --- a/src/components/chat-components/ChatButtons.tsx +++ b/src/components/chat-components/ChatButtons.tsx @@ -40,7 +40,7 @@ export const ChatButtons: React.FC = ({ }) => { return (
@@ -49,7 +49,7 @@ export const ChatButtons: React.FC = ({ Copy @@ -57,7 +57,7 @@ export const ChatButtons: React.FC = ({ Edit @@ -65,7 +65,7 @@ export const ChatButtons: React.FC = ({ Delete @@ -77,7 +77,7 @@ export const ChatButtons: React.FC = ({ Show Sources @@ -91,7 +91,7 @@ export const ChatButtons: React.FC = ({ size="fit" title="Insert / Replace at cursor" > - + Insert / Replace at cursor @@ -99,7 +99,7 @@ export const ChatButtons: React.FC = ({ Copy @@ -107,7 +107,7 @@ export const ChatButtons: React.FC = ({ Regenerate @@ -115,7 +115,7 @@ export const ChatButtons: React.FC = ({ Delete diff --git a/src/components/chat-components/ChatContextMenu.tsx b/src/components/chat-components/ChatContextMenu.tsx index c6ae4881..b54ccc03 100644 --- a/src/components/chat-components/ChatContextMenu.tsx +++ b/src/components/chat-components/ChatContextMenu.tsx @@ -23,11 +23,11 @@ function ContextNote({ onRemoveContext: (path: string) => void; }) { return ( - -
- {note.basename} - {isActive && Current} - {note.extension === "pdf" && pdf} + +
+ {note.basename} + {isActive && Current} + {note.extension === "pdf" && pdf}
); @@ -43,10 +43,10 @@ function ContextNote({ function ContextUrl({ url, onRemoveUrl }: { url: string; onRemoveUrl: (url: string) => void }) { return ( - -
- {url} - Link + +
+ {url} + Link
); @@ -87,19 +87,19 @@ export const ChatContextMenu: React.FC = ({ const hasContext = uniqueNotes.length > 0 || uniqueUrls.length > 0 || !!activeNote; return ( -
-
+
+
-
+
{activeNote && ( -
+
+
- @@ -195,8 +195,8 @@ export function ChatControls({ handleModeChange(ChainType.COPILOT_PLUS_CHAIN); }} > -
- +
+ copilot plus (beta)
@@ -208,18 +208,18 @@ export function ChatControls({ }} > copilot plus (beta) - + )} {isPlusUser ? ( { handleModeChange(ChainType.PROJECT_CHAIN); }} > - + projects (alpha) ) : ( @@ -230,7 +230,7 @@ export function ChatControls({ }} > copilot plus (beta) - + )} @@ -240,7 +240,7 @@ export function ChatControls({ New Chat @@ -249,7 +249,7 @@ export function ChatControls({ Save Chat as Note @@ -258,7 +258,7 @@ export function ChatControls({ Chat History @@ -267,32 +267,32 @@ export function ChatControls({ - + { e.preventDefault(); updateSetting("showSuggestedPrompts", !settings.showSuggestedPrompts); }} > -
- +
+ Suggested Prompt
{ e.preventDefault(); updateSetting("showRelevantNotes", !settings.showRelevantNotes); }} > -
- +
+ Relevant Note
@@ -300,31 +300,31 @@ export function ChatControls({ {selectedChain === ChainType.PROJECT_CHAIN ? ( <> reloadCurrentProject()} > - + Reload Current Project forceRebuildCurrentProjectContext()} > - + Force Rebuild Context ) : ( <> refreshVaultIndex()} > - + Refresh Vault Index { const modal = new ConfirmModal( app, @@ -335,7 +335,7 @@ export function ChatControls({ modal.open(); }} > - + Force Reindex Vault diff --git a/src/components/chat-components/ChatInput.tsx b/src/components/chat-components/ChatInput.tsx index 1eedd86d..1757be27 100644 --- a/src/components/chat-components/ChatInput.tsx +++ b/src/components/chat-components/ChatInput.tsx @@ -432,7 +432,7 @@ const ChatInput = forwardRef<{ focus: () => void }, ChatInputProps>( return (
void }, ChatInputProps>( onClick={() => setSelectedImages((prev) => prev.filter((_, i) => i !== index))} title="Remove image" > - +
))}
)} -
+
{isProjectLoading && ( -
-
- - {loadingMessages[loadingMessageIndex]} +
+
+ + {loadingMessages[loadingMessageIndex]}
)}