feat: Added getTierLabel() helper, gradient track fill via --slider-fil…
- "frontend/src/components/ChatWidget.tsx" - "frontend/src/components/ChatWidget.module.css" GSD-Task: S04/T02
This commit is contained in:
parent
d32864de6a
commit
8e27f994db
2 changed files with 69 additions and 18 deletions
|
|
@ -69,13 +69,16 @@
|
||||||
|
|
||||||
/* ── Personality slider ───────────────────────────────────── */
|
/* ── Personality slider ───────────────────────────────────── */
|
||||||
|
|
||||||
|
.sliderSection {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.sliderRow {
|
.sliderRow {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
border-bottom: 1px solid var(--color-border);
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sliderLabel {
|
.sliderLabel {
|
||||||
|
|
@ -91,7 +94,11 @@
|
||||||
appearance: none;
|
appearance: none;
|
||||||
height: 4px;
|
height: 4px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background: var(--color-border);
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
var(--color-accent) var(--slider-fill, 0%),
|
||||||
|
var(--color-border) var(--slider-fill, 0%)
|
||||||
|
);
|
||||||
outline: none;
|
outline: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
@ -126,7 +133,35 @@
|
||||||
.slider::-moz-range-track {
|
.slider::-moz-range-track {
|
||||||
height: 4px;
|
height: 4px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background: var(--color-border);
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
var(--color-accent) var(--slider-fill, 0%),
|
||||||
|
var(--color-border) var(--slider-fill, 0%)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Tier label + value ───────────────────────────────────── */
|
||||||
|
|
||||||
|
.tierInfo {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 0.375rem;
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tierLabel {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tierValue {
|
||||||
|
font-size: 0.625rem;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
opacity: 0.6;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
}
|
}
|
||||||
|
|
||||||
.headerTitle {
|
.headerTitle {
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,15 @@ function parseCitations(text: string, sources: ChatSource[]): React.ReactNode[]
|
||||||
return nodes.length > 0 ? nodes : [text];
|
return nodes.length > 0 ? nodes : [text];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Map personality weight to a human-readable tier label. */
|
||||||
|
function getTierLabel(weight: number): string {
|
||||||
|
if (weight < 0.2) return "Encyclopedic";
|
||||||
|
if (weight < 0.4) return "Subtle Reference";
|
||||||
|
if (weight < 0.6) return "Creator Tone";
|
||||||
|
if (weight < 0.8) return "Creator Voice";
|
||||||
|
return "Full Embodiment";
|
||||||
|
}
|
||||||
|
|
||||||
export default function ChatWidget({ creatorName, techniques }: ChatWidgetProps) {
|
export default function ChatWidget({ creatorName, techniques }: ChatWidgetProps) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [messages, setMessages] = useState<Message[]>([]);
|
const [messages, setMessages] = useState<Message[]>([]);
|
||||||
|
|
@ -275,6 +284,7 @@ export default function ChatWidget({ creatorName, techniques }: ChatWidgetProps)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Personality slider */}
|
{/* Personality slider */}
|
||||||
|
<div className={styles.sliderSection}>
|
||||||
<div className={styles.sliderRow}>
|
<div className={styles.sliderRow}>
|
||||||
<span className={styles.sliderLabel}>Encyclopedic</span>
|
<span className={styles.sliderLabel}>Encyclopedic</span>
|
||||||
<input
|
<input
|
||||||
|
|
@ -286,9 +296,15 @@ export default function ChatWidget({ creatorName, techniques }: ChatWidgetProps)
|
||||||
value={personalityWeight}
|
value={personalityWeight}
|
||||||
onChange={(e) => setPersonalityWeight(parseFloat(e.target.value))}
|
onChange={(e) => setPersonalityWeight(parseFloat(e.target.value))}
|
||||||
aria-label="Personality weight"
|
aria-label="Personality weight"
|
||||||
|
style={{ '--slider-fill': `${personalityWeight * 100}%` } as React.CSSProperties}
|
||||||
/>
|
/>
|
||||||
<span className={styles.sliderLabel}>Creator Voice</span>
|
<span className={styles.sliderLabel}>Creator Voice</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={styles.tierInfo}>
|
||||||
|
<span className={styles.tierLabel}>{getTierLabel(personalityWeight)}</span>
|
||||||
|
<span className={styles.tierValue}>{personalityWeight.toFixed(1)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Messages */}
|
{/* Messages */}
|
||||||
<div className={styles.messages}>
|
<div className={styles.messages}>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue