feat(initial): scaffold @push.rocks/smartchat with core, CLI, and web layers
Three-layer architecture built on @push.rocks/smartagent: - ts/ — ChatSession wrapping runAgent() with conversation state management - ts_cli/ — ink-based terminal chat TUI (React.createElement, no JSX) - ts_web/ — Lit web components (smartchat-window, smartchat-message, smartchat-input)
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
import { LitElement, html, css } from './plugins.js';
|
||||
import type { CSSResult, TemplateResult } from './plugins.js';
|
||||
|
||||
export class SmartchatInput extends LitElement {
|
||||
declare disabled: boolean;
|
||||
declare placeholder: string;
|
||||
private value = '';
|
||||
|
||||
static properties = {
|
||||
disabled: { type: Boolean },
|
||||
placeholder: { type: String },
|
||||
};
|
||||
|
||||
static styles: CSSResult = css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.input-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
background: var(--smartchat-input-bg, #1f2937);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--smartchat-input-border, #374151);
|
||||
}
|
||||
|
||||
.input-row:focus-within {
|
||||
border-color: var(--smartchat-input-focus, #6366f1);
|
||||
}
|
||||
|
||||
input {
|
||||
flex: 1;
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: var(--smartchat-input-text, #e5e7eb);
|
||||
font-size: 14px;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
input::placeholder {
|
||||
color: var(--smartchat-input-placeholder, #6b7280);
|
||||
}
|
||||
|
||||
button {
|
||||
background: var(--smartchat-send-bg, #6366f1);
|
||||
color: var(--smartchat-send-text, #fff);
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 6px 16px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
`;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.disabled = false;
|
||||
this.placeholder = 'Type a message...';
|
||||
}
|
||||
|
||||
private handleKeydown(e: KeyboardEvent) {
|
||||
if (e.key === 'Enter' && !e.shiftKey && this.value.trim()) {
|
||||
this.submit();
|
||||
}
|
||||
}
|
||||
|
||||
private handleInput(e: Event) {
|
||||
this.value = (e.target as HTMLInputElement).value;
|
||||
}
|
||||
|
||||
private submit() {
|
||||
if (!this.value.trim() || this.disabled) return;
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('send', {
|
||||
detail: { text: this.value.trim() },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
);
|
||||
this.value = '';
|
||||
const input = this.shadowRoot?.querySelector('input');
|
||||
if (input) input.value = '';
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
return html`
|
||||
<div class="input-row">
|
||||
<input
|
||||
type="text"
|
||||
.value=${this.value}
|
||||
@input=${this.handleInput}
|
||||
@keydown=${this.handleKeydown}
|
||||
placeholder=${this.disabled ? 'Waiting for response...' : this.placeholder}
|
||||
?disabled=${this.disabled}
|
||||
/>
|
||||
<button @click=${this.submit} ?disabled=${this.disabled}>
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('smartchat-input', SmartchatInput);
|
||||
Reference in New Issue
Block a user