✨ custom feedback
This commit is contained in:
@@ -68,11 +68,14 @@ export function ChatPanel(): JSX.Element {
|
||||
}
|
||||
)
|
||||
|
||||
// After streaming, parse AI response for annotations
|
||||
// After streaming, parse AI response for annotations.
|
||||
// Attachment-driven messages are tagged 'custom' so they appear with a
|
||||
// distinct visual treatment in the Feedback panel.
|
||||
const currentHistory = useEditorStore.getState().chatHistory
|
||||
const lastMsg = currentHistory[currentHistory.length - 1]
|
||||
if (lastMsg?.role === 'assistant' && lastMsg.content.length > 0) {
|
||||
const parsed = parseAnnotationsFromAIResponse(lastMsg.content, activeFileContent)
|
||||
const overrideType = attachments.length > 0 ? 'custom' as const : undefined
|
||||
const parsed = parseAnnotationsFromAIResponse(lastMsg.content, activeFileContent, overrideType)
|
||||
if (parsed.length > 0) {
|
||||
setAnnotations(parsed)
|
||||
}
|
||||
|
||||
@@ -123,6 +123,14 @@
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* Wrapper that holds the type badge + optional source tag side by side */
|
||||
.fb-card-header-badges {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* Coloured type badge */
|
||||
.fb-card-badge {
|
||||
font-size: 10px;
|
||||
@@ -137,6 +145,20 @@
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
/* Small label shown on attachment-driven (custom) annotations */
|
||||
.fb-card-source-tag {
|
||||
font-size: 9px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(30, 200, 150, 0.75);
|
||||
border: 1px solid rgba(30, 200, 150, 0.3);
|
||||
border-radius: 3px;
|
||||
padding: 1px 5px;
|
||||
align-self: flex-start;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Passage excerpt — wraps so the full text is always visible */
|
||||
.fb-card-excerpt {
|
||||
font-size: 12px;
|
||||
|
||||
@@ -23,6 +23,7 @@ function badgeColor(type: TextAnnotation['type']): string {
|
||||
case 'consistency': return 'rgba(220, 80, 80, 0.75)'
|
||||
case 'style': return 'rgba(80, 160, 255, 0.75)'
|
||||
case 'critique': return 'rgba(160, 80, 220, 0.75)'
|
||||
case 'custom': return 'rgba(30, 200, 150, 0.8)'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +42,11 @@ function FeedbackCard({ ann, autoAnalyse, onDismiss }: FeedbackCardProps): JSX.E
|
||||
const [state, setState] = useState<AnalysisState>(() => {
|
||||
const cached = tooltipAnalysisCache.get(ann.id)
|
||||
if (cached) return { status: 'done', text: cached.text, suggestion: cached.suggestion }
|
||||
// Custom (attachment-driven) annotations already carry their analysis — show
|
||||
// the problem description and suggestion immediately without an extra AI call.
|
||||
if (ann.type === 'custom') {
|
||||
return { status: 'done', text: ann.message, suggestion: ann.suggestion ?? null }
|
||||
}
|
||||
return { status: 'idle' }
|
||||
})
|
||||
|
||||
@@ -85,7 +91,12 @@ function FeedbackCard({ ann, autoAnalyse, onDismiss }: FeedbackCardProps): JSX.E
|
||||
{/* Header — click to jump to passage in editor */}
|
||||
<div className="fb-card-header" onClick={() => scrollToAnnotation(ann)} title="Jump to passage">
|
||||
<div className="fb-card-header-top">
|
||||
<span className="fb-card-badge">{typeName}</span>
|
||||
<div className="fb-card-header-badges">
|
||||
<span className="fb-card-badge">{typeName}</span>
|
||||
{ann.type === 'custom' && (
|
||||
<span className="fb-card-source-tag">from attachment</span>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
className="fb-card-dismiss"
|
||||
onClick={(e) => { e.stopPropagation(); onDismiss() }}
|
||||
@@ -135,7 +146,7 @@ function FeedbackCard({ ann, autoAnalyse, onDismiss }: FeedbackCardProps): JSX.E
|
||||
}
|
||||
|
||||
export function FeedbackPanel(): JSX.Element {
|
||||
const { annotations, setAnnotations, removeAnnotation } = useEditorStore()
|
||||
const { annotations, clearAnnotations, removeAnnotation } = useEditorStore()
|
||||
const [analyseAll, setAnalyseAll] = useState(false)
|
||||
|
||||
// Reset "Analyse all" whenever the annotation set changes (new critique run),
|
||||
@@ -149,7 +160,7 @@ export function FeedbackPanel(): JSX.Element {
|
||||
}, [annotations])
|
||||
|
||||
function handleClearAll(): void {
|
||||
setAnnotations([])
|
||||
clearAnnotations()
|
||||
tooltipAnalysisCache.clear()
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useEffect } from 'react'
|
||||
import { useEditorStore } from '../../store/editorStore'
|
||||
import { detectPassiveVoice } from '../../utils/passiveVoice'
|
||||
import { parseAnnotationsFromAIResponse } from '../../utils/annotationParser'
|
||||
import { tooltipAnalysisCache } from '../Editor/MarkdownEditor'
|
||||
import './Toolbar.css'
|
||||
|
||||
function countWords(text: string): number {
|
||||
@@ -167,7 +168,7 @@ export function AnalysisToolbar(): JSX.Element {
|
||||
{annotations.length > 0 && (
|
||||
<button
|
||||
className="toolbar-btn toolbar-btn-clear"
|
||||
onClick={clearAnnotations}
|
||||
onClick={() => { clearAnnotations(); tooltipAnalysisCache.clear() }}
|
||||
title="Remove all highlights"
|
||||
>
|
||||
Clear
|
||||
|
||||
Reference in New Issue
Block a user