Skip to content

Commit

Permalink
feat: Added settings to hide the counter for characters and implement…
Browse files Browse the repository at this point in the history
…ed a counter for words. Also remooved the max character limit in the textarea
  • Loading branch information
vasilecampeanu committed Oct 25, 2024
1 parent a7e7bcc commit 06d8863
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 40 deletions.
4 changes: 3 additions & 1 deletion src/components/chat/ChatSelectedTextModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ export const ChatSelectedTextModal: React.FC<ChatSelectedTextProps> = ({
<button
className="ow-btn cancel"
onClick={() => {setUserSelection(null)}}
>Cancel</button>
>
Cancel
</button>
</div>
</div>
);
Expand Down
54 changes: 27 additions & 27 deletions src/components/chat/ChatUserInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
} from "react";
import { ChatSelectedTextModal } from "./ChatSelectedTextModal";

const MAX_CHARACTERS = 4200;
const TEXTAREA_LINE_HEIGHT = 14;

const buttonVariants = {
Expand All @@ -25,6 +24,7 @@ interface ChatUserInputProps {}

export const ChatUserInput: React.FC<ChatUserInputProps> = () => {
const [userInputMessage, setUserInputMessage] = useState<string>("");
const [wordCount, setWordCount] = useState<number>(0);
const [charCount, setCharCount] = useState<number>(0);
const [isHovered, setIsHovered] = useState<boolean>(false);
const [isFocused, setIsFocused] = useState<boolean>(false);
Expand Down Expand Up @@ -65,11 +65,11 @@ export const ChatUserInput: React.FC<ChatUserInputProps> = () => {
};
}, []);

