🚧 chat view WIP
This commit is contained in:
parent
e9ac83fd1b
commit
50debaa04d
38
main.ts
38
main.ts
|
@ -1,4 +1,5 @@
|
|||
import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';
|
||||
import { App, Editor, MarkdownView, Modal, Plugin, PluginSettingTab, Setting } from 'obsidian';
|
||||
import { AppView, VIEW_TYPE } from './src/ui/window';
|
||||
|
||||
// Remember to rename these classes and interfaces!
|
||||
|
||||
|
@ -12,14 +13,17 @@ const DEFAULT_SETTINGS: MyPluginSettings = {
|
|||
|
||||
export default class MyPlugin extends Plugin {
|
||||
settings: MyPluginSettings;
|
||||
view: AppView;
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
this.registerView(
|
||||
VIEW_TYPE,
|
||||
(leaf) => (new AppView(leaf, this))
|
||||
);
|
||||
|
||||
// This creates an icon in the left ribbon.
|
||||
const ribbonIconEl = this.addRibbonIcon('dice', 'Sample Plugin', (evt: MouseEvent) => {
|
||||
// Called when the user clicks the icon.
|
||||
new Notice('This is a notice!');
|
||||
const ribbonIconEl = this.addRibbonIcon('dice', 'Open Agent View', (evt: MouseEvent) => {
|
||||
this.activateView();
|
||||
});
|
||||
// Perform additional things with the ribbon
|
||||
ribbonIconEl.addClass('my-plugin-ribbon-class');
|
||||
|
@ -28,6 +32,15 @@ export default class MyPlugin extends Plugin {
|
|||
const statusBarItemEl = this.addStatusBarItem();
|
||||
statusBarItemEl.setText('Status Bar Text');
|
||||
|
||||
this.addCommand({
|
||||
id: "habitica-view-open",
|
||||
name: "Open Writing Assistant",
|
||||
hotkeys: [{ modifiers: ["Mod", "Shift"], key: "h"}],
|
||||
callback: () => {
|
||||
this.activateView();
|
||||
}
|
||||
});
|
||||
|
||||
// This adds a simple command that can be triggered anywhere
|
||||
this.addCommand({
|
||||
id: 'open-sample-modal-simple',
|
||||
|
@ -89,6 +102,19 @@ export default class MyPlugin extends Plugin {
|
|||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
|
||||
async activateView() {
|
||||
this.app.workspace.detachLeavesOfType(VIEW_TYPE);
|
||||
|
||||
await this.app.workspace.getRightLeaf(false).setViewState({
|
||||
type: VIEW_TYPE,
|
||||
active: true,
|
||||
});
|
||||
|
||||
this.app.workspace.revealLeaf(
|
||||
this.app.workspace.getLeavesOfType(VIEW_TYPE)[0]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SampleModal extends Modal {
|
||||
|
@ -131,4 +157,4 @@ class SampleSettingTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -22,6 +22,10 @@
|
|||
"typescript": "4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"openai": "^4.16.1"
|
||||
"@types/react": "^18.2.37",
|
||||
"@types/react-dom": "^18.2.15",
|
||||
"openai": "^4.16.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import React, { useState } from 'react';
|
||||
|
||||
const PluginView = () => {
|
||||
const [messages, setMessages] = useState([
|
||||
{
|
||||
type: 'received',
|
||||
text: `# Please send me a message indicating the following:\n- The type of writing (e.g. essay, blog post, etc.)\n- Topic\n- Audience\n- Length (in words)\n- Structure (optional) (e.g. introduction, body, conclusion)`
|
||||
},
|
||||
{
|
||||
type: 'sent',
|
||||
text: 'Hello, how are you?'
|
||||
}
|
||||
]);
|
||||
const [newMessage, setNewMessage] = useState('');
|
||||
|
||||
const handleSend = () => {
|
||||
setMessages([...messages, { type: 'sent', text: newMessage }]);
|
||||
setNewMessage('');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="agent-view-container">
|
||||
<h2>Writing Assistant</h2>
|
||||
<div className="chat-container">
|
||||
{messages.map((message, index) => (
|
||||
<div key={index} className={`chat-message ${message.type}`}>
|
||||
<p className="text" dangerouslySetInnerHTML={{ __html: message.text.replace(/\n-/g, '<br/>-') }} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="chat-input container">
|
||||
<textarea
|
||||
className="chat-input input"
|
||||
placeholder="Type your message here..."
|
||||
value={newMessage}
|
||||
onChange={e => setNewMessage(e.target.value)}
|
||||
/>
|
||||
<button className="chat-input send" onClick={handleSend}>Send</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PluginView;
|
|
@ -0,0 +1,47 @@
|
|||
import { ItemView,WorkspaceLeaf } from "obsidian";
|
||||
import * as React from "react";
|
||||
import { Root, createRoot } from "react-dom/client";
|
||||
import PluginView from './PluginView';
|
||||
import { App } from "obsidian";
|
||||
import MyPlugin from '../../main'
|
||||
|
||||
|
||||
export const VIEW_TYPE = "example-view";
|
||||
|
||||
export const AppContext = React.createContext<App | undefined>(undefined);
|
||||
|
||||
export const useApp = (): App | undefined => {
|
||||
return React.useContext(AppContext);
|
||||
};
|
||||
|
||||
export class AppView extends ItemView {
|
||||
root: Root | null = null;
|
||||
plugin: MyPlugin;
|
||||
constructor(leaf: WorkspaceLeaf, plugin: MyPlugin) {
|
||||
super(leaf)
|
||||
this.plugin = plugin
|
||||
}
|
||||
|
||||
getViewType() {
|
||||
return VIEW_TYPE
|
||||
}
|
||||
|
||||
getDisplayText() {
|
||||
return "Habitica Pane"
|
||||
}
|
||||
getIcon(): string {
|
||||
return "popup-open"
|
||||
}
|
||||
|
||||
async onOpen() {
|
||||
this.root = createRoot(this.containerEl.children[1]);
|
||||
this.root.render(
|
||||
<AppContext.Provider value={this.app}>
|
||||
<PluginView />
|
||||
</AppContext.Provider>
|
||||
);
|
||||
}
|
||||
async onClose() {
|
||||
this.root?.unmount();
|
||||
}
|
||||
}
|
58
styles.css
58
styles.css
|
@ -1,8 +1,56 @@
|
|||
/*
|
||||
.agent-view-container {
|
||||
height: 100%;
|
||||
}
|
||||
.chat-container {
|
||||
width: 100%;
|
||||
max-height: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
overflow-y: scroll;
|
||||
border: 1px solid var(--blockquote-border-color);
|
||||
border-radius: 10px;
|
||||
margin: 0.5rem 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
box-shadow: 0px 0px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
This CSS file will be included with your plugin, and
|
||||
available in the app when your plugin is enabled.
|
||||
.chat-message {
|
||||
width: 90%;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
If your plugin does not need CSS, delete this file.
|
||||
.chat-message.sent {
|
||||
background-color: var(--color-blue);
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
*/
|
||||
.chat-message.received {
|
||||
background-color: var(--color-base-50);
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.chat-message p.text {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.chat-input div.container {
|
||||
display: flex;
|
||||
max-height: 50%;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.chat-input textarea.input {
|
||||
max-height: 100%;
|
||||
flex-grow: 1;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.chat-input button.send {
|
||||
width: 15%;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"baseUrl": ".",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
|
@ -10,6 +11,7 @@
|
|||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react",
|
||||
"strictNullChecks": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
|
@ -20,5 +22,5 @@
|
|||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
, "src/ui/window.tsx" ]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue