refactor: migrate session, script-builder, account to Design System v4
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -36,27 +36,27 @@ export function DeleteAccountModal({ onClose }: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
|
||||||
<div className="glass-card-static w-full max-w-md p-6">
|
<div className="card-flat w-full max-w-md p-6">
|
||||||
<div className="flex items-center gap-2 text-rose-500 mb-4">
|
<div className="flex items-center gap-2 text-rose-500 mb-4">
|
||||||
<AlertTriangle className="h-5 w-5" />
|
<AlertTriangle className="h-5 w-5" />
|
||||||
<h2 className="text-lg font-semibold font-heading text-foreground">Delete Account</h2>
|
<h2 className="text-lg font-semibold font-heading text-[#e2e5eb]">Delete Account</h2>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-muted-foreground mb-4">
|
<p className="text-sm text-[#848b9b] mb-4">
|
||||||
This action is <strong className="text-rose-400">permanent</strong>. Your account, data,
|
This action is <strong className="text-rose-400">permanent</strong>. Your account, data,
|
||||||
and all associated flows will be permanently deleted.
|
and all associated flows will be permanently deleted.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form onSubmit={handleDelete} className="space-y-4">
|
<form onSubmit={handleDelete} className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-foreground">Confirm Password</label>
|
<label className="block text-sm font-medium text-[#e2e5eb]">Confirm Password</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
required
|
required
|
||||||
className={cn(
|
className={cn(
|
||||||
'mt-1 block w-full rounded-[10px] border border-border bg-card px-3 py-2',
|
'mt-1 block w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-3 py-2',
|
||||||
'text-foreground focus:border-primary focus:outline-hidden'
|
'text-[#e2e5eb] focus:border-primary focus:outline-hidden'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -68,8 +68,8 @@ export function DeleteAccountModal({ onClose }: Props) {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className={cn(
|
className={cn(
|
||||||
'rounded-[10px] px-4 py-2 text-sm font-medium',
|
'rounded-lg px-4 py-2 text-sm font-medium',
|
||||||
'bg-white/[0.04] border border-brand-border text-foreground'
|
'bg-white/[0.04] border border-brand-border text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
@@ -78,7 +78,7 @@ export function DeleteAccountModal({ onClose }: Props) {
|
|||||||
type="submit"
|
type="submit"
|
||||||
disabled={isSubmitting || !password}
|
disabled={isSubmitting || !password}
|
||||||
className={cn(
|
className={cn(
|
||||||
'rounded-[10px] px-4 py-2 text-sm font-semibold',
|
'rounded-lg px-4 py-2 text-sm font-semibold',
|
||||||
'bg-rose-500 text-white hover:bg-rose-400 disabled:opacity-50'
|
'bg-rose-500 text-white hover:bg-rose-400 disabled:opacity-50'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -31,21 +31,21 @@ export function LeaveAccountModal({ accountName, onClose }: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
|
||||||
<div className="glass-card-static w-full max-w-md p-6">
|
<div className="card-flat w-full max-w-md p-6">
|
||||||
<div className="flex items-center gap-2 text-amber-400 mb-4">
|
<div className="flex items-center gap-2 text-amber-400 mb-4">
|
||||||
<AlertTriangle className="h-5 w-5" />
|
<AlertTriangle className="h-5 w-5" />
|
||||||
<h2 className="text-lg font-semibold font-heading text-foreground">Leave Account</h2>
|
<h2 className="text-lg font-semibold font-heading text-[#e2e5eb]">Leave Account</h2>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-muted-foreground mb-4">
|
<p className="text-sm text-[#848b9b] mb-4">
|
||||||
Are you sure you want to leave <strong className="text-foreground">{accountName}</strong>?
|
Are you sure you want to leave <strong className="text-[#e2e5eb]">{accountName}</strong>?
|
||||||
A new personal account will be created for you.
|
A new personal account will be created for you.
|
||||||
</p>
|
</p>
|
||||||
<div className="flex justify-end gap-3">
|
<div className="flex justify-end gap-3">
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className={cn(
|
className={cn(
|
||||||
'rounded-[10px] px-4 py-2 text-sm font-medium',
|
'rounded-lg px-4 py-2 text-sm font-medium',
|
||||||
'bg-white/[0.04] border border-brand-border text-foreground'
|
'bg-white/[0.04] border border-brand-border text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
@@ -54,7 +54,7 @@ export function LeaveAccountModal({ accountName, onClose }: Props) {
|
|||||||
onClick={handleLeave}
|
onClick={handleLeave}
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
className={cn(
|
className={cn(
|
||||||
'rounded-[10px] px-4 py-2 text-sm font-semibold',
|
'rounded-lg px-4 py-2 text-sm font-semibold',
|
||||||
'bg-rose-500 text-white hover:bg-rose-400 disabled:opacity-50'
|
'bg-rose-500 text-white hover:bg-rose-400 disabled:opacity-50'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -173,16 +173,16 @@ export function NotificationSettings() {
|
|||||||
{/* Section header */}
|
{/* Section header */}
|
||||||
<div className="mb-6 flex items-center justify-between">
|
<div className="mb-6 flex items-center justify-between">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<Bell className="h-6 w-6 text-muted-foreground" />
|
<Bell className="h-6 w-6 text-[#848b9b]" />
|
||||||
<h2 className="text-xl font-semibold font-heading text-foreground">Notifications</h2>
|
<h2 className="text-xl font-semibold font-heading text-[#e2e5eb]">Notifications</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative" ref={dropdownRef}>
|
<div className="relative" ref={dropdownRef}>
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowDropdown(!showDropdown)}
|
onClick={() => setShowDropdown(!showDropdown)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center gap-2 rounded-[10px] px-4 py-2 text-sm font-medium',
|
'inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium',
|
||||||
'bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground',
|
'bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-[#e2e5eb]',
|
||||||
'hover:border-[rgba(255,255,255,0.12)] transition-all'
|
'hover:border-[rgba(255,255,255,0.12)] transition-all'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -192,16 +192,16 @@ export function NotificationSettings() {
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
{showDropdown && (
|
{showDropdown && (
|
||||||
<div className="absolute right-0 mt-1 z-20 w-48 rounded-xl border border-border bg-card shadow-xl">
|
<div className="absolute right-0 mt-1 z-20 w-48 rounded-xl border border-[#1e2130] bg-[#14161d] shadow-xl">
|
||||||
{(Object.entries(CHANNEL_LABELS) as [ChannelType, string][]).map(([key, label]) => {
|
{(Object.entries(CHANNEL_LABELS) as [ChannelType, string][]).map(([key, label]) => {
|
||||||
const Icon = CHANNEL_ICONS[key]
|
const Icon = CHANNEL_ICONS[key]
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
key={key}
|
key={key}
|
||||||
onClick={() => handleAddChannel(key)}
|
onClick={() => handleAddChannel(key)}
|
||||||
className="flex w-full items-center gap-2.5 px-4 py-2.5 text-sm text-foreground hover:bg-[rgba(255,255,255,0.04)] first:rounded-t-xl last:rounded-b-xl transition-colors"
|
className="flex w-full items-center gap-2.5 px-4 py-2.5 text-sm text-[#e2e5eb] hover:bg-[rgba(255,255,255,0.04)] first:rounded-t-xl last:rounded-b-xl transition-colors"
|
||||||
>
|
>
|
||||||
<Icon className="h-4 w-4 text-muted-foreground" />
|
<Icon className="h-4 w-4 text-[#848b9b]" />
|
||||||
{label}
|
{label}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
@@ -214,15 +214,15 @@ export function NotificationSettings() {
|
|||||||
{/* Loading */}
|
{/* Loading */}
|
||||||
{loading && (
|
{loading && (
|
||||||
<div className="flex justify-center py-8">
|
<div className="flex justify-center py-8">
|
||||||
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
|
<Loader2 className="h-6 w-6 animate-spin text-[#848b9b]" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Empty state */}
|
{/* Empty state */}
|
||||||
{!loading && configs.length === 0 && !addingChannel && (
|
{!loading && configs.length === 0 && !addingChannel && (
|
||||||
<div className="glass-card-static p-6 text-center">
|
<div className="card-flat p-6 text-center">
|
||||||
<Bell className="mx-auto h-8 w-8 text-muted-foreground/50 mb-3" />
|
<Bell className="mx-auto h-8 w-8 text-[#848b9b]/50 mb-3" />
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-[#848b9b]">
|
||||||
No notification channels configured. Add a channel to receive alerts for session events.
|
No notification channels configured. Add a channel to receive alerts for session events.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -234,11 +234,11 @@ export function NotificationSettings() {
|
|||||||
{configs.map(config => {
|
{configs.map(config => {
|
||||||
const Icon = CHANNEL_ICONS[config.channel]
|
const Icon = CHANNEL_ICONS[config.channel]
|
||||||
return (
|
return (
|
||||||
<div key={config.id} className="glass-card-static p-5">
|
<div key={config.id} className="card-flat p-5">
|
||||||
{/* Header row */}
|
{/* Header row */}
|
||||||
<div className="flex items-center gap-3 mb-4">
|
<div className="flex items-center gap-3 mb-4">
|
||||||
<Icon className="h-5 w-5 text-muted-foreground" />
|
<Icon className="h-5 w-5 text-[#848b9b]" />
|
||||||
<span className="text-sm font-medium text-foreground">
|
<span className="text-sm font-medium text-[#e2e5eb]">
|
||||||
{CHANNEL_LABELS[config.channel]}
|
{CHANNEL_LABELS[config.channel]}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
@@ -248,8 +248,8 @@ export function NotificationSettings() {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<span className={cn(
|
<span className={cn(
|
||||||
'text-xs font-label',
|
'text-xs font-sans text-xs',
|
||||||
config.is_active ? 'text-emerald-400' : 'text-muted-foreground'
|
config.is_active ? 'text-emerald-400' : 'text-[#848b9b]'
|
||||||
)}>
|
)}>
|
||||||
{config.is_active ? 'Active' : 'Inactive'}
|
{config.is_active ? 'Active' : 'Inactive'}
|
||||||
</span>
|
</span>
|
||||||
@@ -259,20 +259,20 @@ export function NotificationSettings() {
|
|||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
{config.webhook_url && (
|
{config.webhook_url && (
|
||||||
<div>
|
<div>
|
||||||
<span className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground">
|
<span className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b]">
|
||||||
Webhook URL
|
Webhook URL
|
||||||
</span>
|
</span>
|
||||||
<p className="mt-0.5 text-sm text-foreground font-mono">
|
<p className="mt-0.5 text-sm text-[#e2e5eb] font-mono">
|
||||||
{maskWebhookUrl(config.webhook_url)}
|
{maskWebhookUrl(config.webhook_url)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{config.email_addresses && config.email_addresses.length > 0 && (
|
{config.email_addresses && config.email_addresses.length > 0 && (
|
||||||
<div>
|
<div>
|
||||||
<span className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground">
|
<span className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b]">
|
||||||
Email Addresses
|
Email Addresses
|
||||||
</span>
|
</span>
|
||||||
<p className="mt-0.5 text-sm text-foreground">
|
<p className="mt-0.5 text-sm text-[#e2e5eb]">
|
||||||
{config.email_addresses.join(', ')}
|
{config.email_addresses.join(', ')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -281,7 +281,7 @@ export function NotificationSettings() {
|
|||||||
|
|
||||||
{/* Event toggles */}
|
{/* Event toggles */}
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<span className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground">
|
<span className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b]">
|
||||||
Events
|
Events
|
||||||
</span>
|
</span>
|
||||||
<div className="mt-2 grid gap-2 sm:grid-cols-2">
|
<div className="mt-2 grid gap-2 sm:grid-cols-2">
|
||||||
@@ -294,28 +294,28 @@ export function NotificationSettings() {
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={config.events_enabled[eventKey] ?? false}
|
checked={config.events_enabled[eventKey] ?? false}
|
||||||
onChange={() => handleToggleEvent(config, eventKey)}
|
onChange={() => handleToggleEvent(config, eventKey)}
|
||||||
className="h-3.5 w-3.5 rounded border-border bg-card text-primary focus:ring-primary/30 focus:ring-offset-0 cursor-pointer accent-[#06b6d4]"
|
className="h-3.5 w-3.5 rounded border-[#1e2130] bg-[#14161d] text-primary focus:ring-primary/30 focus:ring-offset-0 cursor-pointer accent-[#06b6d4]"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm text-foreground">{eventLabel}</span>
|
<span className="text-sm text-[#e2e5eb]">{eventLabel}</span>
|
||||||
</label>
|
</label>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Action buttons */}
|
{/* Action buttons */}
|
||||||
<div className="flex items-center gap-3 pt-2 border-t border-border">
|
<div className="flex items-center gap-3 pt-2 border-t border-[#1e2130]">
|
||||||
<button
|
<button
|
||||||
onClick={() => handleToggleActive(config)}
|
onClick={() => handleToggleActive(config)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center gap-1.5 rounded-[10px] px-3 py-1.5 text-sm font-medium',
|
'inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium',
|
||||||
'bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground',
|
'bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-[#e2e5eb]',
|
||||||
'hover:border-[rgba(255,255,255,0.12)] transition-all'
|
'hover:border-[rgba(255,255,255,0.12)] transition-all'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{config.is_active ? (
|
{config.is_active ? (
|
||||||
<ToggleRight className="h-4 w-4 text-emerald-400" />
|
<ToggleRight className="h-4 w-4 text-emerald-400" />
|
||||||
) : (
|
) : (
|
||||||
<ToggleLeft className="h-4 w-4 text-muted-foreground" />
|
<ToggleLeft className="h-4 w-4 text-[#848b9b]" />
|
||||||
)}
|
)}
|
||||||
{config.is_active ? 'Disable' : 'Enable'}
|
{config.is_active ? 'Disable' : 'Enable'}
|
||||||
</button>
|
</button>
|
||||||
@@ -324,8 +324,8 @@ export function NotificationSettings() {
|
|||||||
onClick={() => handleTest(config.id)}
|
onClick={() => handleTest(config.id)}
|
||||||
disabled={testingId === config.id}
|
disabled={testingId === config.id}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center gap-1.5 rounded-[10px] px-3 py-1.5 text-sm font-medium',
|
'inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium',
|
||||||
'bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground',
|
'bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-[#e2e5eb]',
|
||||||
'hover:border-[rgba(255,255,255,0.12)] transition-all',
|
'hover:border-[rgba(255,255,255,0.12)] transition-all',
|
||||||
'disabled:opacity-50 disabled:cursor-not-allowed'
|
'disabled:opacity-50 disabled:cursor-not-allowed'
|
||||||
)}
|
)}
|
||||||
@@ -349,7 +349,7 @@ export function NotificationSettings() {
|
|||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
onClick={() => setConfirmDeleteId(config.id)}
|
onClick={() => setConfirmDeleteId(config.id)}
|
||||||
className="ml-auto inline-flex items-center gap-1.5 text-sm text-muted-foreground hover:text-red-400 transition-colors"
|
className="ml-auto inline-flex items-center gap-1.5 text-sm text-[#848b9b] hover:text-red-400 transition-colors"
|
||||||
>
|
>
|
||||||
<Trash2 className="h-4 w-4" />
|
<Trash2 className="h-4 w-4" />
|
||||||
Remove
|
Remove
|
||||||
@@ -362,20 +362,20 @@ export function NotificationSettings() {
|
|||||||
|
|
||||||
{/* Inline add form */}
|
{/* Inline add form */}
|
||||||
{addingChannel && (
|
{addingChannel && (
|
||||||
<div className="glass-card-static p-5">
|
<div className="card-flat p-5">
|
||||||
<div className="flex items-center gap-3 mb-4">
|
<div className="flex items-center gap-3 mb-4">
|
||||||
{(() => {
|
{(() => {
|
||||||
const Icon = CHANNEL_ICONS[addingChannel]
|
const Icon = CHANNEL_ICONS[addingChannel]
|
||||||
return <Icon className="h-5 w-5 text-muted-foreground" />
|
return <Icon className="h-5 w-5 text-[#848b9b]" />
|
||||||
})()}
|
})()}
|
||||||
<span className="text-sm font-medium text-foreground">
|
<span className="text-sm font-medium text-[#e2e5eb]">
|
||||||
Add {CHANNEL_LABELS[addingChannel]}
|
Add {CHANNEL_LABELS[addingChannel]}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{addingChannel === 'email' ? (
|
{addingChannel === 'email' ? (
|
||||||
<div>
|
<div>
|
||||||
<label className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground">
|
<label className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b]">
|
||||||
Email Addresses
|
Email Addresses
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
@@ -385,13 +385,13 @@ export function NotificationSettings() {
|
|||||||
placeholder="user@example.com, team@example.com"
|
placeholder="user@example.com, team@example.com"
|
||||||
className="mt-1"
|
className="mt-1"
|
||||||
/>
|
/>
|
||||||
<p className="mt-1 text-xs text-muted-foreground">
|
<p className="mt-1 text-xs text-[#848b9b]">
|
||||||
Separate multiple addresses with commas
|
Separate multiple addresses with commas
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<label className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground">
|
<label className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b]">
|
||||||
Webhook URL
|
Webhook URL
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
@@ -413,9 +413,9 @@ export function NotificationSettings() {
|
|||||||
onClick={handleSaveNew}
|
onClick={handleSaveNew}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center gap-2 rounded-[10px] px-5 py-2.5 text-sm font-semibold',
|
'inline-flex items-center gap-2 rounded-lg px-5 py-2.5 text-sm font-semibold',
|
||||||
'bg-gradient-brand text-[#101114] shadow-lg shadow-primary/20',
|
'bg-[#22d3ee] text-white',
|
||||||
'hover:opacity-90 active:scale-[0.97] transition-all',
|
'hover:brightness-110 active:scale-[0.98] transition-all',
|
||||||
'disabled:opacity-50 disabled:cursor-not-allowed'
|
'disabled:opacity-50 disabled:cursor-not-allowed'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -424,7 +424,7 @@ export function NotificationSettings() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setAddingChannel(null)}
|
onClick={() => setAddingChannel(null)}
|
||||||
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
className="text-sm text-[#848b9b] hover:text-[#e2e5eb] transition-colors"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -40,27 +40,27 @@ export function TransferOwnershipModal({ members, onClose, onTransferred }: Prop
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
|
||||||
<div className="glass-card-static w-full max-w-md p-6">
|
<div className="card-flat w-full max-w-md p-6">
|
||||||
<div className="flex items-center gap-2 text-amber-400 mb-4">
|
<div className="flex items-center gap-2 text-amber-400 mb-4">
|
||||||
<AlertTriangle className="h-5 w-5" />
|
<AlertTriangle className="h-5 w-5" />
|
||||||
<h2 className="text-lg font-semibold font-heading text-foreground">Transfer Ownership</h2>
|
<h2 className="text-lg font-semibold font-heading text-[#e2e5eb]">Transfer Ownership</h2>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-muted-foreground mb-4">
|
<p className="text-sm text-[#848b9b] mb-4">
|
||||||
This will make the selected member the new account owner. You will become an engineer.
|
This will make the selected member the new account owner. You will become an engineer.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{nonOwnerMembers.length === 0 ? (
|
{nonOwnerMembers.length === 0 ? (
|
||||||
<p className="text-sm text-muted-foreground">No other members to transfer to.</p>
|
<p className="text-sm text-[#848b9b]">No other members to transfer to.</p>
|
||||||
) : (
|
) : (
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-foreground">New Owner</label>
|
<label className="block text-sm font-medium text-[#e2e5eb]">New Owner</label>
|
||||||
<select
|
<select
|
||||||
value={targetUserId}
|
value={targetUserId}
|
||||||
onChange={(e) => setTargetUserId(e.target.value)}
|
onChange={(e) => setTargetUserId(e.target.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'mt-1 block w-full rounded-[10px] border border-border bg-card px-3 py-2',
|
'mt-1 block w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-3 py-2',
|
||||||
'text-foreground focus:border-primary focus:outline-hidden'
|
'text-[#e2e5eb] focus:border-primary focus:outline-hidden'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{nonOwnerMembers.map((m) => (
|
{nonOwnerMembers.map((m) => (
|
||||||
@@ -69,15 +69,15 @@ export function TransferOwnershipModal({ members, onClose, onTransferred }: Prop
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-foreground">Your Password</label>
|
<label className="block text-sm font-medium text-[#e2e5eb]">Your Password</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
required
|
required
|
||||||
className={cn(
|
className={cn(
|
||||||
'mt-1 block w-full rounded-[10px] border border-border bg-card px-3 py-2',
|
'mt-1 block w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-3 py-2',
|
||||||
'text-foreground focus:border-primary focus:outline-hidden'
|
'text-[#e2e5eb] focus:border-primary focus:outline-hidden'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -89,8 +89,8 @@ export function TransferOwnershipModal({ members, onClose, onTransferred }: Prop
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className={cn(
|
className={cn(
|
||||||
'rounded-[10px] px-4 py-2 text-sm font-medium',
|
'rounded-lg px-4 py-2 text-sm font-medium',
|
||||||
'bg-white/[0.04] border border-brand-border text-foreground'
|
'bg-white/[0.04] border border-brand-border text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
@@ -99,7 +99,7 @@ export function TransferOwnershipModal({ members, onClose, onTransferred }: Prop
|
|||||||
type="submit"
|
type="submit"
|
||||||
disabled={isSubmitting || !password}
|
disabled={isSubmitting || !password}
|
||||||
className={cn(
|
className={cn(
|
||||||
'rounded-[10px] px-4 py-2 text-sm font-semibold',
|
'rounded-lg px-4 py-2 text-sm font-semibold',
|
||||||
'bg-amber-500 text-brand-dark hover:bg-amber-400',
|
'bg-amber-500 text-brand-dark hover:bg-amber-400',
|
||||||
'disabled:opacity-50'
|
'disabled:opacity-50'
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -63,16 +63,16 @@ export function SaveToLibraryDialog({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 z-50 bg-black/80 backdrop-blur-sm flex items-center justify-center"
|
className="fixed inset-0 z-50 bg-black/80 flex items-center justify-center"
|
||||||
onClick={(e) => { if (e.target === e.currentTarget) onClose() }}
|
onClick={(e) => { if (e.target === e.currentTarget) onClose() }}
|
||||||
>
|
>
|
||||||
<div className="glass-card-static max-w-md w-full mx-4 rounded-xl overflow-hidden">
|
<div className="card-flat max-w-md w-full mx-4 rounded-xl overflow-hidden">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between px-5 py-3.5 border-b border-[rgba(255,255,255,0.06)]">
|
<div className="flex items-center justify-between px-5 py-3.5 border-b border-[rgba(255,255,255,0.06)]">
|
||||||
<h3 className="text-sm font-heading font-bold text-foreground">Save to Library</h3>
|
<h3 className="text-sm font-heading font-bold text-[#e2e5eb]">Save to Library</h3>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="p-1.5 rounded-lg text-muted-foreground hover:text-foreground hover:bg-[rgba(255,255,255,0.06)] transition-colors"
|
className="p-1.5 rounded-lg text-[#848b9b] hover:text-[#e2e5eb] hover:bg-[rgba(255,255,255,0.06)] transition-colors"
|
||||||
>
|
>
|
||||||
<X size={18} />
|
<X size={18} />
|
||||||
</button>
|
</button>
|
||||||
@@ -82,7 +82,7 @@ export function SaveToLibraryDialog({
|
|||||||
<form onSubmit={handleSubmit} className="p-5 space-y-4">
|
<form onSubmit={handleSubmit} className="p-5 space-y-4">
|
||||||
{/* Name */}
|
{/* Name */}
|
||||||
<div>
|
<div>
|
||||||
<label className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground mb-1.5 block">
|
<label className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b] mb-1.5 block">
|
||||||
Name *
|
Name *
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -91,8 +91,8 @@ export function SaveToLibraryDialog({
|
|||||||
onChange={(e) => setName(e.target.value)}
|
onChange={(e) => setName(e.target.value)}
|
||||||
required
|
required
|
||||||
className={cn(
|
className={cn(
|
||||||
"w-full rounded-[10px] px-3 py-2 text-sm",
|
"w-full rounded-lg px-3 py-2 text-sm",
|
||||||
"border border-border bg-card text-foreground placeholder:text-muted-foreground",
|
"border border-[#1e2130] bg-[#14161d] text-[#e2e5eb] placeholder:text-[#848b9b]",
|
||||||
"focus:outline-none focus:border-[rgba(6,182,212,0.3)] transition-colors"
|
"focus:outline-none focus:border-[rgba(6,182,212,0.3)] transition-colors"
|
||||||
)}
|
)}
|
||||||
placeholder="Script name"
|
placeholder="Script name"
|
||||||
@@ -101,7 +101,7 @@ export function SaveToLibraryDialog({
|
|||||||
|
|
||||||
{/* Description */}
|
{/* Description */}
|
||||||
<div>
|
<div>
|
||||||
<label className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground mb-1.5 block">
|
<label className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b] mb-1.5 block">
|
||||||
Description
|
Description
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
@@ -109,8 +109,8 @@ export function SaveToLibraryDialog({
|
|||||||
onChange={(e) => setDescription(e.target.value)}
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
rows={3}
|
rows={3}
|
||||||
className={cn(
|
className={cn(
|
||||||
"w-full rounded-[10px] px-3 py-2 text-sm resize-none",
|
"w-full rounded-lg px-3 py-2 text-sm resize-none",
|
||||||
"border border-border bg-card text-foreground placeholder:text-muted-foreground",
|
"border border-[#1e2130] bg-[#14161d] text-[#e2e5eb] placeholder:text-[#848b9b]",
|
||||||
"focus:outline-none focus:border-[rgba(6,182,212,0.3)] transition-colors"
|
"focus:outline-none focus:border-[rgba(6,182,212,0.3)] transition-colors"
|
||||||
)}
|
)}
|
||||||
placeholder="What does this script do?"
|
placeholder="What does this script do?"
|
||||||
@@ -119,15 +119,15 @@ export function SaveToLibraryDialog({
|
|||||||
|
|
||||||
{/* Category */}
|
{/* Category */}
|
||||||
<div>
|
<div>
|
||||||
<label className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground mb-1.5 block">
|
<label className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b] mb-1.5 block">
|
||||||
Category
|
Category
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
value={categoryId}
|
value={categoryId}
|
||||||
onChange={(e) => setCategoryId(e.target.value)}
|
onChange={(e) => setCategoryId(e.target.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"w-full rounded-[10px] px-3 py-2 text-sm",
|
"w-full rounded-lg px-3 py-2 text-sm",
|
||||||
"border border-border bg-card text-foreground",
|
"border border-[#1e2130] bg-[#14161d] text-[#e2e5eb]",
|
||||||
"focus:outline-none focus:border-[rgba(6,182,212,0.3)] transition-colors"
|
"focus:outline-none focus:border-[rgba(6,182,212,0.3)] transition-colors"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -144,9 +144,9 @@ export function SaveToLibraryDialog({
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={shareWithTeam}
|
checked={shareWithTeam}
|
||||||
onChange={(e) => setShareWithTeam(e.target.checked)}
|
onChange={(e) => setShareWithTeam(e.target.checked)}
|
||||||
className="w-4 h-4 rounded border-border bg-card text-cyan-500 focus:ring-cyan-500/20"
|
className="w-4 h-4 rounded border-[#1e2130] bg-[#14161d] text-cyan-500 focus:ring-cyan-500/20"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm text-foreground">Share with team</span>
|
<span className="text-sm text-[#e2e5eb]">Share with team</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/* Error */}
|
{/* Error */}
|
||||||
@@ -160,8 +160,8 @@ export function SaveToLibraryDialog({
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className={cn(
|
className={cn(
|
||||||
"px-4 py-2 rounded-[10px] text-sm font-medium transition-colors",
|
"px-4 py-2 rounded-lg text-sm font-medium transition-colors",
|
||||||
"bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground hover:border-[rgba(255,255,255,0.12)]"
|
"bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-[#e2e5eb] hover:border-[rgba(255,255,255,0.12)]"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
@@ -170,8 +170,8 @@ export function SaveToLibraryDialog({
|
|||||||
type="submit"
|
type="submit"
|
||||||
disabled={!name.trim() || isSaving}
|
disabled={!name.trim() || isSaving}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-2 px-4 py-2 rounded-[10px] text-sm font-semibold transition-all",
|
"flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-semibold transition-all",
|
||||||
"bg-gradient-brand text-[#101114] hover:opacity-90 active:scale-[0.97]",
|
"bg-[#22d3ee] text-white hover:brightness-110 active:scale-[0.98]",
|
||||||
"disabled:opacity-50 disabled:cursor-not-allowed"
|
"disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -30,13 +30,13 @@ export function ScriptBuilderChat({
|
|||||||
return (
|
return (
|
||||||
<div className="flex-1 flex items-center justify-center p-8">
|
<div className="flex-1 flex items-center justify-center p-8">
|
||||||
<div className="text-center max-w-md">
|
<div className="text-center max-w-md">
|
||||||
<div className="w-14 h-14 rounded-2xl bg-gradient-brand flex items-center justify-center mx-auto mb-4">
|
<div className="w-14 h-14 rounded-2xl bg-[#22d3ee] flex items-center justify-center mx-auto mb-4">
|
||||||
<Bot size={28} className="text-[#101114]" />
|
<Bot size={28} className="text-white" />
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-lg font-heading font-bold text-foreground mb-2">
|
<h2 className="text-lg font-heading font-bold text-[#e2e5eb] mb-2">
|
||||||
Script Builder
|
Script Builder
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
<p className="text-sm text-[#848b9b] leading-relaxed">
|
||||||
Describe the script you need and AI will generate it for you. You can iterate on the script,
|
Describe the script you need and AI will generate it for you. You can iterate on the script,
|
||||||
preview it, and save it to your library.
|
preview it, and save it to your library.
|
||||||
</p>
|
</p>
|
||||||
@@ -65,8 +65,8 @@ export function ScriptBuilderChat({
|
|||||||
className={cn(
|
className={cn(
|
||||||
"max-w-[85%] rounded-xl px-4 py-3 text-sm",
|
"max-w-[85%] rounded-xl px-4 py-3 text-sm",
|
||||||
msg.role === 'user'
|
msg.role === 'user'
|
||||||
? "bg-[rgba(6,182,212,0.08)] border border-[rgba(6,182,212,0.15)] text-foreground"
|
? "bg-[rgba(6,182,212,0.08)] border border-[rgba(6,182,212,0.15)] text-[#e2e5eb]"
|
||||||
: "glass-card-static"
|
: "card-flat"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{msg.role === 'assistant' ? (
|
{msg.role === 'assistant' ? (
|
||||||
@@ -90,7 +90,7 @@ export function ScriptBuilderChat({
|
|||||||
|
|
||||||
{msg.role === 'user' && (
|
{msg.role === 'user' && (
|
||||||
<div className="shrink-0 w-8 h-8 rounded-lg bg-[rgba(255,255,255,0.06)] flex items-center justify-center mt-0.5">
|
<div className="shrink-0 w-8 h-8 rounded-lg bg-[rgba(255,255,255,0.06)] flex items-center justify-center mt-0.5">
|
||||||
<User size={16} className="text-muted-foreground" />
|
<User size={16} className="text-[#848b9b]" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -101,9 +101,9 @@ export function ScriptBuilderChat({
|
|||||||
<div className="shrink-0 w-8 h-8 rounded-lg bg-[rgba(6,182,212,0.1)] flex items-center justify-center">
|
<div className="shrink-0 w-8 h-8 rounded-lg bg-[rgba(6,182,212,0.1)] flex items-center justify-center">
|
||||||
<Bot size={16} className="text-cyan-400" />
|
<Bot size={16} className="text-cyan-400" />
|
||||||
</div>
|
</div>
|
||||||
<div className="glass-card-static rounded-xl px-4 py-3 text-sm flex items-center gap-2">
|
<div className="card-flat rounded-xl px-4 py-3 text-sm flex items-center gap-2">
|
||||||
<Loader2 size={14} className="animate-spin text-cyan-400" />
|
<Loader2 size={14} className="animate-spin text-cyan-400" />
|
||||||
<span className="text-muted-foreground">Generating script...</span>
|
<span className="text-[#848b9b]">Generating script...</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export function ScriptBuilderInput({
|
|||||||
rows={1}
|
rows={1}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex-1 resize-none rounded-xl px-4 py-2.5 text-sm",
|
"flex-1 resize-none rounded-xl px-4 py-2.5 text-sm",
|
||||||
"bg-card border border-border text-foreground placeholder:text-muted-foreground",
|
"bg-[#14161d] border border-[#1e2130] text-[#e2e5eb] placeholder:text-[#848b9b]",
|
||||||
"focus:outline-none focus:border-[rgba(6,182,212,0.3)] transition-colors",
|
"focus:outline-none focus:border-[rgba(6,182,212,0.3)] transition-colors",
|
||||||
"disabled:opacity-50"
|
"disabled:opacity-50"
|
||||||
)}
|
)}
|
||||||
@@ -67,7 +67,7 @@ export function ScriptBuilderInput({
|
|||||||
className={cn(
|
className={cn(
|
||||||
"shrink-0 flex items-center justify-center w-10 h-10 rounded-xl transition-all",
|
"shrink-0 flex items-center justify-center w-10 h-10 rounded-xl transition-all",
|
||||||
canSend
|
canSend
|
||||||
? "bg-gradient-brand text-[#101114] hover:opacity-90 active:scale-[0.97]"
|
? "bg-[#22d3ee] text-white hover:brightness-110 active:scale-[0.98]"
|
||||||
: "bg-[rgba(255,255,255,0.04)] text-[#5a6170] cursor-not-allowed"
|
: "bg-[rgba(255,255,255,0.04)] text-[#5a6170] cursor-not-allowed"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -55,11 +55,11 @@ export function ScriptCodeBlock({
|
|||||||
<div className="mt-3 rounded-lg border bg-[rgba(0,0,0,0.3)] border-[rgba(255,255,255,0.06)] overflow-hidden">
|
<div className="mt-3 rounded-lg border bg-[rgba(0,0,0,0.3)] border-[rgba(255,255,255,0.06)] overflow-hidden">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between px-3 py-2 border-b border-[rgba(255,255,255,0.06)]">
|
<div className="flex items-center justify-between px-3 py-2 border-b border-[rgba(255,255,255,0.06)]">
|
||||||
<span className="font-label text-xs text-cyan-400 truncate">
|
<span className="font-mono text-xs text-cyan-400 truncate">
|
||||||
{filename || 'script'}
|
{filename || 'script'}
|
||||||
</span>
|
</span>
|
||||||
{lineCount != null && (
|
{lineCount != null && (
|
||||||
<span className="font-label text-[0.625rem] text-muted-foreground ml-2 shrink-0">
|
<span className="font-mono text-[0.625rem] text-[#848b9b] ml-2 shrink-0">
|
||||||
{lineCount} lines
|
{lineCount} lines
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -85,7 +85,7 @@ export function ScriptCodeBlock({
|
|||||||
{previewLines}
|
{previewLines}
|
||||||
</SyntaxHighlighter>
|
</SyntaxHighlighter>
|
||||||
{remainingLines > 0 && (
|
{remainingLines > 0 && (
|
||||||
<div className="px-3 pb-2 font-label text-[0.625rem] text-[#5a6170]">
|
<div className="px-3 pb-2 font-mono text-[0.625rem] text-[#5a6170]">
|
||||||
{"··· "}{remainingLines} more line{remainingLines !== 1 ? 's' : ''}
|
{"··· "}{remainingLines} more line{remainingLines !== 1 ? 's' : ''}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -96,8 +96,8 @@ export function ScriptCodeBlock({
|
|||||||
<button
|
<button
|
||||||
onClick={onViewFull}
|
onClick={onViewFull}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-1.5 px-3 py-1.5 rounded-[10px] text-xs font-semibold transition-all",
|
"flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-semibold transition-all",
|
||||||
"bg-gradient-brand text-[#101114] hover:opacity-90 active:scale-[0.97]"
|
"bg-[#22d3ee] text-white hover:brightness-110 active:scale-[0.98]"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Eye size={14} />
|
<Eye size={14} />
|
||||||
@@ -106,8 +106,8 @@ export function ScriptCodeBlock({
|
|||||||
<button
|
<button
|
||||||
onClick={handleCopy}
|
onClick={handleCopy}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-1.5 px-3 py-1.5 rounded-[10px] text-xs font-medium transition-colors",
|
"flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors",
|
||||||
"bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground hover:border-[rgba(255,255,255,0.12)]"
|
"bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-[#e2e5eb] hover:border-[rgba(255,255,255,0.12)]"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{copied ? <Check size={14} className="text-emerald-400" /> : <Copy size={14} />}
|
{copied ? <Check size={14} className="text-emerald-400" /> : <Copy size={14} />}
|
||||||
@@ -116,7 +116,7 @@ export function ScriptCodeBlock({
|
|||||||
<button
|
<button
|
||||||
onClick={(e) => { e.stopPropagation(); onSave() }}
|
onClick={(e) => { e.stopPropagation(); onSave() }}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-1.5 px-3 py-1.5 rounded-[10px] text-xs font-medium transition-colors",
|
"flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors",
|
||||||
"bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 hover:bg-emerald-500/15"
|
"bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 hover:bg-emerald-500/15"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -55,17 +55,17 @@ export function ScriptPreviewModal({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 z-50 bg-black/80 backdrop-blur-sm flex items-center justify-center"
|
className="fixed inset-0 z-50 bg-black/80 flex items-center justify-center"
|
||||||
onClick={(e) => { if (e.target === e.currentTarget) onClose() }}
|
onClick={(e) => { if (e.target === e.currentTarget) onClose() }}
|
||||||
>
|
>
|
||||||
<div className="bg-[#18191f] rounded-xl border border-[rgba(255,255,255,0.08)] max-w-[900px] w-full mx-4 max-h-[85vh] flex flex-col">
|
<div className="bg-[#18191f] rounded-xl border border-[rgba(255,255,255,0.08)] max-w-[900px] w-full mx-4 max-h-[85vh] flex flex-col">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between px-5 py-3.5 border-b border-[rgba(255,255,255,0.06)]">
|
<div className="flex items-center justify-between px-5 py-3.5 border-b border-[rgba(255,255,255,0.06)]">
|
||||||
<div className="flex items-center gap-3 min-w-0">
|
<div className="flex items-center gap-3 min-w-0">
|
||||||
<span className="font-label text-sm text-cyan-400 truncate">
|
<span className="font-mono text-sm text-cyan-400 truncate">
|
||||||
{filename || 'script'}
|
{filename || 'script'}
|
||||||
</span>
|
</span>
|
||||||
<span className="shrink-0 font-label text-[0.625rem] uppercase tracking-wider px-2 py-0.5 rounded-full bg-[rgba(255,255,255,0.06)] text-muted-foreground">
|
<span className="shrink-0 font-mono text-[0.625rem] uppercase tracking-wider px-2 py-0.5 rounded-full bg-[rgba(255,255,255,0.06)] text-[#848b9b]">
|
||||||
{LANGUAGE_LABELS[language] || language}
|
{LANGUAGE_LABELS[language] || language}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -73,8 +73,8 @@ export function ScriptPreviewModal({
|
|||||||
<button
|
<button
|
||||||
onClick={handleCopy}
|
onClick={handleCopy}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-1.5 px-3 py-1.5 rounded-[10px] text-xs font-medium transition-colors",
|
"flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors",
|
||||||
"bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground hover:border-[rgba(255,255,255,0.12)]"
|
"bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-[#e2e5eb] hover:border-[rgba(255,255,255,0.12)]"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{copied ? <Check size={14} className="text-emerald-400" /> : <Copy size={14} />}
|
{copied ? <Check size={14} className="text-emerald-400" /> : <Copy size={14} />}
|
||||||
@@ -83,7 +83,7 @@ export function ScriptPreviewModal({
|
|||||||
<button
|
<button
|
||||||
onClick={onSave}
|
onClick={onSave}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-1.5 px-3 py-1.5 rounded-[10px] text-xs font-medium transition-colors",
|
"flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors",
|
||||||
"bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 hover:bg-emerald-500/15"
|
"bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 hover:bg-emerald-500/15"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -92,7 +92,7 @@ export function ScriptPreviewModal({
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="p-1.5 rounded-lg text-muted-foreground hover:text-foreground hover:bg-[rgba(255,255,255,0.06)] transition-colors"
|
className="p-1.5 rounded-lg text-[#848b9b] hover:text-[#e2e5eb] hover:bg-[rgba(255,255,255,0.06)] transition-colors"
|
||||||
>
|
>
|
||||||
<X size={18} />
|
<X size={18} />
|
||||||
</button>
|
</button>
|
||||||
@@ -126,14 +126,14 @@ export function ScriptPreviewModal({
|
|||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<div className="flex items-center justify-between px-5 py-3 border-t border-[rgba(255,255,255,0.06)]">
|
<div className="flex items-center justify-between px-5 py-3 border-t border-[rgba(255,255,255,0.06)]">
|
||||||
<span className="font-label text-[0.625rem] text-muted-foreground">
|
<span className="font-mono text-[0.625rem] text-[#848b9b]">
|
||||||
{lineCount} line{lineCount !== 1 ? 's' : ''}
|
{lineCount} line{lineCount !== 1 ? 's' : ''}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className={cn(
|
className={cn(
|
||||||
"px-4 py-1.5 rounded-[10px] text-xs font-medium transition-colors",
|
"px-4 py-1.5 rounded-lg text-xs font-medium transition-colors",
|
||||||
"bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground hover:border-[rgba(255,255,255,0.12)]"
|
"bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-[#e2e5eb] hover:border-[rgba(255,255,255,0.12)]"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
Close & Return to Chat
|
Close & Return to Chat
|
||||||
|
|||||||
@@ -130,8 +130,8 @@ export function AddSupportingDataModal({ isOpen, onClose, sessionId, onAdded }:
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex flex-1 items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors',
|
'flex flex-1 items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors',
|
||||||
activeTab === 'text_snippet'
|
activeTab === 'text_snippet'
|
||||||
? 'bg-card text-foreground shadow-sm'
|
? 'bg-[#14161d] text-[#e2e5eb] shadow-sm'
|
||||||
: 'text-muted-foreground hover:text-foreground'
|
: 'text-[#848b9b] hover:text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Code2 className="h-4 w-4" />
|
<Code2 className="h-4 w-4" />
|
||||||
@@ -143,8 +143,8 @@ export function AddSupportingDataModal({ isOpen, onClose, sessionId, onAdded }:
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex flex-1 items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors',
|
'flex flex-1 items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors',
|
||||||
activeTab === 'screenshot'
|
activeTab === 'screenshot'
|
||||||
? 'bg-card text-foreground shadow-sm'
|
? 'bg-[#14161d] text-[#e2e5eb] shadow-sm'
|
||||||
: 'text-muted-foreground hover:text-foreground'
|
: 'text-[#848b9b] hover:text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<ImageIcon className="h-4 w-4" />
|
<ImageIcon className="h-4 w-4" />
|
||||||
@@ -154,7 +154,7 @@ export function AddSupportingDataModal({ isOpen, onClose, sessionId, onAdded }:
|
|||||||
|
|
||||||
{/* Label */}
|
{/* Label */}
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label htmlFor="sd-label" className="mb-1 block text-sm font-medium text-foreground">
|
<label htmlFor="sd-label" className="mb-1 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Label
|
Label
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -164,8 +164,8 @@ export function AddSupportingDataModal({ isOpen, onClose, sessionId, onAdded }:
|
|||||||
onChange={(e) => setLabel(e.target.value)}
|
onChange={(e) => setLabel(e.target.value)}
|
||||||
placeholder={activeTab === 'text_snippet' ? 'e.g. Error log output' : 'e.g. Blue screen photo'}
|
placeholder={activeTab === 'text_snippet' ? 'e.g. Error log output' : 'e.g. Blue screen photo'}
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full rounded-md border border-border bg-card px-3 py-2 text-sm',
|
'w-full rounded-md border border-[#1e2130] bg-[#14161d] px-3 py-2 text-sm',
|
||||||
'text-foreground placeholder:text-muted-foreground',
|
'text-[#e2e5eb] placeholder:text-[#848b9b]',
|
||||||
'focus:border-[rgba(6,182,212,0.3)] focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
'focus:border-[rgba(6,182,212,0.3)] focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -174,7 +174,7 @@ export function AddSupportingDataModal({ isOpen, onClose, sessionId, onAdded }:
|
|||||||
{/* Text Snippet Tab Content */}
|
{/* Text Snippet Tab Content */}
|
||||||
{activeTab === 'text_snippet' && (
|
{activeTab === 'text_snippet' && (
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label htmlFor="sd-content" className="mb-1 block text-sm font-medium text-foreground">
|
<label htmlFor="sd-content" className="mb-1 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Content
|
Content
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
@@ -184,8 +184,8 @@ export function AddSupportingDataModal({ isOpen, onClose, sessionId, onAdded }:
|
|||||||
placeholder="Paste log output, error messages, config snippets..."
|
placeholder="Paste log output, error messages, config snippets..."
|
||||||
rows={8}
|
rows={8}
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full resize-y rounded-md border border-border bg-card px-3 py-2 text-sm',
|
'w-full resize-y rounded-md border border-[#1e2130] bg-[#14161d] px-3 py-2 text-sm',
|
||||||
'font-mono text-foreground placeholder:text-muted-foreground',
|
'font-mono text-[#e2e5eb] placeholder:text-[#848b9b]',
|
||||||
'focus:border-[rgba(6,182,212,0.3)] focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
'focus:border-[rgba(6,182,212,0.3)] focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -195,17 +195,17 @@ export function AddSupportingDataModal({ isOpen, onClose, sessionId, onAdded }:
|
|||||||
{/* Screenshot Tab Content */}
|
{/* Screenshot Tab Content */}
|
||||||
{activeTab === 'screenshot' && (
|
{activeTab === 'screenshot' && (
|
||||||
<div className="mb-4" onPaste={handlePaste}>
|
<div className="mb-4" onPaste={handlePaste}>
|
||||||
<label className="mb-1 block text-sm font-medium text-foreground">
|
<label className="mb-1 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Image
|
Image
|
||||||
</label>
|
</label>
|
||||||
{imageBase64 ? (
|
{imageBase64 ? (
|
||||||
<div className="relative rounded-md border border-border bg-card p-2">
|
<div className="relative rounded-md border border-[#1e2130] bg-[#14161d] p-2">
|
||||||
<img
|
<img
|
||||||
src={`data:${imageContentType};base64,${imageBase64}`}
|
src={`data:${imageContentType};base64,${imageBase64}`}
|
||||||
alt="Preview"
|
alt="Preview"
|
||||||
className="mx-auto max-h-48 rounded object-contain"
|
className="mx-auto max-h-48 rounded object-contain"
|
||||||
/>
|
/>
|
||||||
<p className="mt-2 text-center text-xs text-muted-foreground">{imageFileName}</p>
|
<p className="mt-2 text-center text-xs text-[#848b9b]">{imageFileName}</p>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -214,7 +214,7 @@ export function AddSupportingDataModal({ isOpen, onClose, sessionId, onAdded }:
|
|||||||
setImageFileName(null)
|
setImageFileName(null)
|
||||||
if (fileInputRef.current) fileInputRef.current.value = ''
|
if (fileInputRef.current) fileInputRef.current.value = ''
|
||||||
}}
|
}}
|
||||||
className="mt-2 w-full text-center text-xs text-muted-foreground hover:text-foreground"
|
className="mt-2 w-full text-center text-xs text-[#848b9b] hover:text-[#e2e5eb]"
|
||||||
>
|
>
|
||||||
Remove and choose another
|
Remove and choose another
|
||||||
</button>
|
</button>
|
||||||
@@ -223,13 +223,13 @@ export function AddSupportingDataModal({ isOpen, onClose, sessionId, onAdded }:
|
|||||||
<div
|
<div
|
||||||
onClick={() => fileInputRef.current?.click()}
|
onClick={() => fileInputRef.current?.click()}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex cursor-pointer flex-col items-center justify-center gap-2 rounded-md border-2 border-dashed border-border',
|
'flex cursor-pointer flex-col items-center justify-center gap-2 rounded-md border-2 border-dashed border-[#1e2130]',
|
||||||
'bg-card/50 py-10 transition-colors hover:border-muted-foreground'
|
'bg-[#14161d]/50 py-10 transition-colors hover:border-muted-foreground'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Upload className="h-8 w-8 text-muted-foreground" />
|
<Upload className="h-8 w-8 text-[#848b9b]" />
|
||||||
<p className="text-sm text-muted-foreground">Click to upload or paste from clipboard</p>
|
<p className="text-sm text-[#848b9b]">Click to upload or paste from clipboard</p>
|
||||||
<p className="text-xs text-muted-foreground">PNG, JPEG, or SVG - max 2MB</p>
|
<p className="text-xs text-[#848b9b]">PNG, JPEG, or SVG - max 2MB</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export function CSATModal({ isOpen, onClose, sessionId }: CSATModalProps) {
|
|||||||
return (
|
return (
|
||||||
<Modal isOpen={isOpen} onClose={handleSkip} title="How was this flow?" size="sm">
|
<Modal isOpen={isOpen} onClose={handleSkip} title="How was this flow?" size="sm">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-[#848b9b]">
|
||||||
Your feedback helps flow authors improve troubleshooting paths.
|
Your feedback helps flow authors improve troubleshooting paths.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ export function CSATModal({ isOpen, onClose, sessionId }: CSATModalProps) {
|
|||||||
'transition-colors',
|
'transition-colors',
|
||||||
(hoveredRating || rating) >= value
|
(hoveredRating || rating) >= value
|
||||||
? 'fill-yellow-400 text-yellow-400'
|
? 'fill-yellow-400 text-yellow-400'
|
||||||
: 'fill-none text-muted-foreground'
|
: 'fill-none text-[#848b9b]'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
@@ -74,21 +74,21 @@ export function CSATModal({ isOpen, onClose, sessionId }: CSATModalProps) {
|
|||||||
placeholder="Any comments? (optional)"
|
placeholder="Any comments? (optional)"
|
||||||
maxLength={500}
|
maxLength={500}
|
||||||
rows={3}
|
rows={3}
|
||||||
className="w-full rounded-lg border border-border bg-card px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20 resize-none"
|
className="w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-3 py-2 text-sm text-[#e2e5eb] placeholder:text-[#848b9b] focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20 resize-none"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Actions */}
|
{/* Actions */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<button
|
<button
|
||||||
onClick={handleSkip}
|
onClick={handleSkip}
|
||||||
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
className="text-sm text-[#848b9b] hover:text-[#e2e5eb] transition-colors"
|
||||||
>
|
>
|
||||||
Skip
|
Skip
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
disabled={rating === 0 || submitting}
|
disabled={rating === 0 || submitting}
|
||||||
className="rounded-lg bg-gradient-brand px-4 py-2 text-sm font-semibold text-white shadow-lg shadow-primary/20 hover:opacity-90 transition-opacity disabled:opacity-50"
|
className="rounded-lg bg-[#22d3ee] text-white px-4 py-2 text-sm font-semibold hover:brightness-110 transition-opacity disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{submitting ? 'Submitting...' : 'Submit'}
|
{submitting ? 'Submitting...' : 'Submit'}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export function ContinuationModal({
|
|||||||
{/* Descendant Selection */}
|
{/* Descendant Selection */}
|
||||||
{hasDescendants && (
|
{hasDescendants && (
|
||||||
<div>
|
<div>
|
||||||
<p className="mb-4 text-sm text-muted-foreground">
|
<p className="mb-4 text-sm text-[#848b9b]">
|
||||||
Select the next step in your troubleshooting path:
|
Select the next step in your troubleshooting path:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -58,20 +58,20 @@ export function ContinuationModal({
|
|||||||
onClick={() => onSelectNode(node.id)}
|
onClick={() => onSelectNode(node.id)}
|
||||||
title={`From: ${node.parentOptionLabel}`}
|
title={`From: ${node.parentOptionLabel}`}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex w-full items-center gap-3 rounded-lg border border-border p-3 text-left transition-colors',
|
'flex w-full items-center gap-3 rounded-lg border border-[#1e2130] p-3 text-left transition-colors',
|
||||||
'hover:border-border hover:bg-accent'
|
'hover:border-[#1e2130] hover:bg-accent'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-accent">
|
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-accent">
|
||||||
{nodeTypeIcons[node.type]}
|
{nodeTypeIcons[node.type]}
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<p className="truncate font-medium text-foreground">{node.label}</p>
|
<p className="truncate font-medium text-[#e2e5eb]">{node.label}</p>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-[#848b9b]">
|
||||||
{nodeTypeLabels[node.type]}
|
{nodeTypeLabels[node.type]}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<ArrowRight className="h-4 w-4 shrink-0 text-muted-foreground" />
|
<ArrowRight className="h-4 w-4 shrink-0 text-[#848b9b]" />
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -81,11 +81,11 @@ export function ContinuationModal({
|
|||||||
{/* Divider */}
|
{/* Divider */}
|
||||||
{hasDescendants && (
|
{hasDescendants && (
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<div className="h-px flex-1 bg-border" />
|
<div className="h-px flex-1 bg-[#1e2130]" />
|
||||||
<span className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
<span className="text-xs font-medium uppercase tracking-wide text-[#848b9b]">
|
||||||
Or
|
Or
|
||||||
</span>
|
</span>
|
||||||
<div className="h-px flex-1 bg-border" />
|
<div className="h-px flex-1 bg-[#1e2130]" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -102,8 +102,8 @@ export function ContinuationModal({
|
|||||||
<GitBranch className="h-5 w-5 text-amber-500" />
|
<GitBranch className="h-5 w-5 text-amber-500" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<p className="font-medium text-foreground">Build Custom Branch</p>
|
<p className="font-medium text-[#e2e5eb]">Build Custom Branch</p>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-[#848b9b]">
|
||||||
Create your own troubleshooting path with custom steps
|
Create your own troubleshooting path with custom steps
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -73,9 +73,9 @@ export function ExportPreviewModal({
|
|||||||
<Modal isOpen={isOpen} onClose={handleClose} title="Export Preview" size="xl">
|
<Modal isOpen={isOpen} onClose={handleClose} title="Export Preview" size="xl">
|
||||||
{/* Filename, format info, and controls */}
|
{/* Filename, format info, and controls */}
|
||||||
<div className="mb-3 flex flex-wrap items-center justify-between gap-2">
|
<div className="mb-3 flex flex-wrap items-center justify-between gap-2">
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-[#848b9b]">
|
||||||
Filename: <span className="font-mono text-foreground">{filename}</span>
|
Filename: <span className="font-mono text-[#e2e5eb]">{filename}</span>
|
||||||
<span className="ml-3 rounded bg-accent px-2 py-0.5 text-xs text-muted-foreground">
|
<span className="ml-3 rounded bg-accent px-2 py-0.5 text-xs text-[#848b9b]">
|
||||||
{format === 'markdown' ? 'Markdown' : format === 'html' ? 'HTML' : format === 'psa' ? 'PSA' : format === 'pdf' ? 'PDF' : 'Plain Text'}
|
{format === 'markdown' ? 'Markdown' : format === 'html' ? 'HTML' : format === 'psa' ? 'PSA' : format === 'pdf' ? 'PDF' : 'Plain Text'}
|
||||||
</span>
|
</span>
|
||||||
{isModified && (
|
{isModified && (
|
||||||
@@ -85,23 +85,23 @@ export function ExportPreviewModal({
|
|||||||
<div className="flex flex-col items-end gap-1">
|
<div className="flex flex-col items-end gap-1">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
{onToggleSummary && (
|
{onToggleSummary && (
|
||||||
<label className="flex items-center gap-2 text-sm text-muted-foreground cursor-pointer">
|
<label className="flex items-center gap-2 text-sm text-[#848b9b] cursor-pointer">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={includeSummary}
|
checked={includeSummary}
|
||||||
onChange={(e) => onToggleSummary(e.target.checked)}
|
onChange={(e) => onToggleSummary(e.target.checked)}
|
||||||
className="h-4 w-4 rounded border-border bg-card"
|
className="h-4 w-4 rounded border-[#1e2130] bg-[#14161d]"
|
||||||
/>
|
/>
|
||||||
Include Summary
|
Include Summary
|
||||||
</label>
|
</label>
|
||||||
)}
|
)}
|
||||||
{onToggleRedaction && (
|
{onToggleRedaction && (
|
||||||
<label className="flex items-center gap-2 text-sm text-muted-foreground cursor-pointer">
|
<label className="flex items-center gap-2 text-sm text-[#848b9b] cursor-pointer">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={redactionEnabled}
|
checked={redactionEnabled}
|
||||||
onChange={(e) => onToggleRedaction(e.target.checked)}
|
onChange={(e) => onToggleRedaction(e.target.checked)}
|
||||||
className="h-4 w-4 rounded border-border bg-card"
|
className="h-4 w-4 rounded border-[#1e2130] bg-[#14161d]"
|
||||||
/>
|
/>
|
||||||
Mask Sensitive Data
|
Mask Sensitive Data
|
||||||
</label>
|
</label>
|
||||||
@@ -118,13 +118,13 @@ export function ExportPreviewModal({
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{redactionEnabled && redactionSummary && redactionSummary.total === 0 && (
|
{redactionEnabled && redactionSummary && redactionSummary.total === 0 && (
|
||||||
<p className="text-xs text-muted-foreground">No sensitive data detected</p>
|
<p className="text-xs text-[#848b9b]">No sensitive data detected</p>
|
||||||
)}
|
)}
|
||||||
{isModified && (
|
{isModified && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleReset}
|
onClick={handleReset}
|
||||||
className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground"
|
className="flex items-center gap-1 text-xs text-[#848b9b] hover:text-[#e2e5eb]"
|
||||||
title="Reset to original"
|
title="Reset to original"
|
||||||
>
|
>
|
||||||
<RotateCcw className="h-3 w-3" />
|
<RotateCcw className="h-3 w-3" />
|
||||||
@@ -137,15 +137,15 @@ export function ExportPreviewModal({
|
|||||||
{format === 'pdf' ? (
|
{format === 'pdf' ? (
|
||||||
/* PDF download-only UI */
|
/* PDF download-only UI */
|
||||||
<div className="flex flex-col items-center justify-center py-12">
|
<div className="flex flex-col items-center justify-center py-12">
|
||||||
<FileDown className="mb-4 h-12 w-12 text-muted-foreground" />
|
<FileDown className="mb-4 h-12 w-12 text-[#848b9b]" />
|
||||||
<p className="text-muted-foreground mb-4">PDF exports are generated server-side with your team's branding.</p>
|
<p className="text-[#848b9b] mb-4">PDF exports are generated server-side with your team's branding.</p>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onDownloadPdf}
|
onClick={onDownloadPdf}
|
||||||
disabled={pdfLoading}
|
disabled={pdfLoading}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center gap-2 rounded-[10px] bg-gradient-brand px-6 py-3 text-sm font-semibold text-[#101114]',
|
'inline-flex items-center gap-2 rounded-lg bg-[#22d3ee] text-white px-6 py-3 text-sm font-semibold',
|
||||||
'hover:opacity-90 active:scale-[0.97] transition-all',
|
'hover:brightness-110 active:scale-[0.98] transition-all',
|
||||||
'disabled:opacity-60 disabled:cursor-not-allowed'
|
'disabled:opacity-60 disabled:cursor-not-allowed'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -168,8 +168,8 @@ export function ExportPreviewModal({
|
|||||||
value={editedContent}
|
value={editedContent}
|
||||||
onChange={(e) => setEditedContent(e.target.value)}
|
onChange={(e) => setEditedContent(e.target.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'h-96 w-full resize-y rounded-md border border-border bg-card p-4',
|
'h-96 w-full resize-y rounded-md border border-[#1e2130] bg-[#14161d] p-4',
|
||||||
'font-mono text-sm text-foreground',
|
'font-mono text-sm text-[#e2e5eb]',
|
||||||
'focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
'focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -180,8 +180,8 @@ export function ExportPreviewModal({
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={handleCopy}
|
onClick={handleCopy}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-2 rounded-md border border-border px-3 py-2 text-sm font-medium',
|
'flex items-center gap-2 rounded-md border border-[#1e2130] px-3 py-2 text-sm font-medium',
|
||||||
'text-muted-foreground hover:bg-accent hover:text-foreground',
|
'text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb]',
|
||||||
'focus:outline-hidden focus:ring-2 focus:ring-primary/20'
|
'focus:outline-hidden focus:ring-2 focus:ring-primary/20'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -201,8 +201,8 @@ export function ExportPreviewModal({
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={handleDownload}
|
onClick={handleDownload}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-2 rounded-md bg-gradient-brand text-white shadow-lg shadow-primary/20 px-3 py-2 text-sm font-medium',
|
'flex items-center gap-2 rounded-md bg-[#22d3ee] text-white px-3 py-2 text-sm font-medium',
|
||||||
'hover:opacity-90 focus:outline-hidden focus:ring-2 focus:ring-primary/20'
|
'hover:brightness-110 focus:outline-hidden focus:ring-2 focus:ring-primary/20'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Download className="h-4 w-4" />
|
<Download className="h-4 w-4" />
|
||||||
|
|||||||
@@ -69,11 +69,11 @@ export function ForkTreeModal({
|
|||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-start gap-3 rounded-lg bg-accent/50 p-4">
|
<div className="flex items-start gap-3 rounded-lg bg-accent/50 p-4">
|
||||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-accent">
|
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-accent">
|
||||||
<GitFork className="h-5 w-5 text-foreground" />
|
<GitFork className="h-5 w-5 text-[#e2e5eb]" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="font-medium text-foreground">You've created a custom troubleshooting path!</p>
|
<p className="font-medium text-[#e2e5eb]">You've created a custom troubleshooting path!</p>
|
||||||
<p className="mt-1 text-sm text-muted-foreground">
|
<p className="mt-1 text-sm text-[#848b9b]">
|
||||||
Save it as your own personal tree to reuse this troubleshooting flow in the future.
|
Save it as your own personal tree to reuse this troubleshooting flow in the future.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -81,7 +81,7 @@ export function ForkTreeModal({
|
|||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="tree-name" className="mb-1.5 block text-sm font-medium text-foreground">
|
<label htmlFor="tree-name" className="mb-1.5 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Tree Name <span className="text-red-400">*</span>
|
Tree Name <span className="text-red-400">*</span>
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
@@ -94,8 +94,8 @@ export function ForkTreeModal({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="tree-description" className="mb-1.5 block text-sm font-medium text-foreground">
|
<label htmlFor="tree-description" className="mb-1.5 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Description <span className="text-muted-foreground">(optional)</span>
|
Description <span className="text-[#848b9b]">(optional)</span>
|
||||||
</label>
|
</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
id="tree-description"
|
id="tree-description"
|
||||||
@@ -112,7 +112,7 @@ export function ForkTreeModal({
|
|||||||
<p className="text-sm text-red-400">{error}</p>
|
<p className="text-sm text-red-400">{error}</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-[#848b9b]">
|
||||||
The new tree will include your custom steps and will be saved to your personal tree library.
|
The new tree will include your custom steps and will be saved to your personal tree library.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ export function PostStepActionModal({
|
|||||||
return (
|
return (
|
||||||
<Modal isOpen={isOpen} onClose={onClose} title="What would you like to do?">
|
<Modal isOpen={isOpen} onClose={onClose} title="What would you like to do?">
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<p className="mb-4 text-sm text-muted-foreground">
|
<p className="mb-4 text-sm text-[#848b9b]">
|
||||||
You've created: <strong className="text-foreground">{step.title}</strong>
|
You've created: <strong className="text-[#e2e5eb]">{step.title}</strong>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Save for Later - Only show if not already from library */}
|
{/* Save for Later - Only show if not already from library */}
|
||||||
@@ -38,7 +38,7 @@ export function PostStepActionModal({
|
|||||||
onClick={onSaveForLater}
|
onClick={onSaveForLater}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full rounded-lg border border-border p-4 text-left transition-colors',
|
'w-full rounded-lg border border-[#1e2130] p-4 text-left transition-colors',
|
||||||
'hover:border-primary hover:bg-accent',
|
'hover:border-primary hover:bg-accent',
|
||||||
'disabled:cursor-not-allowed disabled:opacity-50'
|
'disabled:cursor-not-allowed disabled:opacity-50'
|
||||||
)}
|
)}
|
||||||
@@ -48,8 +48,8 @@ export function PostStepActionModal({
|
|||||||
<Bookmark className="h-5 w-5 text-blue-500" />
|
<Bookmark className="h-5 w-5 text-blue-500" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="font-medium text-foreground">Save for Later</p>
|
<p className="font-medium text-[#e2e5eb]">Save for Later</p>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-[#848b9b]">
|
||||||
Add to your step library for future use
|
Add to your step library for future use
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -62,8 +62,8 @@ export function PostStepActionModal({
|
|||||||
onClick={onUseNow}
|
onClick={onUseNow}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full rounded-lg border border-border p-4 text-left transition-colors',
|
'w-full rounded-lg border border-[#1e2130] p-4 text-left transition-colors',
|
||||||
'hover:border-border hover:bg-accent',
|
'hover:border-[#1e2130] hover:bg-accent',
|
||||||
'disabled:cursor-not-allowed disabled:opacity-50'
|
'disabled:cursor-not-allowed disabled:opacity-50'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -73,7 +73,7 @@ export function PostStepActionModal({
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="font-medium">Use Now</p>
|
<p className="font-medium">Use Now</p>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-[#848b9b]">
|
||||||
Insert into this session and continue troubleshooting
|
Insert into this session and continue troubleshooting
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -86,7 +86,7 @@ export function PostStepActionModal({
|
|||||||
onClick={onBoth}
|
onClick={onBoth}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full rounded-lg border border-border p-4 text-left transition-colors',
|
'w-full rounded-lg border border-[#1e2130] p-4 text-left transition-colors',
|
||||||
'hover:border-primary hover:bg-accent',
|
'hover:border-primary hover:bg-accent',
|
||||||
'disabled:cursor-not-allowed disabled:opacity-50'
|
'disabled:cursor-not-allowed disabled:opacity-50'
|
||||||
)}
|
)}
|
||||||
@@ -96,8 +96,8 @@ export function PostStepActionModal({
|
|||||||
<BookmarkPlus className="h-5 w-5 text-purple-500" />
|
<BookmarkPlus className="h-5 w-5 text-purple-500" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="font-medium text-foreground">Do Both</p>
|
<p className="font-medium text-[#e2e5eb]">Do Both</p>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-[#848b9b]">
|
||||||
Save to library AND use in this session
|
Save to library AND use in this session
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,7 +106,7 @@ export function PostStepActionModal({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{isSaving && (
|
{isSaving && (
|
||||||
<p className="text-center text-sm text-muted-foreground">Saving...</p>
|
<p className="text-center text-sm text-[#848b9b]">Saving...</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -36,21 +36,21 @@ export function SaveSessionAsTreeModal({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-xs">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-xs">
|
||||||
<div className="bg-card border border-border w-full max-w-lg rounded-2xl p-6 shadow-lg">
|
<div className="bg-[#14161d] border border-[#1e2130] w-full max-w-lg rounded-lg p-6 shadow-lg">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="mb-4 flex items-center justify-between">
|
<div className="mb-4 flex items-center justify-between">
|
||||||
<h2 className="text-lg font-semibold text-foreground">Save Session as Tree</h2>
|
<h2 className="text-lg font-semibold text-[#e2e5eb]">Save Session as Tree</h2>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
className="rounded-full p-1 text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-50"
|
className="rounded-full p-1 text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb] disabled:opacity-50"
|
||||||
>
|
>
|
||||||
<X className="h-5 w-5" />
|
<X className="h-5 w-5" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Info */}
|
{/* Info */}
|
||||||
<p className="mb-4 text-sm text-muted-foreground">
|
<p className="mb-4 text-sm text-[#848b9b]">
|
||||||
Create a new tree from this session's path. The tree will be linked to the original tree as a fork.
|
Create a new tree from this session's path. The tree will be linked to the original tree as a fork.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -58,8 +58,8 @@ export function SaveSessionAsTreeModal({
|
|||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
{/* Tree Name */}
|
{/* Tree Name */}
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="treeName" className="mb-1 block text-sm font-medium text-foreground">
|
<label htmlFor="treeName" className="mb-1 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Tree Name <span className="text-muted-foreground">(optional)</span>
|
Tree Name <span className="text-[#848b9b]">(optional)</span>
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
id="treeName"
|
id="treeName"
|
||||||
@@ -74,8 +74,8 @@ export function SaveSessionAsTreeModal({
|
|||||||
|
|
||||||
{/* Description */}
|
{/* Description */}
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="description" className="mb-1 block text-sm font-medium text-foreground">
|
<label htmlFor="description" className="mb-1 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Description <span className="text-muted-foreground">(optional)</span>
|
Description <span className="text-[#848b9b]">(optional)</span>
|
||||||
</label>
|
</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
id="description"
|
id="description"
|
||||||
@@ -89,7 +89,7 @@ export function SaveSessionAsTreeModal({
|
|||||||
|
|
||||||
{/* Status */}
|
{/* Status */}
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-2 block text-sm font-medium text-foreground">Status</label>
|
<label className="mb-2 block text-sm font-medium text-[#e2e5eb]">Status</label>
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<label className="flex cursor-pointer items-center gap-2">
|
<label className="flex cursor-pointer items-center gap-2">
|
||||||
<input
|
<input
|
||||||
@@ -99,9 +99,9 @@ export function SaveSessionAsTreeModal({
|
|||||||
checked={status === 'draft'}
|
checked={status === 'draft'}
|
||||||
onChange={() => setStatus('draft')}
|
onChange={() => setStatus('draft')}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
className="h-4 w-4 border-border text-foreground focus:ring-2 focus:ring-primary/20 focus:ring-offset-0"
|
className="h-4 w-4 border-[#1e2130] text-[#e2e5eb] focus:ring-2 focus:ring-primary/20 focus:ring-offset-0"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm text-foreground">Draft</span>
|
<span className="text-sm text-[#e2e5eb]">Draft</span>
|
||||||
</label>
|
</label>
|
||||||
<label className="flex cursor-pointer items-center gap-2">
|
<label className="flex cursor-pointer items-center gap-2">
|
||||||
<input
|
<input
|
||||||
@@ -111,9 +111,9 @@ export function SaveSessionAsTreeModal({
|
|||||||
checked={status === 'published'}
|
checked={status === 'published'}
|
||||||
onChange={() => setStatus('published')}
|
onChange={() => setStatus('published')}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
className="h-4 w-4 border-border text-foreground focus:ring-2 focus:ring-primary/20 focus:ring-offset-0"
|
className="h-4 w-4 border-[#1e2130] text-[#e2e5eb] focus:ring-2 focus:ring-primary/20 focus:ring-offset-0"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm text-foreground">Published</span>
|
<span className="text-sm text-[#e2e5eb]">Published</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -124,8 +124,8 @@ export function ScratchpadSidebar({ sessionId, initialContent, onSave, onOpenCha
|
|||||||
onClick={() => setIsCollapsed(false)}
|
onClick={() => setIsCollapsed(false)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'fixed right-2 top-1/2 z-40 -translate-y-1/2 rounded-md p-2.5',
|
'fixed right-2 top-1/2 z-40 -translate-y-1/2 rounded-md p-2.5',
|
||||||
'bg-card border border-border shadow-md',
|
'bg-[#14161d] border border-[#1e2130] shadow-md',
|
||||||
'text-muted-foreground hover:bg-accent hover:text-foreground',
|
'text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb]',
|
||||||
'transition-opacity duration-200',
|
'transition-opacity duration-200',
|
||||||
isCollapsed ? 'opacity-100' : 'pointer-events-none opacity-0'
|
isCollapsed ? 'opacity-100' : 'pointer-events-none opacity-0'
|
||||||
)}
|
)}
|
||||||
@@ -153,29 +153,29 @@ export function ScratchpadSidebar({ sessionId, initialContent, onSave, onOpenCha
|
|||||||
'fixed z-40',
|
'fixed z-40',
|
||||||
'inset-0 sm:inset-auto sm:right-2 sm:top-1/2 sm:-translate-y-1/2',
|
'inset-0 sm:inset-auto sm:right-2 sm:top-1/2 sm:-translate-y-1/2',
|
||||||
'flex w-full flex-col sm:h-[55vh] sm:w-[420px]',
|
'flex w-full flex-col sm:h-[55vh] sm:w-[420px]',
|
||||||
'border-border bg-card/95 backdrop-blur-md shadow-xl sm:rounded-lg sm:border',
|
'border-[#1e2130] bg-[#14161d]/95 shadow-xl sm:rounded-lg sm:border',
|
||||||
'transition-transform duration-200 ease-out',
|
'transition-transform duration-200 ease-out',
|
||||||
isCollapsed ? 'translate-x-full' : 'translate-x-0'
|
isCollapsed ? 'translate-x-full' : 'translate-x-0'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between border-b border-border px-3 py-2">
|
<div className="flex items-center justify-between border-b border-[#1e2130] px-3 py-2">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<StickyNote className="h-4 w-4 text-muted-foreground" />
|
<StickyNote className="h-4 w-4 text-[#848b9b]" />
|
||||||
<span className="text-sm font-medium text-foreground">Scratchpad</span>
|
<span className="text-sm font-medium text-[#e2e5eb]">Scratchpad</span>
|
||||||
<span className="text-xs text-muted-foreground">Ctrl+/</span>
|
<span className="text-xs text-[#848b9b]">Ctrl+/</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowPreview(!showPreview)}
|
onClick={() => setShowPreview(!showPreview)}
|
||||||
className="rounded p-1 text-muted-foreground hover:bg-accent hover:text-foreground"
|
className="rounded p-1 text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb]"
|
||||||
title={showPreview ? 'Edit' : 'Preview'}
|
title={showPreview ? 'Edit' : 'Preview'}
|
||||||
>
|
>
|
||||||
{showPreview ? <Pencil className="h-3.5 w-3.5" /> : <Eye className="h-3.5 w-3.5" />}
|
{showPreview ? <Pencil className="h-3.5 w-3.5" /> : <Eye className="h-3.5 w-3.5" />}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsCollapsed(true)}
|
onClick={() => setIsCollapsed(true)}
|
||||||
className="rounded p-1 text-muted-foreground hover:bg-accent hover:text-foreground"
|
className="rounded p-1 text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb]"
|
||||||
title="Close scratchpad"
|
title="Close scratchpad"
|
||||||
aria-label="Close scratchpad"
|
aria-label="Close scratchpad"
|
||||||
>
|
>
|
||||||
@@ -191,7 +191,7 @@ export function ScratchpadSidebar({ sessionId, initialContent, onSave, onOpenCha
|
|||||||
{content.trim() ? (
|
{content.trim() ? (
|
||||||
<MarkdownContent content={content} className="text-sm" />
|
<MarkdownContent content={content} className="text-sm" />
|
||||||
) : (
|
) : (
|
||||||
<p className="text-sm italic text-muted-foreground">Nothing to preview</p>
|
<p className="text-sm italic text-[#848b9b]">Nothing to preview</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -202,7 +202,7 @@ export function ScratchpadSidebar({ sessionId, initialContent, onSave, onOpenCha
|
|||||||
placeholder={"Capture IPs, error codes, server names, user info...\n\nSupports markdown formatting."}
|
placeholder={"Capture IPs, error codes, server names, user info...\n\nSupports markdown formatting."}
|
||||||
className={cn(
|
className={cn(
|
||||||
'h-full min-h-[200px] w-full resize-none rounded-md border-0 bg-transparent p-0 text-sm',
|
'h-full min-h-[200px] w-full resize-none rounded-md border-0 bg-transparent p-0 text-sm',
|
||||||
'text-foreground placeholder:text-muted-foreground',
|
'text-[#e2e5eb] placeholder:text-[#848b9b]',
|
||||||
'focus:outline-hidden focus:ring-0'
|
'focus:outline-hidden focus:ring-0'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -210,15 +210,15 @@ export function ScratchpadSidebar({ sessionId, initialContent, onSave, onOpenCha
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Save Indicator */}
|
{/* Save Indicator */}
|
||||||
<div className="border-t border-border px-3 py-1.5">
|
<div className="border-t border-[#1e2130] px-3 py-1.5">
|
||||||
<div className="flex items-center gap-1.5 text-xs">
|
<div className="flex items-center gap-1.5 text-xs">
|
||||||
{saveStatus === 'unsaved' && (
|
{saveStatus === 'unsaved' && (
|
||||||
<span className="text-muted-foreground">Unsaved changes</span>
|
<span className="text-[#848b9b]">Unsaved changes</span>
|
||||||
)}
|
)}
|
||||||
{saveStatus === 'saving' && (
|
{saveStatus === 'saving' && (
|
||||||
<>
|
<>
|
||||||
<Loader2 className="h-3 w-3 animate-spin text-muted-foreground" />
|
<Loader2 className="h-3 w-3 animate-spin text-[#848b9b]" />
|
||||||
<span className="text-muted-foreground">Saving...</span>
|
<span className="text-[#848b9b]">Saving...</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{saveStatus === 'saved' && (
|
{saveStatus === 'saved' && (
|
||||||
@@ -228,7 +228,7 @@ export function ScratchpadSidebar({ sessionId, initialContent, onSave, onOpenCha
|
|||||||
<span className="text-red-400">Save failed</span>
|
<span className="text-red-400">Save failed</span>
|
||||||
)}
|
)}
|
||||||
{saveStatus === 'idle' && (
|
{saveStatus === 'idle' && (
|
||||||
<span className="text-muted-foreground">Markdown supported</span>
|
<span className="text-[#848b9b]">Markdown supported</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -93,15 +93,15 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
<div className="flex flex-col gap-3 sm:flex-row">
|
<div className="flex flex-col gap-3 sm:flex-row">
|
||||||
{/* Ticket Number Search */}
|
{/* Ticket Number Search */}
|
||||||
<div className="relative flex-1">
|
<div className="relative flex-1">
|
||||||
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-[#848b9b]" />
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Search by ticket number..."
|
placeholder="Search by ticket number..."
|
||||||
value={filters.ticketNumber}
|
value={filters.ticketNumber}
|
||||||
onChange={(e) => handleFilterChange('ticketNumber', e.target.value)}
|
onChange={(e) => handleFilterChange('ticketNumber', e.target.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full rounded-md border border-border bg-card py-2 pl-9 pr-3',
|
'w-full rounded-md border border-[#1e2130] bg-[#14161d] py-2 pl-9 pr-3',
|
||||||
'text-foreground placeholder:text-muted-foreground',
|
'text-[#e2e5eb] placeholder:text-[#848b9b]',
|
||||||
'focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
'focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -109,15 +109,15 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
|
|
||||||
{/* Client Name Search */}
|
{/* Client Name Search */}
|
||||||
<div className="relative flex-1">
|
<div className="relative flex-1">
|
||||||
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-[#848b9b]" />
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Search by client name..."
|
placeholder="Search by client name..."
|
||||||
value={filters.clientName}
|
value={filters.clientName}
|
||||||
onChange={(e) => handleFilterChange('clientName', e.target.value)}
|
onChange={(e) => handleFilterChange('clientName', e.target.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full rounded-md border border-border bg-card py-2 pl-9 pr-3',
|
'w-full rounded-md border border-[#1e2130] bg-[#14161d] py-2 pl-9 pr-3',
|
||||||
'text-foreground placeholder:text-muted-foreground',
|
'text-[#e2e5eb] placeholder:text-[#848b9b]',
|
||||||
'focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
'focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -128,8 +128,8 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
value={filters.treeName}
|
value={filters.treeName}
|
||||||
onChange={(e) => handleFilterChange('treeName', e.target.value)}
|
onChange={(e) => handleFilterChange('treeName', e.target.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'rounded-md border border-border bg-card px-3 py-2',
|
'rounded-md border border-[#1e2130] bg-[#14161d] px-3 py-2',
|
||||||
'text-foreground focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20',
|
'text-[#e2e5eb] focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20',
|
||||||
'sm:min-w-[200px]'
|
'sm:min-w-[200px]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -148,19 +148,19 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
<button
|
<button
|
||||||
onClick={() => setShowDatePicker(!showDatePicker)}
|
onClick={() => setShowDatePicker(!showDatePicker)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex w-full items-center gap-2 rounded-md border border-border bg-card px-3 py-2 text-sm',
|
'flex w-full items-center gap-2 rounded-md border border-[#1e2130] bg-[#14161d] px-3 py-2 text-sm',
|
||||||
'text-foreground hover:bg-accent',
|
'text-[#e2e5eb] hover:bg-accent',
|
||||||
filters.dateRange?.from && 'border-primary/30'
|
filters.dateRange?.from && 'border-primary/30'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Calendar className="h-4 w-4 text-muted-foreground" />
|
<Calendar className="h-4 w-4 text-[#848b9b]" />
|
||||||
<span className={cn(!filters.dateRange?.from && 'text-muted-foreground')}>
|
<span className={cn(!filters.dateRange?.from && 'text-[#848b9b]')}>
|
||||||
{formatDateRange(filters.dateRange)}
|
{formatDateRange(filters.dateRange)}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{showDatePicker && (
|
{showDatePicker && (
|
||||||
<div className="absolute left-0 top-full z-50 mt-2 rounded-lg border border-border bg-background p-4 shadow-lg">
|
<div className="absolute left-0 top-full z-50 mt-2 rounded-lg border border-[#1e2130] bg-[#0c0d10] p-4 shadow-lg">
|
||||||
{/* Date Type Toggle */}
|
{/* Date Type Toggle */}
|
||||||
<div className="mb-3 flex gap-2">
|
<div className="mb-3 flex gap-2">
|
||||||
<button
|
<button
|
||||||
@@ -168,8 +168,8 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex-1 rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
|
'flex-1 rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
|
||||||
filters.dateType === 'started'
|
filters.dateType === 'started'
|
||||||
? 'bg-gradient-brand text-white shadow-lg shadow-primary/20'
|
? 'bg-[#22d3ee] text-white'
|
||||||
: 'border border-border text-muted-foreground hover:bg-accent hover:text-foreground'
|
: 'border border-[#1e2130] text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
Started
|
Started
|
||||||
@@ -179,8 +179,8 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex-1 rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
|
'flex-1 rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
|
||||||
filters.dateType === 'completed'
|
filters.dateType === 'completed'
|
||||||
? 'bg-gradient-brand text-white shadow-lg shadow-primary/20'
|
? 'bg-[#22d3ee] text-white'
|
||||||
: 'border border-border text-muted-foreground hover:bg-accent hover:text-foreground'
|
: 'border border-[#1e2130] text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
Completed
|
Completed
|
||||||
@@ -194,8 +194,8 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
key={preset.value}
|
key={preset.value}
|
||||||
onClick={() => applyDatePreset(preset.value)}
|
onClick={() => applyDatePreset(preset.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'rounded-md bg-accent px-3 py-1.5 text-sm font-medium text-muted-foreground',
|
'rounded-md bg-accent px-3 py-1.5 text-sm font-medium text-[#848b9b]',
|
||||||
'hover:bg-accent/80 hover:text-foreground'
|
'hover:bg-accent/80 hover:text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{preset.label}
|
{preset.label}
|
||||||
@@ -228,7 +228,7 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex-1 rounded-md bg-gradient-brand px-3 py-1.5 text-sm font-medium text-white shadow-lg shadow-primary/20',
|
'flex-1 rounded-md bg-gradient-brand px-3 py-1.5 text-sm font-medium text-white shadow-lg shadow-primary/20',
|
||||||
'hover:opacity-90'
|
'hover:brightness-110'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
Apply
|
Apply
|
||||||
@@ -236,8 +236,8 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
<button
|
<button
|
||||||
onClick={() => setShowDatePicker(false)}
|
onClick={() => setShowDatePicker(false)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'rounded-md border border-border px-3 py-1.5 text-sm font-medium text-muted-foreground',
|
'rounded-md border border-[#1e2130] px-3 py-1.5 text-sm font-medium text-[#848b9b]',
|
||||||
'hover:bg-accent hover:text-foreground'
|
'hover:bg-accent hover:text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
@@ -252,8 +252,8 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
<button
|
<button
|
||||||
onClick={onClear}
|
onClick={onClear}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-2 rounded-md border border-border px-3 py-2 text-sm font-medium',
|
'flex items-center gap-2 rounded-md border border-[#1e2130] px-3 py-2 text-sm font-medium',
|
||||||
'text-muted-foreground hover:bg-accent hover:text-foreground'
|
'text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Filter className="h-4 w-4" />
|
<Filter className="h-4 w-4" />
|
||||||
@@ -265,9 +265,9 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
{/* Active Filter Chips */}
|
{/* Active Filter Chips */}
|
||||||
{hasActiveFilters && (
|
{hasActiveFilters && (
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
<span className="text-sm text-muted-foreground">Active filters:</span>
|
<span className="text-sm text-[#848b9b]">Active filters:</span>
|
||||||
{filters.ticketNumber && (
|
{filters.ticketNumber && (
|
||||||
<span className="inline-flex items-center gap-1 rounded-full bg-accent px-3 py-1 text-sm text-muted-foreground">
|
<span className="inline-flex items-center gap-1 rounded-full bg-accent px-3 py-1 text-sm text-[#848b9b]">
|
||||||
Ticket: {filters.ticketNumber}
|
Ticket: {filters.ticketNumber}
|
||||||
<button
|
<button
|
||||||
onClick={() => handleFilterChange('ticketNumber', '')}
|
onClick={() => handleFilterChange('ticketNumber', '')}
|
||||||
@@ -278,7 +278,7 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{filters.clientName && (
|
{filters.clientName && (
|
||||||
<span className="inline-flex items-center gap-1 rounded-full bg-accent px-3 py-1 text-sm text-muted-foreground">
|
<span className="inline-flex items-center gap-1 rounded-full bg-accent px-3 py-1 text-sm text-[#848b9b]">
|
||||||
Client: {filters.clientName}
|
Client: {filters.clientName}
|
||||||
<button
|
<button
|
||||||
onClick={() => handleFilterChange('clientName', '')}
|
onClick={() => handleFilterChange('clientName', '')}
|
||||||
@@ -289,7 +289,7 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{filters.treeName && (
|
{filters.treeName && (
|
||||||
<span className="inline-flex items-center gap-1 rounded-full bg-accent px-3 py-1 text-sm text-muted-foreground">
|
<span className="inline-flex items-center gap-1 rounded-full bg-accent px-3 py-1 text-sm text-[#848b9b]">
|
||||||
Tree: {filters.treeName}
|
Tree: {filters.treeName}
|
||||||
<button
|
<button
|
||||||
onClick={() => handleFilterChange('treeName', '')}
|
onClick={() => handleFilterChange('treeName', '')}
|
||||||
@@ -300,7 +300,7 @@ export function SessionFilters({ filters, onChange, onClear, trees }: SessionFil
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{filters.dateRange?.from && (
|
{filters.dateRange?.from && (
|
||||||
<span className="inline-flex items-center gap-1 rounded-full bg-accent px-3 py-1 text-sm text-muted-foreground">
|
<span className="inline-flex items-center gap-1 rounded-full bg-accent px-3 py-1 text-sm text-[#848b9b]">
|
||||||
{formatDateRange(filters.dateRange)} ({filters.dateType})
|
{formatDateRange(filters.dateRange)} ({filters.dateType})
|
||||||
<button
|
<button
|
||||||
onClick={clearDateRange}
|
onClick={clearDateRange}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export function SessionOutcomeModal({
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<form key={String(isOpen)} ref={formRef} className="space-y-4">
|
<form key={String(isOpen)} ref={formRef} className="space-y-4">
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-[#848b9b]">
|
||||||
Select the session outcome before completion.
|
Select the session outcome before completion.
|
||||||
</p>
|
</p>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -74,7 +74,7 @@ export function SessionOutcomeModal({
|
|||||||
<label
|
<label
|
||||||
key={option.value}
|
key={option.value}
|
||||||
className={cn(
|
className={cn(
|
||||||
'block cursor-pointer rounded-lg border border-border p-3 transition-colors',
|
'block cursor-pointer rounded-lg border border-[#1e2130] p-3 transition-colors',
|
||||||
'hover:bg-accent/50'
|
'hover:bg-accent/50'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -87,8 +87,8 @@ export function SessionOutcomeModal({
|
|||||||
className="mt-1 h-4 w-4"
|
className="mt-1 h-4 w-4"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-foreground">{option.label}</p>
|
<p className="text-sm font-medium text-[#e2e5eb]">{option.label}</p>
|
||||||
<p className="text-xs text-muted-foreground">{option.description}</p>
|
<p className="text-xs text-[#848b9b]">{option.description}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
@@ -96,30 +96,30 @@ export function SessionOutcomeModal({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-foreground">Outcome Notes (optional)</label>
|
<label className="block text-sm font-medium text-[#e2e5eb]">Outcome Notes (optional)</label>
|
||||||
<textarea
|
<textarea
|
||||||
name="outcome-notes"
|
name="outcome-notes"
|
||||||
defaultValue=""
|
defaultValue=""
|
||||||
rows={3}
|
rows={3}
|
||||||
placeholder="Add context for this outcome..."
|
placeholder="Add context for this outcome..."
|
||||||
className={cn(
|
className={cn(
|
||||||
'mt-1 block w-full rounded-md border border-border bg-card px-3 py-2',
|
'mt-1 block w-full rounded-md border border-[#1e2130] bg-[#14161d] px-3 py-2',
|
||||||
'text-sm text-foreground placeholder:text-muted-foreground',
|
'text-sm text-[#e2e5eb] placeholder:text-[#848b9b]',
|
||||||
'focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
'focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-foreground">Next Steps / Follow-Up (optional)</label>
|
<label className="block text-sm font-medium text-[#e2e5eb]">Next Steps / Follow-Up (optional)</label>
|
||||||
<textarea
|
<textarea
|
||||||
name="next-steps"
|
name="next-steps"
|
||||||
defaultValue=""
|
defaultValue=""
|
||||||
rows={3}
|
rows={3}
|
||||||
placeholder="Actions to take after this session..."
|
placeholder="Actions to take after this session..."
|
||||||
className={cn(
|
className={cn(
|
||||||
'mt-1 block w-full rounded-md border border-border bg-card px-3 py-2',
|
'mt-1 block w-full rounded-md border border-[#1e2130] bg-[#14161d] px-3 py-2',
|
||||||
'text-sm text-foreground placeholder:text-muted-foreground',
|
'text-sm text-[#e2e5eb] placeholder:text-[#848b9b]',
|
||||||
'focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
'focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export function SessionTimeline({
|
|||||||
if (treeType === 'procedural') {
|
if (treeType === 'procedural') {
|
||||||
return (
|
return (
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<h2 className="mb-4 text-lg font-semibold text-foreground">Procedure Steps</h2>
|
<h2 className="mb-4 text-lg font-semibold text-[#e2e5eb]">Procedure Steps</h2>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{decisions.map((decision, index) => {
|
{decisions.map((decision, index) => {
|
||||||
const isCompleted = decision.answer === 'completed'
|
const isCompleted = decision.answer === 'completed'
|
||||||
@@ -61,31 +61,31 @@ export function SessionTimeline({
|
|||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-card border border-border rounded-xl p-4',
|
'bg-[#14161d] border border-[#1e2130] rounded-xl p-4',
|
||||||
isCompleted && 'border-l-2 border-emerald-400/50'
|
isCompleted && 'border-l-2 border-emerald-400/50'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
<span className={cn(
|
<span className={cn(
|
||||||
'mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-medium',
|
'mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-medium',
|
||||||
isCompleted ? 'bg-emerald-400/10 text-emerald-400' : 'bg-accent text-muted-foreground'
|
isCompleted ? 'bg-emerald-400/10 text-emerald-400' : 'bg-accent text-[#848b9b]'
|
||||||
)}>
|
)}>
|
||||||
{isCompleted ? '\u2713' : index + 1}
|
{isCompleted ? '\u2713' : index + 1}
|
||||||
</span>
|
</span>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<p className="font-medium text-foreground">{decision.question || 'Step'}</p>
|
<p className="font-medium text-[#e2e5eb]">{decision.question || 'Step'}</p>
|
||||||
{decision.notes && (
|
{decision.notes && (
|
||||||
<p className="mt-1.5 rounded bg-white/5 p-2 text-sm text-muted-foreground">
|
<p className="mt-1.5 rounded bg-white/5 p-2 text-sm text-[#848b9b]">
|
||||||
Notes: {decision.notes}
|
Notes: {decision.notes}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{decision.command_output && (
|
{decision.command_output && (
|
||||||
<p className="mt-1 text-sm text-muted-foreground">
|
<p className="mt-1 text-sm text-[#848b9b]">
|
||||||
Verification: {decision.command_output}
|
Verification: {decision.command_output}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{decision.duration_seconds != null && (
|
{decision.duration_seconds != null && (
|
||||||
<p className="mt-1 text-xs text-muted-foreground">
|
<p className="mt-1 text-xs text-[#848b9b]">
|
||||||
Duration: {formatDuration(decision.duration_seconds)}
|
Duration: {formatDuration(decision.duration_seconds)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -94,7 +94,7 @@ export function SessionTimeline({
|
|||||||
<button
|
<button
|
||||||
onClick={() => handleCopyStep(decision, index)}
|
onClick={() => handleCopyStep(decision, index)}
|
||||||
title="Copy step to clipboard"
|
title="Copy step to clipboard"
|
||||||
className="rounded p-1 text-muted-foreground hover:bg-accent hover:text-foreground"
|
className="rounded p-1 text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb]"
|
||||||
>
|
>
|
||||||
{copiedStepIndex === index ? (
|
{copiedStepIndex === index ? (
|
||||||
<Check className="h-4 w-4 text-emerald-400" />
|
<Check className="h-4 w-4 text-emerald-400" />
|
||||||
@@ -123,52 +123,52 @@ export function SessionTimeline({
|
|||||||
// Default: troubleshooting decision timeline
|
// Default: troubleshooting decision timeline
|
||||||
return (
|
return (
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<h2 className="mb-4 text-lg font-semibold text-foreground">Decision Timeline</h2>
|
<h2 className="mb-4 text-lg font-semibold text-[#e2e5eb]">Decision Timeline</h2>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-center gap-3 text-sm">
|
<div className="flex items-center gap-3 text-sm">
|
||||||
<span className="h-3 w-3 rounded-full bg-foreground" />
|
<span className="h-3 w-3 rounded-full bg-[#e2e5eb]" />
|
||||||
<span className="text-muted-foreground">
|
<span className="text-[#848b9b]">
|
||||||
Session started: {formatDate(startedAt)}
|
Session started: {formatDate(startedAt)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{decisions.map((decision, index) => (
|
{decisions.map((decision, index) => (
|
||||||
<div key={index} className="ml-1 border-l-2 border-border pl-6">
|
<div key={index} className="ml-1 border-l-2 border-[#1e2130] pl-6">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<span className="absolute -left-6.5 top-1 h-2 w-2 rounded-full bg-muted-foreground" />
|
<span className="absolute -left-6.5 top-1 h-2 w-2 rounded-full bg-[#848b9b]" />
|
||||||
<div className="bg-card border border-border rounded-xl p-4">
|
<div className="bg-[#14161d] border border-[#1e2130] rounded-xl p-4">
|
||||||
<div className="flex items-start justify-between gap-2">
|
<div className="flex items-start justify-between gap-2">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
{decision.question && (
|
{decision.question && (
|
||||||
<p className="font-medium text-foreground">{decision.question}</p>
|
<p className="font-medium text-[#e2e5eb]">{decision.question}</p>
|
||||||
)}
|
)}
|
||||||
{decision.answer && (
|
{decision.answer && (
|
||||||
<p className="mt-1 text-sm text-foreground">Answer: {decision.answer}</p>
|
<p className="mt-1 text-sm text-[#e2e5eb]">Answer: {decision.answer}</p>
|
||||||
)}
|
)}
|
||||||
{decision.action_performed && (
|
{decision.action_performed && (
|
||||||
<p className="mt-1 text-sm text-muted-foreground">
|
<p className="mt-1 text-sm text-[#848b9b]">
|
||||||
Action: {decision.action_performed}
|
Action: {decision.action_performed}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{decision.notes && (
|
{decision.notes && (
|
||||||
<p className="mt-2 rounded bg-white/5 p-2 text-sm text-muted-foreground">
|
<p className="mt-2 rounded bg-white/5 p-2 text-sm text-[#848b9b]">
|
||||||
Notes: {decision.notes}
|
Notes: {decision.notes}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{decision.command_output && (
|
{decision.command_output && (
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<p className="mb-1 text-xs font-medium text-muted-foreground">Command Output</p>
|
<p className="mb-1 text-xs font-medium text-[#848b9b]">Command Output</p>
|
||||||
<pre className="overflow-x-auto rounded bg-white/5 p-2 text-xs font-mono text-muted-foreground whitespace-pre-wrap">
|
<pre className="overflow-x-auto rounded bg-white/5 p-2 text-xs font-mono text-[#848b9b] whitespace-pre-wrap">
|
||||||
{decision.command_output}
|
{decision.command_output}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{decision.duration_seconds != null && (
|
{decision.duration_seconds != null && (
|
||||||
<p className="mt-2 text-xs text-muted-foreground">
|
<p className="mt-2 text-xs text-[#848b9b]">
|
||||||
Duration: {formatDuration(decision.duration_seconds)}
|
Duration: {formatDuration(decision.duration_seconds)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<p className="mt-2 text-xs text-muted-foreground">
|
<p className="mt-2 text-xs text-[#848b9b]">
|
||||||
{formatDate(decision.timestamp)}
|
{formatDate(decision.timestamp)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -176,7 +176,7 @@ export function SessionTimeline({
|
|||||||
<button
|
<button
|
||||||
onClick={() => handleCopyStep(decision, index)}
|
onClick={() => handleCopyStep(decision, index)}
|
||||||
title="Copy step to clipboard"
|
title="Copy step to clipboard"
|
||||||
className="rounded p-1 text-muted-foreground hover:bg-accent hover:text-foreground"
|
className="rounded p-1 text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb]"
|
||||||
>
|
>
|
||||||
{copiedStepIndex === index ? (
|
{copiedStepIndex === index ? (
|
||||||
<Check className="h-4 w-4 text-emerald-400" />
|
<Check className="h-4 w-4 text-emerald-400" />
|
||||||
|
|||||||
@@ -191,14 +191,14 @@ export function ShareSessionModal({ sessionId, sessionLabel, isOpen, onClose }:
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
{/* Subtitle */}
|
{/* Subtitle */}
|
||||||
<p className="-mt-2 mb-4 text-sm text-muted-foreground">{sessionLabel}</p>
|
<p className="-mt-2 mb-4 text-sm text-[#848b9b]">{sessionLabel}</p>
|
||||||
|
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* Create Share Form */}
|
{/* Create Share Form */}
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{/* Visibility */}
|
{/* Visibility */}
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-2 block text-sm font-medium text-foreground">
|
<label className="mb-2 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Visibility
|
Visibility
|
||||||
</label>
|
</label>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -207,14 +207,14 @@ export function ShareSessionModal({ sessionId, sessionLabel, isOpen, onClose }:
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex w-full items-center gap-3 rounded-md border px-4 py-3 text-left transition-colors',
|
'flex w-full items-center gap-3 rounded-md border px-4 py-3 text-left transition-colors',
|
||||||
visibility === 'account'
|
visibility === 'account'
|
||||||
? 'border-primary/30 bg-primary/10 text-foreground'
|
? 'border-primary/30 bg-[rgba(34,211,238,0.10)] text-[#e2e5eb]'
|
||||||
: 'border-border bg-transparent text-muted-foreground hover:border-border hover:bg-accent'
|
: 'border-[#1e2130] bg-transparent text-[#848b9b] hover:border-[#1e2130] hover:bg-accent'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Users className="h-4 w-4" />
|
<Users className="h-4 w-4" />
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="text-sm font-medium">Account Only</div>
|
<div className="text-sm font-medium">Account Only</div>
|
||||||
<div className="text-xs text-muted-foreground">Visible to your team</div>
|
<div className="text-xs text-[#848b9b]">Visible to your team</div>
|
||||||
</div>
|
</div>
|
||||||
{visibility === 'account' && (
|
{visibility === 'account' && (
|
||||||
<div className="h-2 w-2 rounded-full bg-primary" />
|
<div className="h-2 w-2 rounded-full bg-primary" />
|
||||||
@@ -225,14 +225,14 @@ export function ShareSessionModal({ sessionId, sessionLabel, isOpen, onClose }:
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex w-full items-center gap-3 rounded-md border px-4 py-3 text-left transition-colors',
|
'flex w-full items-center gap-3 rounded-md border px-4 py-3 text-left transition-colors',
|
||||||
visibility === 'public'
|
visibility === 'public'
|
||||||
? 'border-primary/30 bg-primary/10 text-foreground'
|
? 'border-primary/30 bg-[rgba(34,211,238,0.10)] text-[#e2e5eb]'
|
||||||
: 'border-border bg-transparent text-muted-foreground hover:border-border hover:bg-accent'
|
: 'border-[#1e2130] bg-transparent text-[#848b9b] hover:border-[#1e2130] hover:bg-accent'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Globe className="h-4 w-4" />
|
<Globe className="h-4 w-4" />
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="text-sm font-medium">Public</div>
|
<div className="text-sm font-medium">Public</div>
|
||||||
<div className="text-xs text-muted-foreground">Anyone with the link</div>
|
<div className="text-xs text-[#848b9b]">Anyone with the link</div>
|
||||||
</div>
|
</div>
|
||||||
{visibility === 'public' && (
|
{visibility === 'public' && (
|
||||||
<div className="h-2 w-2 rounded-full bg-primary" />
|
<div className="h-2 w-2 rounded-full bg-primary" />
|
||||||
@@ -246,8 +246,8 @@ export function ShareSessionModal({ sessionId, sessionLabel, isOpen, onClose }:
|
|||||||
|
|
||||||
{/* Share Name */}
|
{/* Share Name */}
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-2 block text-sm font-medium text-foreground">
|
<label className="mb-2 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Share Name <span className="text-muted-foreground">(optional)</span>
|
Share Name <span className="text-[#848b9b]">(optional)</span>
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -260,7 +260,7 @@ export function ShareSessionModal({ sessionId, sessionLabel, isOpen, onClose }:
|
|||||||
|
|
||||||
{/* Expiration */}
|
{/* Expiration */}
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-2 block text-sm font-medium text-foreground">
|
<label className="mb-2 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Expiration
|
Expiration
|
||||||
</label>
|
</label>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
@@ -271,8 +271,8 @@ export function ShareSessionModal({ sessionId, sessionLabel, isOpen, onClose }:
|
|||||||
className={cn(
|
className={cn(
|
||||||
'rounded-md border px-3 py-1.5 text-sm transition-colors',
|
'rounded-md border px-3 py-1.5 text-sm transition-colors',
|
||||||
expirationPreset === preset.value
|
expirationPreset === preset.value
|
||||||
? 'border-primary/30 bg-primary/10 text-foreground'
|
? 'border-primary/30 bg-[rgba(34,211,238,0.10)] text-[#e2e5eb]'
|
||||||
: 'border-border text-muted-foreground hover:border-border hover:bg-accent'
|
: 'border-[#1e2130] text-[#848b9b] hover:border-[#1e2130] hover:bg-accent'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{preset.label}
|
{preset.label}
|
||||||
@@ -285,7 +285,7 @@ export function ShareSessionModal({ sessionId, sessionLabel, isOpen, onClose }:
|
|||||||
value={customDatetime}
|
value={customDatetime}
|
||||||
onChange={(e) => setCustomDatetime(e.target.value)}
|
onChange={(e) => setCustomDatetime(e.target.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'mt-2 w-full rounded-md border border-border bg-card px-3 py-2 text-sm text-foreground',
|
'mt-2 w-full rounded-md border border-[#1e2130] bg-[#14161d] px-3 py-2 text-sm text-[#e2e5eb]',
|
||||||
'focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20',
|
'focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20',
|
||||||
'scheme-dark'
|
'scheme-dark'
|
||||||
)}
|
)}
|
||||||
@@ -308,7 +308,7 @@ export function ShareSessionModal({ sessionId, sessionLabel, isOpen, onClose }:
|
|||||||
{/* Existing Shares */}
|
{/* Existing Shares */}
|
||||||
{shares.length > 0 && (
|
{shares.length > 0 && (
|
||||||
<div>
|
<div>
|
||||||
<h3 className="mb-3 text-sm font-medium text-foreground">
|
<h3 className="mb-3 text-sm font-medium text-[#e2e5eb]">
|
||||||
Active Shares ({shares.length})
|
Active Shares ({shares.length})
|
||||||
</h3>
|
</h3>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
@@ -318,7 +318,7 @@ export function ShareSessionModal({ sessionId, sessionLabel, isOpen, onClose }:
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={share.id}
|
key={share.id}
|
||||||
className="bg-card border border-border rounded-xl p-4 space-y-2"
|
className="bg-[#14161d] border border-[#1e2130] rounded-lg p-4 space-y-2"
|
||||||
>
|
>
|
||||||
<div className="flex items-start justify-between gap-2">
|
<div className="flex items-start justify-between gap-2">
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
@@ -326,8 +326,8 @@ export function ShareSessionModal({ sessionId, sessionLabel, isOpen, onClose }:
|
|||||||
<span className={cn(
|
<span className={cn(
|
||||||
'inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs',
|
'inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs',
|
||||||
share.visibility === 'public'
|
share.visibility === 'public'
|
||||||
? 'bg-accent text-muted-foreground'
|
? 'bg-accent text-[#848b9b]'
|
||||||
: 'bg-accent text-muted-foreground'
|
: 'bg-accent text-[#848b9b]'
|
||||||
)}>
|
)}>
|
||||||
{share.visibility === 'public' ? (
|
{share.visibility === 'public' ? (
|
||||||
<Globe className="h-3 w-3" />
|
<Globe className="h-3 w-3" />
|
||||||
@@ -336,11 +336,11 @@ export function ShareSessionModal({ sessionId, sessionLabel, isOpen, onClose }:
|
|||||||
)}
|
)}
|
||||||
{share.visibility === 'public' ? 'Public' : 'Account'}
|
{share.visibility === 'public' ? 'Public' : 'Account'}
|
||||||
</span>
|
</span>
|
||||||
<span className="truncate text-sm font-medium text-foreground">
|
<span className="truncate text-sm font-medium text-[#e2e5eb]">
|
||||||
{share.share_name || 'Untitled share'}
|
{share.share_name || 'Untitled share'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground">
|
<div className="mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-[#848b9b]">
|
||||||
<span>{getRelativeTime(share.created_at)}</span>
|
<span>{getRelativeTime(share.created_at)}</span>
|
||||||
<span>
|
<span>
|
||||||
{share.view_count > 0
|
{share.view_count > 0
|
||||||
@@ -361,10 +361,10 @@ export function ShareSessionModal({ sessionId, sessionLabel, isOpen, onClose }:
|
|||||||
onClick={() => handleCopyUrl(share)}
|
onClick={() => handleCopyUrl(share)}
|
||||||
title="Copy share URL"
|
title="Copy share URL"
|
||||||
className={cn(
|
className={cn(
|
||||||
'rounded-md border border-border p-1.5 text-sm transition-colors',
|
'rounded-md border border-[#1e2130] p-1.5 text-sm transition-colors',
|
||||||
isCopied
|
isCopied
|
||||||
? 'border-emerald-500/30 bg-emerald-500/10 text-emerald-400'
|
? 'border-emerald-500/30 bg-emerald-500/10 text-emerald-400'
|
||||||
: 'text-muted-foreground hover:bg-accent hover:text-foreground'
|
: 'text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{isCopied ? (
|
{isCopied ? (
|
||||||
@@ -376,7 +376,7 @@ export function ShareSessionModal({ sessionId, sessionLabel, isOpen, onClose }:
|
|||||||
<button
|
<button
|
||||||
onClick={() => handleRevoke(share.id)}
|
onClick={() => handleRevoke(share.id)}
|
||||||
title="Revoke share"
|
title="Revoke share"
|
||||||
className="rounded-md border border-border p-1.5 text-muted-foreground hover:bg-red-500/10 hover:border-red-500/30 hover:text-red-400 transition-colors"
|
className="rounded-md border border-[#1e2130] p-1.5 text-[#848b9b] hover:bg-red-500/10 hover:border-red-500/30 hover:text-red-400 transition-colors"
|
||||||
>
|
>
|
||||||
<Trash2 className="h-3.5 w-3.5" />
|
<Trash2 className="h-3.5 w-3.5" />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ interface SharedSessionTreePreviewProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const nodeTypeColors: Record<string, string> = {
|
const nodeTypeColors: Record<string, string> = {
|
||||||
root: 'bg-foreground',
|
root: 'bg-[#e2e5eb]',
|
||||||
decision: 'bg-blue-400',
|
decision: 'bg-blue-400',
|
||||||
action: 'bg-yellow-400',
|
action: 'bg-yellow-400',
|
||||||
solution: 'bg-emerald-400',
|
solution: 'bg-emerald-400',
|
||||||
information: 'bg-muted-foreground',
|
information: 'bg-[#848b9b]',
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNodeTitle(node: Record<string, unknown>): string {
|
function getNodeTitle(node: Record<string, unknown>): string {
|
||||||
@@ -36,7 +36,7 @@ function TreeNode({
|
|||||||
const nodeType = (node.node_type as string) || 'decision'
|
const nodeType = (node.node_type as string) || 'decision'
|
||||||
const isInPath = pathTaken.includes(nodeId)
|
const isInPath = pathTaken.includes(nodeId)
|
||||||
const children = (node.children as Record<string, unknown>[]) || []
|
const children = (node.children as Record<string, unknown>[]) || []
|
||||||
const colorClass = nodeTypeColors[nodeType] || 'bg-muted-foreground'
|
const colorClass = nodeTypeColors[nodeType] || 'bg-[#848b9b]'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -44,8 +44,8 @@ function TreeNode({
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-2 px-3 py-1.5 text-sm',
|
'flex items-center gap-2 px-3 py-1.5 text-sm',
|
||||||
isInPath
|
isInPath
|
||||||
? 'rounded-md border-l-2 border-muted-foreground bg-accent font-medium text-foreground'
|
? 'rounded-md border-l-2 border-muted-foreground bg-accent font-medium text-[#e2e5eb]'
|
||||||
: 'text-muted-foreground'
|
: 'text-[#848b9b]'
|
||||||
)}
|
)}
|
||||||
style={{ paddingLeft: `${depth * 16 + 12}px` }}
|
style={{ paddingLeft: `${depth * 16 + 12}px` }}
|
||||||
>
|
>
|
||||||
@@ -75,9 +75,9 @@ export function SharedSessionTreePreview({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-card border border-border rounded-2xl">
|
<div className="bg-[#14161d] border border-[#1e2130] rounded-lg">
|
||||||
<div className="sticky top-0 z-10 rounded-t-2xl border-b border-border bg-black/80 px-6 py-4 backdrop-blur-sm">
|
<div className="sticky top-0 z-10 rounded-t-2xl border-b border-[#1e2130] bg-black/80 px-6 py-4 ">
|
||||||
<h3 className="text-sm font-semibold text-foreground">Tree Structure</h3>
|
<h3 className="text-sm font-semibold text-[#e2e5eb]">Tree Structure</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="max-h-[600px] overflow-y-auto py-2">
|
<div className="max-h-[600px] overflow-y-auto py-2">
|
||||||
<TreeNode node={treeStructure as unknown as Record<string, unknown>} depth={0} pathTaken={pathTaken} />
|
<TreeNode node={treeStructure as unknown as Record<string, unknown>} depth={0} pathTaken={pathTaken} />
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export function StepFeedback({ stepId, sessionId }: StepFeedbackProps) {
|
|||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{showHint && (
|
{showHint && (
|
||||||
<span className="text-xs text-muted-foreground">Was this step helpful?</span>
|
<span className="text-xs text-[#848b9b]">Was this step helpful?</span>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={() => handleFeedback(true)}
|
onClick={() => handleFeedback(true)}
|
||||||
@@ -53,7 +53,7 @@ export function StepFeedback({ stepId, sessionId }: StepFeedbackProps) {
|
|||||||
'rounded-md p-1.5 transition-colors',
|
'rounded-md p-1.5 transition-colors',
|
||||||
feedback === true
|
feedback === true
|
||||||
? 'text-emerald-400 bg-emerald-400/10'
|
? 'text-emerald-400 bg-emerald-400/10'
|
||||||
: 'text-muted-foreground hover:text-emerald-400 hover:bg-accent'
|
: 'text-[#848b9b] hover:text-emerald-400 hover:bg-accent'
|
||||||
)}
|
)}
|
||||||
title="Helpful"
|
title="Helpful"
|
||||||
>
|
>
|
||||||
@@ -66,7 +66,7 @@ export function StepFeedback({ stepId, sessionId }: StepFeedbackProps) {
|
|||||||
'rounded-md p-1.5 transition-colors',
|
'rounded-md p-1.5 transition-colors',
|
||||||
feedback === false
|
feedback === false
|
||||||
? 'text-red-400 bg-red-400/10'
|
? 'text-red-400 bg-red-400/10'
|
||||||
: 'text-muted-foreground hover:text-red-400 hover:bg-accent'
|
: 'text-[#848b9b] hover:text-red-400 hover:bg-accent'
|
||||||
)}
|
)}
|
||||||
title="Not helpful"
|
title="Not helpful"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -80,19 +80,19 @@ export function StepRatingModal({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-xs p-4">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-xs p-4">
|
||||||
<div className="bg-card border border-border w-full max-w-2xl max-h-[90vh] flex flex-col rounded-2xl shadow-lg">
|
<div className="bg-[#14161d] border border-[#1e2130] w-full max-w-2xl max-h-[90vh] flex flex-col rounded-lg shadow-lg">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between border-b border-border px-6 py-4">
|
<div className="flex items-center justify-between border-b border-[#1e2130] px-6 py-4">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-semibold text-foreground">Rate Your Experience</h2>
|
<h2 className="text-lg font-semibold text-[#e2e5eb]">Rate Your Experience</h2>
|
||||||
<p className="mt-1 text-sm text-muted-foreground">
|
<p className="mt-1 text-sm text-[#848b9b]">
|
||||||
Help others by rating the steps you used ({librarySteps.length} step{librarySteps.length !== 1 ? 's' : ''})
|
Help others by rating the steps you used ({librarySteps.length} step{librarySteps.length !== 1 ? 's' : ''})
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
className="rounded-full p-1 text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-50"
|
className="rounded-full p-1 text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb] disabled:opacity-50"
|
||||||
>
|
>
|
||||||
<X className="h-5 w-5" />
|
<X className="h-5 w-5" />
|
||||||
</button>
|
</button>
|
||||||
@@ -104,14 +104,14 @@ export function StepRatingModal({
|
|||||||
{librarySteps.map((step) => {
|
{librarySteps.map((step) => {
|
||||||
const rating = getRating(step.id)
|
const rating = getRating(step.id)
|
||||||
return (
|
return (
|
||||||
<div key={step.id} className="rounded-lg border border-border bg-background p-4">
|
<div key={step.id} className="rounded-lg border border-[#1e2130] bg-[#0c0d10] p-4">
|
||||||
{/* Step Title */}
|
{/* Step Title */}
|
||||||
<h3 className="font-medium text-foreground">{step.title}</h3>
|
<h3 className="font-medium text-[#e2e5eb]">{step.title}</h3>
|
||||||
<p className="mt-1 text-sm text-muted-foreground capitalize">{step.step_type}</p>
|
<p className="mt-1 text-sm text-[#848b9b] capitalize">{step.step_type}</p>
|
||||||
|
|
||||||
{/* Star Rating */}
|
{/* Star Rating */}
|
||||||
<div className="mt-3">
|
<div className="mt-3">
|
||||||
<label className="mb-1 block text-sm font-medium text-foreground">
|
<label className="mb-1 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Rating
|
Rating
|
||||||
</label>
|
</label>
|
||||||
<StarRating
|
<StarRating
|
||||||
@@ -123,7 +123,7 @@ export function StepRatingModal({
|
|||||||
|
|
||||||
{/* Was this helpful? */}
|
{/* Was this helpful? */}
|
||||||
<div className="mt-3">
|
<div className="mt-3">
|
||||||
<label className="mb-2 block text-sm font-medium text-foreground">
|
<label className="mb-2 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Was this helpful?
|
Was this helpful?
|
||||||
</label>
|
</label>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
@@ -135,7 +135,7 @@ export function StepRatingModal({
|
|||||||
'flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium transition-colors',
|
'flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium transition-colors',
|
||||||
rating?.helpful === true
|
rating?.helpful === true
|
||||||
? 'border-emerald-400/20 bg-emerald-400/10 text-emerald-400'
|
? 'border-emerald-400/20 bg-emerald-400/10 text-emerald-400'
|
||||||
: 'border-border text-muted-foreground hover:bg-accent hover:text-foreground',
|
: 'border-[#1e2130] text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb]',
|
||||||
'disabled:opacity-50'
|
'disabled:opacity-50'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -150,7 +150,7 @@ export function StepRatingModal({
|
|||||||
'flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium transition-colors',
|
'flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium transition-colors',
|
||||||
rating?.helpful === false
|
rating?.helpful === false
|
||||||
? 'border-red-400/20 bg-red-400/10 text-red-400'
|
? 'border-red-400/20 bg-red-400/10 text-red-400'
|
||||||
: 'border-border text-muted-foreground hover:bg-accent hover:text-foreground',
|
: 'border-[#1e2130] text-[#848b9b] hover:bg-accent hover:text-[#e2e5eb]',
|
||||||
'disabled:opacity-50'
|
'disabled:opacity-50'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -162,8 +162,8 @@ export function StepRatingModal({
|
|||||||
|
|
||||||
{/* Optional Review */}
|
{/* Optional Review */}
|
||||||
<div className="mt-3">
|
<div className="mt-3">
|
||||||
<label htmlFor={`review-${step.id}`} className="mb-1 block text-sm font-medium text-foreground">
|
<label htmlFor={`review-${step.id}`} className="mb-1 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Review <span className="text-muted-foreground">(optional)</span>
|
Review <span className="text-[#848b9b]">(optional)</span>
|
||||||
</label>
|
</label>
|
||||||
<Textarea
|
<Textarea
|
||||||
id={`review-${step.id}`}
|
id={`review-${step.id}`}
|
||||||
@@ -174,7 +174,7 @@ export function StepRatingModal({
|
|||||||
rows={2}
|
rows={2}
|
||||||
placeholder="Share your experience with this step..."
|
placeholder="Share your experience with this step..."
|
||||||
/>
|
/>
|
||||||
<p className="mt-1 text-xs text-muted-foreground text-right">
|
<p className="mt-1 text-xs text-[#848b9b] text-right">
|
||||||
{rating?.review?.length || 0}/500
|
{rating?.review?.length || 0}/500
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -185,7 +185,7 @@ export function StepRatingModal({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<div className="flex justify-end gap-2 border-t border-border px-6 py-4">
|
<div className="flex justify-end gap-2 border-t border-[#1e2130] px-6 py-4">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
|
|||||||
@@ -49,22 +49,22 @@ export function SupportingDataPanel({ sessionId }: SupportingDataPanelProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-xl border border-border bg-card/50">
|
<div className="rounded-xl border border-[#1e2130] bg-card/50">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between px-4 py-3">
|
<div className="flex items-center justify-between px-4 py-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setIsExpanded(!isExpanded)}
|
onClick={() => setIsExpanded(!isExpanded)}
|
||||||
className="flex items-center gap-2 text-sm font-medium text-foreground hover:text-foreground/80"
|
className="flex items-center gap-2 text-sm font-medium text-[#e2e5eb] hover:text-[#e2e5eb]/80"
|
||||||
>
|
>
|
||||||
{isExpanded ? (
|
{isExpanded ? (
|
||||||
<ChevronDown className="h-4 w-4 text-muted-foreground" />
|
<ChevronDown className="h-4 w-4 text-[#848b9b]" />
|
||||||
) : (
|
) : (
|
||||||
<ChevronRight className="h-4 w-4 text-muted-foreground" />
|
<ChevronRight className="h-4 w-4 text-[#848b9b]" />
|
||||||
)}
|
)}
|
||||||
Supporting Data
|
Supporting Data
|
||||||
{items.length > 0 && (
|
{items.length > 0 && (
|
||||||
<span className="rounded-full bg-accent px-2 py-0.5 text-xs text-muted-foreground">
|
<span className="rounded-full bg-accent px-2 py-0.5 text-xs text-[#848b9b]">
|
||||||
{items.length}
|
{items.length}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -73,8 +73,8 @@ export function SupportingDataPanel({ sessionId }: SupportingDataPanelProps) {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowAddModal(true)}
|
onClick={() => setShowAddModal(true)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-1.5 rounded-[10px] px-3 py-1.5 text-xs font-medium',
|
'flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium',
|
||||||
'bg-gradient-brand text-[#101114] hover:opacity-90 active:scale-[0.97] transition-all'
|
'bg-[#22d3ee] text-white hover:brightness-110 active:scale-[0.98] transition-all'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Plus className="h-3.5 w-3.5" />
|
<Plus className="h-3.5 w-3.5" />
|
||||||
@@ -84,11 +84,11 @@ export function SupportingDataPanel({ sessionId }: SupportingDataPanelProps) {
|
|||||||
|
|
||||||
{/* Items list */}
|
{/* Items list */}
|
||||||
{isExpanded && (
|
{isExpanded && (
|
||||||
<div className="border-t border-border px-4 py-2">
|
<div className="border-t border-[#1e2130] px-4 py-2">
|
||||||
{isLoading && items.length === 0 ? (
|
{isLoading && items.length === 0 ? (
|
||||||
<p className="py-4 text-center text-xs text-muted-foreground">Loading...</p>
|
<p className="py-4 text-center text-xs text-[#848b9b]">Loading...</p>
|
||||||
) : items.length === 0 ? (
|
) : items.length === 0 ? (
|
||||||
<p className="py-4 text-center text-xs text-muted-foreground">
|
<p className="py-4 text-center text-xs text-[#848b9b]">
|
||||||
No supporting data yet. Add text snippets or screenshots to include in exports.
|
No supporting data yet. Add text snippets or screenshots to include in exports.
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
@@ -97,11 +97,11 @@ export function SupportingDataPanel({ sessionId }: SupportingDataPanelProps) {
|
|||||||
<div
|
<div
|
||||||
key={item.id}
|
key={item.id}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex items-start gap-3 rounded-lg border border-border bg-card/30 px-3 py-2.5',
|
'flex items-start gap-3 rounded-lg border border-[#1e2130] bg-card/30 px-3 py-2.5',
|
||||||
'group transition-colors hover:border-[rgba(255,255,255,0.12)]'
|
'group transition-colors hover:border-[rgba(255,255,255,0.12)]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className="mt-0.5 shrink-0 text-muted-foreground">
|
<span className="mt-0.5 shrink-0 text-[#848b9b]">
|
||||||
{item.data_type === 'text_snippet' ? (
|
{item.data_type === 'text_snippet' ? (
|
||||||
<Code2 className="h-4 w-4" />
|
<Code2 className="h-4 w-4" />
|
||||||
) : (
|
) : (
|
||||||
@@ -109,9 +109,9 @@ export function SupportingDataPanel({ sessionId }: SupportingDataPanelProps) {
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<p className="text-sm font-medium text-foreground">{item.label}</p>
|
<p className="text-sm font-medium text-[#e2e5eb]">{item.label}</p>
|
||||||
{item.data_type === 'text_snippet' && item.content && (
|
{item.data_type === 'text_snippet' && item.content && (
|
||||||
<p className="mt-0.5 truncate text-xs font-mono text-muted-foreground">
|
<p className="mt-0.5 truncate text-xs font-mono text-[#848b9b]">
|
||||||
{item.content.length > 120 ? item.content.slice(0, 120) + '...' : item.content}
|
{item.content.length > 120 ? item.content.slice(0, 120) + '...' : item.content}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -119,14 +119,14 @@ export function SupportingDataPanel({ sessionId }: SupportingDataPanelProps) {
|
|||||||
<img
|
<img
|
||||||
src={`data:${item.content_type || 'image/png'};base64,${item.content}`}
|
src={`data:${item.content_type || 'image/png'};base64,${item.content}`}
|
||||||
alt={item.label}
|
alt={item.label}
|
||||||
className="mt-1 max-h-16 rounded border border-border object-contain"
|
className="mt-1 max-h-16 rounded border border-[#1e2130] object-contain"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleDelete(item.id)}
|
onClick={() => handleDelete(item.id)}
|
||||||
className="shrink-0 text-muted-foreground opacity-0 transition-opacity hover:text-rose-500 group-hover:opacity-100"
|
className="shrink-0 text-[#848b9b] opacity-0 transition-opacity hover:text-rose-500 group-hover:opacity-100"
|
||||||
title="Remove"
|
title="Remove"
|
||||||
>
|
>
|
||||||
<Trash2 className="h-4 w-4" />
|
<Trash2 className="h-4 w-4" />
|
||||||
|
|||||||
@@ -38,14 +38,14 @@ function AccordionSection({ label, icon, count, children }: AccordionSectionProp
|
|||||||
onClick={() => setOpen(!open)}
|
onClick={() => setOpen(!open)}
|
||||||
className="flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-[rgba(255,255,255,0.03)] transition-colors"
|
className="flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-[rgba(255,255,255,0.03)] transition-colors"
|
||||||
>
|
>
|
||||||
<span className="text-muted-foreground">{icon}</span>
|
<span className="text-[#848b9b]">{icon}</span>
|
||||||
<span className="flex-1 text-xs font-medium text-foreground">{label}</span>
|
<span className="flex-1 text-xs font-medium text-[#e2e5eb]">{label}</span>
|
||||||
{count !== undefined && count > 0 && (
|
{count !== undefined && count > 0 && (
|
||||||
<span className="rounded-full bg-primary/10 px-1.5 py-0.5 text-[0.6rem] font-label text-primary">
|
<span className="rounded-full bg-[rgba(34,211,238,0.10)] px-1.5 py-0.5 text-[0.6rem] font-sans text-xs text-[#22d3ee]">
|
||||||
{count}
|
{count}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<span className="text-muted-foreground">
|
<span className="text-[#848b9b]">
|
||||||
{open ? <ChevronDown className="h-3.5 w-3.5" /> : <ChevronRight className="h-3.5 w-3.5" />}
|
{open ? <ChevronDown className="h-3.5 w-3.5" /> : <ChevronRight className="h-3.5 w-3.5" />}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -60,18 +60,18 @@ function AccordionSection({ label, icon, count, children }: AccordionSectionProp
|
|||||||
|
|
||||||
export function TicketContextPanel({ context, loading, error, onRefresh }: TicketContextPanelProps) {
|
export function TicketContextPanel({ context, loading, error, onRefresh }: TicketContextPanelProps) {
|
||||||
return (
|
return (
|
||||||
<div className="glass-card-static overflow-hidden rounded-2xl">
|
<div className="card-flat overflow-hidden rounded-lg">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center gap-2 bg-primary/5 px-3 py-2.5">
|
<div className="flex items-center gap-2 bg-[rgba(34,211,238,0.05)] px-3 py-2.5">
|
||||||
<Ticket className="h-3.5 w-3.5 text-primary" />
|
<Ticket className="h-3.5 w-3.5 text-[#22d3ee]" />
|
||||||
<span className="flex-1 font-label text-[0.625rem] uppercase tracking-[0.1em] text-primary">
|
<span className="flex-1 font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#22d3ee]">
|
||||||
Ticket Context
|
Ticket Context
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
onClick={onRefresh}
|
onClick={onRefresh}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
title="Refresh ticket context"
|
title="Refresh ticket context"
|
||||||
className="rounded p-0.5 text-muted-foreground hover:text-foreground disabled:cursor-not-allowed transition-colors"
|
className="rounded p-0.5 text-[#848b9b] hover:text-[#e2e5eb] disabled:cursor-not-allowed transition-colors"
|
||||||
>
|
>
|
||||||
<RefreshCw className={cn('h-3 w-3', loading && 'animate-spin')} />
|
<RefreshCw className={cn('h-3 w-3', loading && 'animate-spin')} />
|
||||||
</button>
|
</button>
|
||||||
@@ -80,7 +80,7 @@ export function TicketContextPanel({ context, loading, error, onRefresh }: Ticke
|
|||||||
{/* Loading */}
|
{/* Loading */}
|
||||||
{loading && !context && (
|
{loading && !context && (
|
||||||
<div className="flex items-center justify-center py-6">
|
<div className="flex items-center justify-center py-6">
|
||||||
<Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
|
<Loader2 className="h-5 w-5 animate-spin text-[#848b9b]" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -98,43 +98,43 @@ export function TicketContextPanel({ context, loading, error, onRefresh }: Ticke
|
|||||||
{/* Compact summary */}
|
{/* Compact summary */}
|
||||||
<div className="px-3 py-2.5">
|
<div className="px-3 py-2.5">
|
||||||
<div className="flex items-baseline gap-2">
|
<div className="flex items-baseline gap-2">
|
||||||
<span className="font-label text-xs font-medium text-primary">#{context.ticket.id}</span>
|
<span className="font-sans text-xs text-xs font-medium text-[#22d3ee]">#{context.ticket.id}</span>
|
||||||
<span className="flex-1 truncate text-xs text-foreground">{context.ticket.summary}</span>
|
<span className="flex-1 truncate text-xs text-[#e2e5eb]">{context.ticket.summary}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1.5 flex flex-wrap gap-1.5">
|
<div className="mt-1.5 flex flex-wrap gap-1.5">
|
||||||
<span className="rounded-md bg-card px-1.5 py-0.5 font-label text-[0.6rem] text-muted-foreground border border-[rgba(255,255,255,0.06)]">
|
<span className="rounded-md bg-[#14161d] px-1.5 py-0.5 font-sans text-xs text-[0.6rem] text-[#848b9b] border border-[rgba(255,255,255,0.06)]">
|
||||||
{context.ticket.status}
|
{context.ticket.status}
|
||||||
</span>
|
</span>
|
||||||
<span className="rounded-md bg-card px-1.5 py-0.5 font-label text-[0.6rem] text-muted-foreground border border-[rgba(255,255,255,0.06)]">
|
<span className="rounded-md bg-[#14161d] px-1.5 py-0.5 font-sans text-xs text-[0.6rem] text-[#848b9b] border border-[rgba(255,255,255,0.06)]">
|
||||||
{context.ticket.priority}
|
{context.ticket.priority}
|
||||||
</span>
|
</span>
|
||||||
{context.ticket.sla && (
|
{context.ticket.sla && (
|
||||||
<span className="rounded-md bg-amber-400/10 px-1.5 py-0.5 font-label text-[0.6rem] text-amber-400 border border-amber-400/20">
|
<span className="rounded-md bg-amber-400/10 px-1.5 py-0.5 font-sans text-xs text-[0.6rem] text-amber-400 border border-amber-400/20">
|
||||||
SLA: {context.ticket.sla}
|
SLA: {context.ticket.sla}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-1 text-[0.6875rem] text-muted-foreground">{context.company.name}</p>
|
<p className="mt-1 text-[0.6875rem] text-[#848b9b]">{context.company.name}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Client */}
|
{/* Client */}
|
||||||
<AccordionSection label="Client" icon={<Building2 className="h-3.5 w-3.5" />}>
|
<AccordionSection label="Client" icon={<Building2 className="h-3.5 w-3.5" />}>
|
||||||
<div className="space-y-1 text-xs">
|
<div className="space-y-1 text-xs">
|
||||||
<p className="font-medium text-foreground">{context.company.name}</p>
|
<p className="font-medium text-[#e2e5eb]">{context.company.name}</p>
|
||||||
{context.company.type && (
|
{context.company.type && (
|
||||||
<p className="text-muted-foreground">Type: {context.company.type}</p>
|
<p className="text-[#848b9b]">Type: {context.company.type}</p>
|
||||||
)}
|
)}
|
||||||
{context.company.territory && (
|
{context.company.territory && (
|
||||||
<p className="text-muted-foreground">Territory: {context.company.territory}</p>
|
<p className="text-[#848b9b]">Territory: {context.company.territory}</p>
|
||||||
)}
|
)}
|
||||||
{context.company.site && (
|
{context.company.site && (
|
||||||
<p className="text-muted-foreground">Site: {context.company.site}</p>
|
<p className="text-[#848b9b]">Site: {context.company.site}</p>
|
||||||
)}
|
)}
|
||||||
{context.company.address && (
|
{context.company.address && (
|
||||||
<p className="text-muted-foreground">{context.company.address}</p>
|
<p className="text-[#848b9b]">{context.company.address}</p>
|
||||||
)}
|
)}
|
||||||
{context.company.phone && (
|
{context.company.phone && (
|
||||||
<p className="text-muted-foreground">{context.company.phone}</p>
|
<p className="text-[#848b9b]">{context.company.phone}</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</AccordionSection>
|
</AccordionSection>
|
||||||
@@ -143,15 +143,15 @@ export function TicketContextPanel({ context, loading, error, onRefresh }: Ticke
|
|||||||
{context.contact && (
|
{context.contact && (
|
||||||
<AccordionSection label="Contact" icon={<UserCircle className="h-3.5 w-3.5" />}>
|
<AccordionSection label="Contact" icon={<UserCircle className="h-3.5 w-3.5" />}>
|
||||||
<div className="space-y-1 text-xs">
|
<div className="space-y-1 text-xs">
|
||||||
<p className="font-medium text-foreground">{context.contact.name}</p>
|
<p className="font-medium text-[#e2e5eb]">{context.contact.name}</p>
|
||||||
{context.contact.title && (
|
{context.contact.title && (
|
||||||
<p className="text-muted-foreground">{context.contact.title}</p>
|
<p className="text-[#848b9b]">{context.contact.title}</p>
|
||||||
)}
|
)}
|
||||||
{context.contact.email && (
|
{context.contact.email && (
|
||||||
<p className="text-muted-foreground">{context.contact.email}</p>
|
<p className="text-[#848b9b]">{context.contact.email}</p>
|
||||||
)}
|
)}
|
||||||
{context.contact.phone && (
|
{context.contact.phone && (
|
||||||
<p className="text-muted-foreground">{context.contact.phone}</p>
|
<p className="text-[#848b9b]">{context.contact.phone}</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</AccordionSection>
|
</AccordionSection>
|
||||||
@@ -166,9 +166,9 @@ export function TicketContextPanel({ context, loading, error, onRefresh }: Ticke
|
|||||||
>
|
>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{context.configurations.map((cfg, i) => (
|
{context.configurations.map((cfg, i) => (
|
||||||
<div key={i} className="rounded-md border border-[rgba(255,255,255,0.06)] bg-card p-2">
|
<div key={i} className="rounded-md border border-[rgba(255,255,255,0.06)] bg-[#14161d] p-2">
|
||||||
<p className="text-xs font-medium text-foreground">{cfg.device_identifier}</p>
|
<p className="text-xs font-medium text-[#e2e5eb]">{cfg.device_identifier}</p>
|
||||||
<div className="mt-0.5 space-y-0.5 text-[0.6875rem] text-muted-foreground">
|
<div className="mt-0.5 space-y-0.5 text-[0.6875rem] text-[#848b9b]">
|
||||||
{cfg.type && <p>Type: {cfg.type}</p>}
|
{cfg.type && <p>Type: {cfg.type}</p>}
|
||||||
{cfg.os_type && <p>OS: {cfg.os_type}</p>}
|
{cfg.os_type && <p>OS: {cfg.os_type}</p>}
|
||||||
{cfg.ip_address && <p>IP: {cfg.ip_address}</p>}
|
{cfg.ip_address && <p>IP: {cfg.ip_address}</p>}
|
||||||
@@ -190,16 +190,16 @@ export function TicketContextPanel({ context, loading, error, onRefresh }: Ticke
|
|||||||
>
|
>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{context.notes.map((note, i) => (
|
{context.notes.map((note, i) => (
|
||||||
<div key={i} className="rounded-md border border-[rgba(255,255,255,0.06)] bg-card p-2">
|
<div key={i} className="rounded-md border border-[rgba(255,255,255,0.06)] bg-[#14161d] p-2">
|
||||||
<div className="mb-1 flex items-center justify-between gap-2">
|
<div className="mb-1 flex items-center justify-between gap-2">
|
||||||
{note.member && (
|
{note.member && (
|
||||||
<span className="text-[0.6rem] font-label text-muted-foreground">{note.member}</span>
|
<span className="text-[0.6rem] font-sans text-xs text-[#848b9b]">{note.member}</span>
|
||||||
)}
|
)}
|
||||||
<span className="ml-auto text-[0.6rem] font-label text-muted-foreground">
|
<span className="ml-auto text-[0.6rem] font-sans text-xs text-[#848b9b]">
|
||||||
{new Date(note.date_created).toLocaleDateString()}
|
{new Date(note.date_created).toLocaleDateString()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="whitespace-pre-wrap text-[0.6875rem] text-foreground line-clamp-4">
|
<p className="whitespace-pre-wrap text-[0.6875rem] text-[#e2e5eb] line-clamp-4">
|
||||||
{note.text}
|
{note.text}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -219,16 +219,16 @@ export function TicketContextPanel({ context, loading, error, onRefresh }: Ticke
|
|||||||
{context.related_tickets.map((rt) => (
|
{context.related_tickets.map((rt) => (
|
||||||
<div
|
<div
|
||||||
key={rt.id}
|
key={rt.id}
|
||||||
className="rounded-md border border-[rgba(255,255,255,0.06)] bg-card px-2 py-1.5"
|
className="rounded-md border border-[rgba(255,255,255,0.06)] bg-[#14161d] px-2 py-1.5"
|
||||||
>
|
>
|
||||||
<div className="flex items-baseline gap-1.5">
|
<div className="flex items-baseline gap-1.5">
|
||||||
<span className="font-label text-[0.6rem] text-primary">#{rt.id}</span>
|
<span className="font-sans text-xs text-[0.6rem] text-[#22d3ee]">#{rt.id}</span>
|
||||||
<span className="flex-1 truncate text-[0.6875rem] text-foreground">{rt.summary}</span>
|
<span className="flex-1 truncate text-[0.6875rem] text-[#e2e5eb]">{rt.summary}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-0.5 flex gap-1">
|
<div className="mt-0.5 flex gap-1">
|
||||||
<span className="text-[0.6rem] text-muted-foreground">{rt.status}</span>
|
<span className="text-[0.6rem] text-[#848b9b]">{rt.status}</span>
|
||||||
<span className="text-[0.6rem] text-muted-foreground">·</span>
|
<span className="text-[0.6rem] text-[#848b9b]">·</span>
|
||||||
<span className="text-[0.6rem] text-muted-foreground">{rt.priority}</span>
|
<span className="text-[0.6rem] text-[#848b9b]">{rt.priority}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ export function TicketLinkIndicator({ session, hasConnection, onLinkClick, onUnl
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={onLinkClick}
|
onClick={onLinkClick}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center gap-1.5 rounded-lg px-2 py-1 text-xs text-muted-foreground transition-colors',
|
'inline-flex items-center gap-1.5 rounded-lg px-2 py-1 text-xs text-[#848b9b] transition-colors',
|
||||||
'hover:bg-accent hover:text-foreground'
|
'hover:bg-accent hover:text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Link2 className="h-3.5 w-3.5" />
|
<Link2 className="h-3.5 w-3.5" />
|
||||||
@@ -35,17 +35,17 @@ export function TicketLinkIndicator({ session, hasConnection, onLinkClick, onUnl
|
|||||||
|
|
||||||
// Ticket linked
|
// Ticket linked
|
||||||
return (
|
return (
|
||||||
<div className="glass-card-static inline-flex items-start gap-2.5 rounded-lg border border-border px-3 py-2">
|
<div className="card-flat inline-flex items-start gap-2.5 rounded-lg border border-[#1e2130] px-3 py-2">
|
||||||
<Ticket className="mt-0.5 h-4 w-4 shrink-0 text-cyan-400" />
|
<Ticket className="mt-0.5 h-4 w-4 shrink-0 text-cyan-400" />
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="text-sm font-medium text-foreground">
|
<p className="text-sm font-medium text-[#e2e5eb]">
|
||||||
CW #{session.psa_ticket_id}
|
CW #{session.psa_ticket_id}
|
||||||
{ticketInfo?.summary && (
|
{ticketInfo?.summary && (
|
||||||
<span className="text-muted-foreground"> — {ticketInfo.summary}</span>
|
<span className="text-[#848b9b]"> — {ticketInfo.summary}</span>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
{ticketInfo && (
|
{ticketInfo && (
|
||||||
<div className="mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-muted-foreground">
|
<div className="mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-[#848b9b]">
|
||||||
{ticketInfo.company_name && <span>{ticketInfo.company_name}</span>}
|
{ticketInfo.company_name && <span>{ticketInfo.company_name}</span>}
|
||||||
{ticketInfo.board_name && (
|
{ticketInfo.board_name && (
|
||||||
<>
|
<>
|
||||||
@@ -68,8 +68,8 @@ export function TicketLinkIndicator({ session, hasConnection, onLinkClick, onUnl
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={onUpdateClick}
|
onClick={onUpdateClick}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs text-muted-foreground transition-colors',
|
'inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs text-[#848b9b] transition-colors',
|
||||||
'hover:bg-primary/10 hover:text-foreground'
|
'hover:bg-[rgba(34,211,238,0.10)] hover:text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
title="Update ticket"
|
title="Update ticket"
|
||||||
>
|
>
|
||||||
@@ -80,7 +80,7 @@ export function TicketLinkIndicator({ session, hasConnection, onLinkClick, onUnl
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onUnlink}
|
onClick={onUnlink}
|
||||||
className="shrink-0 rounded p-0.5 text-xs text-muted-foreground transition-colors hover:text-foreground"
|
className="shrink-0 rounded p-0.5 text-xs text-[#848b9b] transition-colors hover:text-[#e2e5eb]"
|
||||||
title="Unlink ticket"
|
title="Unlink ticket"
|
||||||
>
|
>
|
||||||
<Unlink className="h-3.5 w-3.5" />
|
<Unlink className="h-3.5 w-3.5" />
|
||||||
|
|||||||
@@ -219,8 +219,8 @@ export function TicketPickerModal({ open, onClose, sessionId, onLinked, onSelect
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex flex-1 items-center justify-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-all',
|
'flex flex-1 items-center justify-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-all',
|
||||||
mode === 'search'
|
mode === 'search'
|
||||||
? 'bg-white/[0.08] text-foreground shadow-sm'
|
? 'bg-white/[0.08] text-[#e2e5eb] shadow-sm'
|
||||||
: 'text-muted-foreground hover:text-foreground'
|
: 'text-[#848b9b] hover:text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Search className="h-3.5 w-3.5" />
|
<Search className="h-3.5 w-3.5" />
|
||||||
@@ -232,8 +232,8 @@ export function TicketPickerModal({ open, onClose, sessionId, onLinked, onSelect
|
|||||||
className={cn(
|
className={cn(
|
||||||
'flex flex-1 items-center justify-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-all',
|
'flex flex-1 items-center justify-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-all',
|
||||||
mode === 'manual'
|
mode === 'manual'
|
||||||
? 'bg-white/[0.08] text-foreground shadow-sm'
|
? 'bg-white/[0.08] text-[#e2e5eb] shadow-sm'
|
||||||
: 'text-muted-foreground hover:text-foreground'
|
: 'text-[#848b9b] hover:text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Hash className="h-3.5 w-3.5" />
|
<Hash className="h-3.5 w-3.5" />
|
||||||
@@ -257,12 +257,12 @@ export function TicketPickerModal({ open, onClose, sessionId, onLinked, onSelect
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Include closed toggle */}
|
{/* Include closed toggle */}
|
||||||
<label className="flex cursor-pointer items-center gap-2 text-xs text-muted-foreground">
|
<label className="flex cursor-pointer items-center gap-2 text-xs text-[#848b9b]">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={includeClosed}
|
checked={includeClosed}
|
||||||
onChange={(e) => setIncludeClosed(e.target.checked)}
|
onChange={(e) => setIncludeClosed(e.target.checked)}
|
||||||
className="rounded border-border bg-card accent-primary"
|
className="rounded border-[#1e2130] bg-[#14161d] accent-primary"
|
||||||
/>
|
/>
|
||||||
Include closed tickets
|
Include closed tickets
|
||||||
</label>
|
</label>
|
||||||
@@ -270,12 +270,12 @@ export function TicketPickerModal({ open, onClose, sessionId, onLinked, onSelect
|
|||||||
{/* Search results */}
|
{/* Search results */}
|
||||||
{isSearching && (
|
{isSearching && (
|
||||||
<div className="flex items-center justify-center py-6">
|
<div className="flex items-center justify-center py-6">
|
||||||
<Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
|
<Loader2 className="h-5 w-5 animate-spin text-[#848b9b]" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!isSearching && hasSearched && searchResults.length === 0 && (
|
{!isSearching && hasSearched && searchResults.length === 0 && (
|
||||||
<div className="py-6 text-center text-sm text-muted-foreground">
|
<div className="py-6 text-center text-sm text-[#848b9b]">
|
||||||
No tickets found
|
No tickets found
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -290,17 +290,17 @@ export function TicketPickerModal({ open, onClose, sessionId, onLinked, onSelect
|
|||||||
disabled={isLooking}
|
disabled={isLooking}
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full rounded-lg border border-transparent px-3 py-2.5 text-left transition-all',
|
'w-full rounded-lg border border-transparent px-3 py-2.5 text-left transition-all',
|
||||||
'hover:border-border hover:bg-white/[0.04]',
|
'hover:border-[#1e2130] hover:bg-white/[0.04]',
|
||||||
'disabled:opacity-50',
|
'disabled:opacity-50',
|
||||||
result.closed && 'opacity-60'
|
result.closed && 'opacity-60'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<p className="truncate text-sm font-medium text-foreground">
|
<p className="truncate text-sm font-medium text-[#e2e5eb]">
|
||||||
<span className="text-muted-foreground">#{result.id}</span>
|
<span className="text-[#848b9b]">#{result.id}</span>
|
||||||
{' — '}
|
{' — '}
|
||||||
{result.summary}
|
{result.summary}
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-0.5 flex flex-wrap items-center gap-x-2 text-xs text-muted-foreground">
|
<div className="mt-0.5 flex flex-wrap items-center gap-x-2 text-xs text-[#848b9b]">
|
||||||
{result.company_name && <span>{result.company_name}</span>}
|
{result.company_name && <span>{result.company_name}</span>}
|
||||||
{result.board_name && (
|
{result.board_name && (
|
||||||
<>
|
<>
|
||||||
@@ -324,8 +324,8 @@ export function TicketPickerModal({ open, onClose, sessionId, onLinked, onSelect
|
|||||||
|
|
||||||
{isLooking && (
|
{isLooking && (
|
||||||
<div className="flex items-center justify-center py-3">
|
<div className="flex items-center justify-center py-3">
|
||||||
<Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
|
<Loader2 className="h-5 w-5 animate-spin text-[#848b9b]" />
|
||||||
<span className="ml-2 text-sm text-muted-foreground">Loading ticket details...</span>
|
<span className="ml-2 text-sm text-[#848b9b]">Loading ticket details...</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -334,7 +334,7 @@ export function TicketPickerModal({ open, onClose, sessionId, onLinked, onSelect
|
|||||||
{/* Manual mode */}
|
{/* Manual mode */}
|
||||||
{mode === 'manual' && !selectedTicket && (
|
{mode === 'manual' && !selectedTicket && (
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-1.5 block text-sm font-medium text-foreground">
|
<label className="mb-1.5 block text-sm font-medium text-[#e2e5eb]">
|
||||||
Ticket Number
|
Ticket Number
|
||||||
</label>
|
</label>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
@@ -376,14 +376,14 @@ export function TicketPickerModal({ open, onClose, sessionId, onLinked, onSelect
|
|||||||
|
|
||||||
{/* Selected ticket confirmation card */}
|
{/* Selected ticket confirmation card */}
|
||||||
{selectedTicket && selectedTicketId && (
|
{selectedTicket && selectedTicketId && (
|
||||||
<div className="glass-card-static space-y-3 rounded-xl border border-border p-4">
|
<div className="card-flat space-y-3 rounded-xl border border-[#1e2130] p-4">
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<CheckCircle2 className="mt-0.5 h-4 w-4 shrink-0 text-emerald-400" />
|
<CheckCircle2 className="mt-0.5 h-4 w-4 shrink-0 text-emerald-400" />
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="text-sm font-semibold text-foreground">
|
<p className="text-sm font-semibold text-[#e2e5eb]">
|
||||||
CW #{selectedTicketId} — {selectedTicket.summary}
|
CW #{selectedTicketId} — {selectedTicket.summary}
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-1.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground">
|
<div className="mt-1.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-[#848b9b]">
|
||||||
{selectedTicket.company_name && (
|
{selectedTicket.company_name && (
|
||||||
<span>{selectedTicket.company_name}</span>
|
<span>{selectedTicket.company_name}</span>
|
||||||
)}
|
)}
|
||||||
@@ -437,8 +437,8 @@ export function TicketPickerModal({ open, onClose, sessionId, onLinked, onSelect
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
className={cn(
|
className={cn(
|
||||||
'text-sm text-muted-foreground transition-colors',
|
'text-sm text-[#848b9b] transition-colors',
|
||||||
'hover:text-foreground'
|
'hover:text-[#e2e5eb]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
Skip
|
Skip
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ export function UpdateTicketModal({ open, onClose, sessionId, onPosted }: Props)
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
className="text-sm text-[#848b9b] hover:text-[#e2e5eb] transition-colors"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
@@ -143,9 +143,9 @@ export function UpdateTicketModal({ open, onClose, sessionId, onPosted }: Props)
|
|||||||
onClick={handlePost}
|
onClick={handlePost}
|
||||||
disabled={isPosting || !content.trim()}
|
disabled={isPosting || !content.trim()}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center gap-2 rounded-[10px] px-5 py-2.5 text-sm font-semibold',
|
'inline-flex items-center gap-2 rounded-lg px-5 py-2.5 text-sm font-semibold',
|
||||||
'bg-gradient-brand text-[#101114] shadow-lg shadow-primary/20',
|
'bg-[#22d3ee] text-white',
|
||||||
'hover:opacity-90 active:scale-[0.97] transition-all',
|
'hover:brightness-110 active:scale-[0.98] transition-all',
|
||||||
'disabled:opacity-50 disabled:cursor-not-allowed'
|
'disabled:opacity-50 disabled:cursor-not-allowed'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -160,7 +160,7 @@ export function UpdateTicketModal({ open, onClose, sessionId, onPosted }: Props)
|
|||||||
<Modal isOpen={open} onClose={onClose} title="Update Ticket" size="xl" footer={footer}>
|
<Modal isOpen={open} onClose={onClose} title="Update Ticket" size="xl" footer={footer}>
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="flex items-center justify-center py-12">
|
<div className="flex items-center justify-center py-12">
|
||||||
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
|
<Loader2 className="h-8 w-8 animate-spin text-[#848b9b]" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ export function UpdateTicketModal({ open, onClose, sessionId, onPosted }: Props)
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={loadPreview}
|
onClick={loadPreview}
|
||||||
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
className="text-sm text-[#848b9b] hover:text-[#e2e5eb] transition-colors"
|
||||||
>
|
>
|
||||||
Try again
|
Try again
|
||||||
</button>
|
</button>
|
||||||
@@ -184,13 +184,13 @@ export function UpdateTicketModal({ open, onClose, sessionId, onPosted }: Props)
|
|||||||
{/* Left panel - Content editor */}
|
{/* Left panel - Content editor */}
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<p className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground">
|
<p className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b]">
|
||||||
Note Content
|
Note Content
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleCopyContent}
|
onClick={handleCopyContent}
|
||||||
className="inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs text-muted-foreground hover:text-foreground transition-colors"
|
className="inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs text-[#848b9b] hover:text-[#e2e5eb] transition-colors"
|
||||||
title="Copy content"
|
title="Copy content"
|
||||||
>
|
>
|
||||||
<Copy className="h-3 w-3" />
|
<Copy className="h-3 w-3" />
|
||||||
@@ -214,7 +214,7 @@ export function UpdateTicketModal({ open, onClose, sessionId, onPosted }: Props)
|
|||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
)}
|
)}
|
||||||
<span className="text-muted-foreground">
|
<span className="text-[#848b9b]">
|
||||||
{content.length.toLocaleString()} characters
|
{content.length.toLocaleString()} characters
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -223,15 +223,15 @@ export function UpdateTicketModal({ open, onClose, sessionId, onPosted }: Props)
|
|||||||
{/* Right panel - Controls */}
|
{/* Right panel - Controls */}
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* Ticket info summary */}
|
{/* Ticket info summary */}
|
||||||
<div className="glass-card-static rounded-lg border border-border p-3">
|
<div className="card-flat rounded-lg border border-[#1e2130] p-3">
|
||||||
<p className="text-sm font-medium text-foreground">
|
<p className="text-sm font-medium text-[#e2e5eb]">
|
||||||
CW #{preview.ticket.id}
|
CW #{preview.ticket.id}
|
||||||
{preview.ticket.summary && (
|
{preview.ticket.summary && (
|
||||||
<span className="text-muted-foreground"> — {preview.ticket.summary}</span>
|
<span className="text-[#848b9b]"> — {preview.ticket.summary}</span>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
{(preview.ticket.company_name || preview.ticket.board_name) && (
|
{(preview.ticket.company_name || preview.ticket.board_name) && (
|
||||||
<p className="mt-1 text-xs text-muted-foreground">
|
<p className="mt-1 text-xs text-[#848b9b]">
|
||||||
{[preview.ticket.company_name, preview.ticket.board_name].filter(Boolean).join(' / ')}
|
{[preview.ticket.company_name, preview.ticket.board_name].filter(Boolean).join(' / ')}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -239,7 +239,7 @@ export function UpdateTicketModal({ open, onClose, sessionId, onPosted }: Props)
|
|||||||
|
|
||||||
{/* Note Type */}
|
{/* Note Type */}
|
||||||
<div>
|
<div>
|
||||||
<p className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground mb-3">
|
<p className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b] mb-3">
|
||||||
Note Type
|
Note Type
|
||||||
</p>
|
</p>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -250,7 +250,7 @@ export function UpdateTicketModal({ open, onClose, sessionId, onPosted }: Props)
|
|||||||
'flex cursor-pointer items-start gap-3 rounded-lg border px-3 py-2.5 transition-colors',
|
'flex cursor-pointer items-start gap-3 rounded-lg border px-3 py-2.5 transition-colors',
|
||||||
noteType === opt.value
|
noteType === opt.value
|
||||||
? 'border-primary/30 bg-primary/5'
|
? 'border-primary/30 bg-primary/5'
|
||||||
: 'border-border hover:border-[rgba(255,255,255,0.12)]'
|
: 'border-[#1e2130] hover:border-[rgba(255,255,255,0.12)]'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -262,8 +262,8 @@ export function UpdateTicketModal({ open, onClose, sessionId, onPosted }: Props)
|
|||||||
className="mt-0.5 accent-cyan-400"
|
className="mt-0.5 accent-cyan-400"
|
||||||
/>
|
/>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<span className="text-sm font-medium text-foreground">{opt.label}</span>
|
<span className="text-sm font-medium text-[#e2e5eb]">{opt.label}</span>
|
||||||
<p className="text-xs text-muted-foreground">{opt.description}</p>
|
<p className="text-xs text-[#848b9b]">{opt.description}</p>
|
||||||
{opt.warning && noteType === opt.value && (
|
{opt.warning && noteType === opt.value && (
|
||||||
<p className="mt-1 flex items-center gap-1 text-xs text-amber-400">
|
<p className="mt-1 flex items-center gap-1 text-xs text-amber-400">
|
||||||
<AlertTriangle className="h-3 w-3 shrink-0" />
|
<AlertTriangle className="h-3 w-3 shrink-0" />
|
||||||
@@ -278,14 +278,14 @@ export function UpdateTicketModal({ open, onClose, sessionId, onPosted }: Props)
|
|||||||
|
|
||||||
{/* Ticket Status */}
|
{/* Ticket Status */}
|
||||||
<div>
|
<div>
|
||||||
<p className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground mb-2">
|
<p className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b] mb-2">
|
||||||
Ticket Status
|
Ticket Status
|
||||||
</p>
|
</p>
|
||||||
<select
|
<select
|
||||||
value={selectedStatusId ?? ''}
|
value={selectedStatusId ?? ''}
|
||||||
onChange={(e) => setSelectedStatusId(e.target.value ? Number(e.target.value) : null)}
|
onChange={(e) => setSelectedStatusId(e.target.value ? Number(e.target.value) : null)}
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full rounded-md border border-border bg-card px-3 py-2 text-sm text-foreground',
|
'w-full rounded-md border border-[#1e2130] bg-[#14161d] px-3 py-2 text-sm text-[#e2e5eb]',
|
||||||
'focus:border-primary/30 focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
'focus:border-primary/30 focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -301,7 +301,7 @@ export function UpdateTicketModal({ open, onClose, sessionId, onPosted }: Props)
|
|||||||
|
|
||||||
{/* Previous posts */}
|
{/* Previous posts */}
|
||||||
{preview.previous_posts > 0 && (
|
{preview.previous_posts > 0 && (
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-[#848b9b]">
|
||||||
This session has been posted {preview.previous_posts} time{preview.previous_posts > 1 ? 's' : ''} before.
|
This session has been posted {preview.previous_posts} time{preview.previous_posts > 1 ? 's' : ''} before.
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -23,14 +23,14 @@ export function VariablePromptModal({ prompt, onSubmit, onCancel }: VariableProm
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-xs">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-xs">
|
||||||
<div className="bg-card border border-border w-full max-w-md rounded-2xl p-6 shadow-lg">
|
<div className="bg-[#14161d] border border-[#1e2130] w-full max-w-md rounded-lg p-6 shadow-lg">
|
||||||
<h2 className="mb-1 text-lg font-semibold text-foreground">Input Required</h2>
|
<h2 className="mb-1 text-lg font-semibold text-[#e2e5eb]">Input Required</h2>
|
||||||
<p className="mb-4 text-sm text-muted-foreground">
|
<p className="mb-4 text-sm text-[#848b9b]">
|
||||||
This step requires you to provide a value.
|
This step requires you to provide a value.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<label className="mb-2 block text-sm font-medium text-muted-foreground">
|
<label className="mb-2 block text-sm font-medium text-[#848b9b]">
|
||||||
{prompt}
|
{prompt}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -40,8 +40,8 @@ export function VariablePromptModal({ prompt, onSubmit, onCancel }: VariableProm
|
|||||||
placeholder="Enter value..."
|
placeholder="Enter value..."
|
||||||
autoFocus
|
autoFocus
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full rounded-lg border border-border bg-card px-3 py-2 text-sm text-foreground',
|
'w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-3 py-2 text-sm text-[#e2e5eb]',
|
||||||
'placeholder:text-muted-foreground focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
'placeholder:text-[#848b9b] focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user