// Extracted submission logic into a separate function
const submitMessage = async () => {
try {
// Do this early
setUserInputMessage("");
setWordCount(0);
setCharCount(0);

const selection = userSelection;
Expand All @@ -90,32 +90,28 @@ export const ChatUserInput: React.FC<ChatUserInputProps> = () => {
await submitMessage();
};

const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
let value = event.target.value;
const countWords = (text: string): number => {
return text.trim() === "" ? 0 : text.trim().split(/\s+/).length;
};

if (value.length > MAX_CHARACTERS) {
value = value.slice(0, MAX_CHARACTERS);
}
const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
const value = event.target.value;

setUserInputMessage(value);
setCharCount(value.length);
setWordCount(countWords(value));
};

const handlePaste = (event: ClipboardEvent<HTMLTextAreaElement>) => {
event.preventDefault();

const pasteData = event.clipboardData.getData("text");
const remainingChars = MAX_CHARACTERS - userInputMessage.length;

if (remainingChars <= 0) {
return;
}

const trimmedData = pasteData.slice(0, remainingChars);
const newValue = userInputMessage + trimmedData;
const currentValue = userInputMessage;
const newValue = currentValue + pasteData;

setUserInputMessage(newValue);
setCharCount(newValue.length);
setWordCount(countWords(newValue));

event.preventDefault();
};

const handleFocus = () => {
Expand Down Expand Up @@ -192,7 +188,6 @@ export const ChatUserInput: React.FC<ChatUserInputProps> = () => {
value={userInputMessage}
onChange={handleChange}
onPaste={handlePaste}
maxLength={MAX_CHARACTERS}
className="ow-textarea"
onFocus={handleFocus}
onBlur={handleBlur}
Expand Down Expand Up @@ -232,15 +227,20 @@ export const ChatUserInput: React.FC<ChatUserInputProps> = () => {
)}
</form>
<div className="ow-inline-input-utilities">
<div
className={`ow-input-character-counter ${
charCount > MAX_CHARACTERS
? "ow-character-limit-exceeded"
: ""
}`}
>
{charCount}/{MAX_CHARACTERS}
</div>
{userInputMessage.length > 0 && (plugin.settings.enableWordCounter || plugin.settings.enableCharacterCounter)? (
<div className="ow-input-counters">
{plugin.settings.enableWordCounter ? (
<div className="ow-input-word-counter">
{wordCount}
</div>
): null}
{plugin.settings.enableCharacterCounter ? (
<div className="ow-input-character-counter">
{charCount}
</div>
) : null}
</div>
): null}
<button
className={`ow-btn pin-input ${
isPinned ? "pinned" : ""
Expand Down
2 changes: 1 addition & 1 deletion src/components/conversations/ConversationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface ConversationListProps {}
export const ConversationList: React.FC<ConversationListProps> = () => {
const { conversations, loading, error } = useConversationList();
const { switchToChat } = useTab();
const { conversation, loadConversation, initConversation } = useConversation();
const { loadConversation, initConversation } = useConversation();

const sortedConversations = [...conversations].sort(
(a, b) =>
Expand Down
32 changes: 25 additions & 7 deletions src/components/primitives/Popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import {
FloatingFocusManager,
Middleware,
Placement,
useFloating
useFloating,
} from "@floating-ui/react";
import React, { useEffect } from "react";

interface PopoverProps {
referenceElement: React.RefObject<HTMLElement>;
renderContent: () => React.ReactNode;
placement: Placement
placement: Placement;
middleware?: Array<Middleware | null | undefined | false>;
isOpen: boolean;
onClose: () => void;
Expand All @@ -27,7 +27,7 @@ export const Popover: React.FC<PopoverProps> = ({
const { refs, floatingStyles, context } = useFloating({
whileElementsMounted: autoUpdate,
placement: placement,
middleware: middleware
middleware: middleware,
});

useEffect(() => {
Expand All @@ -46,18 +46,36 @@ export const Popover: React.FC<PopoverProps> = ({
onClose();
}
};

if (isOpen) {
document.addEventListener("mousedown", handleClickOutside);
} else {
document.removeEventListener("mousedown", handleClickOutside);
}

return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [isOpen, refs, onClose]);

}, [isOpen, refs, onClose, referenceElement]);

useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "Escape") {
onClose();
}
};

if (isOpen) {
document.addEventListener("keydown", handleKeyDown);
} else {
document.removeEventListener("keydown", handleKeyDown);
}

return () => {
document.removeEventListener("keydown", handleKeyDown);
};
}, [isOpen, onClose]);

if (!isOpen) return null;

return (
Expand Down
30 changes: 28 additions & 2 deletions src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ export interface WeaverSettings {
model: EChatModels,
systemPrompt: string,
openOnStartup: boolean,
sendSelectionToChat: boolean
sendSelectionToChat: boolean,
enableCharacterCounter: boolean,
enableWordCounter: boolean
}

export const DEFAULT_SETTINGS: WeaverSettings = {
Expand All @@ -23,7 +25,9 @@ export const DEFAULT_SETTINGS: WeaverSettings = {
model: EChatModels.GPT_4o,
systemPrompt: 'As an AI assistant integrated with Obsidian.md, provide responses formatted in Markdown. Use $ ... $ for inline LaTeX and $$ ... $$ on separate lines for block LaTeX.',
openOnStartup: true,
sendSelectionToChat: false
sendSelectionToChat: false,
enableWordCounter: false,
enableCharacterCounter: true,
};

export class WeaverSettingTab extends PluginSettingTab {
Expand Down Expand Up @@ -53,6 +57,28 @@ export class WeaverSettingTab extends PluginSettingTab {
})
);

new Setting(containerEl)
.setName('Enable Word Counter')
.setDesc('Toggle the display of the word counter in the chat input area.')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableWordCounter)
.onChange(async (value) => {
this.plugin.settings.enableWordCounter = value;
await this.plugin.saveSettings();
})
);

new Setting(containerEl)
.setName('Enable Character Counter')
.setDesc('Toggle the display of the character counter in the chat input area.')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableCharacterCounter)
.onChange(async (value) => {
this.plugin.settings.enableCharacterCounter = value;
await this.plugin.saveSettings();
})
);

containerEl.createEl('h2', {
text: 'OpenAI'
});
Expand Down
5 changes: 4 additions & 1 deletion src/styles/components/chat/ChatModelSwitcher.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@
border-radius: 15px;
list-style: none;
padding: 10px;
min-width: 300px;
min-width: 250px;

.ow-model-switcher-header
{
padding: 10px;
font-weight: bold;
font-size: var(--font-ui-medium);
color: var(--text-muted);
}

Expand Down Expand Up @@ -45,11 +46,13 @@

.model-name
{
font-size: var(--font-ui-medium);
font-weight: bold;
}

.model-description
{
font-size: var(--font-ui-small);
color: var(--text-muted);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/styles/components/chat/ChatOptions.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
.ow-chat-options-header
{
font-weight: bold;
font-size: var(--font-ui-medium);
color: var(--text-muted);
}

Expand All @@ -35,6 +36,7 @@
transition: background-color 0.2s ease;
display: flex;
align-items: center;
font-size: var(--font-ui-small);

&:hover,
&:focus
Expand Down
11 changes: 10 additions & 1 deletion src/styles/components/chat/ChatUserInput.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
background-color: var(--interactive-accent);
box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 5px 0px, rgba(0, 0, 0, 0.1) 0px 0px 1px 0px;
margin-top: auto;

&:hover
{
opacity: .9 !important;
}
}

.ow-chat-user-input-form-wrapper
Expand Down Expand Up @@ -96,15 +101,19 @@
.ow-inline-input-utilities
{
display: flex;
align-content: center;
gap: 5px;
height: 18px;

.ow-btn.paperclip
{
all: unset;
}

.ow-input-character-counter
.ow-input-counters
{
display: flex;
gap: 5px;
font-size: var(--font-ui-small);
color: var(--text-muted);
}
Expand Down

0 comments on commit 06d8863

Please sign in to comment.