🚧 chat view WIP
This commit is contained in:
parent
e9ac83fd1b
commit
50debaa04d
36
main.ts
36
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!
|
// Remember to rename these classes and interfaces!
|
||||||
|
|
||||||
|
@ -12,14 +13,17 @@ const DEFAULT_SETTINGS: MyPluginSettings = {
|
||||||
|
|
||||||
export default class MyPlugin extends Plugin {
|
export default class MyPlugin extends Plugin {
|
||||||
settings: MyPluginSettings;
|
settings: MyPluginSettings;
|
||||||
|
view: AppView;
|
||||||
|
|
||||||
async onload() {
|
async onload() {
|
||||||
await this.loadSettings();
|
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', 'Open Agent View', (evt: MouseEvent) => {
|
||||||
const ribbonIconEl = this.addRibbonIcon('dice', 'Sample Plugin', (evt: MouseEvent) => {
|
this.activateView();
|
||||||
// Called when the user clicks the icon.
|
|
||||||
new Notice('This is a notice!');
|
|
||||||
});
|
});
|
||||||
// Perform additional things with the ribbon
|
// Perform additional things with the ribbon
|
||||||
ribbonIconEl.addClass('my-plugin-ribbon-class');
|
ribbonIconEl.addClass('my-plugin-ribbon-class');
|
||||||
|
@ -28,6 +32,15 @@ export default class MyPlugin extends Plugin {
|
||||||
const statusBarItemEl = this.addStatusBarItem();
|
const statusBarItemEl = this.addStatusBarItem();
|
||||||
statusBarItemEl.setText('Status Bar Text');
|
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 adds a simple command that can be triggered anywhere
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: 'open-sample-modal-simple',
|
id: 'open-sample-modal-simple',
|
||||||
|
@ -89,6 +102,19 @@ export default class MyPlugin extends Plugin {
|
||||||
async saveSettings() {
|
async saveSettings() {
|
||||||
await this.saveData(this.settings);
|
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 {
|
class SampleModal extends Modal {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -22,6 +22,10 @@
|
||||||
"typescript": "4.7.4"
|
"typescript": "4.7.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"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
|
.chat-message {
|
||||||
available in the app when your plugin is enabled.
|
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": {
|
"compilerOptions": {
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"inlineSourceMap": true,
|
"inlineSourceMap": true,
|
||||||
"inlineSources": true,
|
"inlineSources": true,
|
||||||
|
@ -10,6 +11,7 @@
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
|
"jsx": "react",
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"lib": [
|
"lib": [
|
||||||
"DOM",
|
"DOM",
|
||||||
|
@ -20,5 +22,5 @@
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"**/*.ts"
|
"**/*.ts"
|
||||||
]
|
, "src/ui/window.tsx" ]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue