File size: 6,168 Bytes
65d68f5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | "use client";
import { ChevronRight, Flame, Plus, Sparkles } from "lucide-react";
import LiquidGlass from "liquid-glass-react";
import { cn } from "@/lib/utils";
import { studyFeatures } from "./workspaceData";
import type { StudyFeature, StudyProgress } from "./workspaceTypes";
const DAY_LABELS = ["M", "T", "W", "T", "F", "S", "S"];
type AIStudyAssistantPanelProps = {
className?: string;
activeFeatureId: string | null;
subject: string;
progress: StudyProgress;
onFeatureSelect: (feature: StudyFeature) => void;
onAddTask: () => void;
};
export function AIStudyAssistantPanel({
className,
activeFeatureId,
progress,
onFeatureSelect,
onAddTask,
}: AIStudyAssistantPanelProps) {
return (
<LiquidGlass
mode="standard"
blurAmount={20}
saturation={1.16}
elasticity={0.14}
displacementScale={0.03}
aberrationIntensity={0.007}
cornerRadius={20}
className={cn(
"flex h-full flex-col overflow-hidden border border-white/[0.07] bg-[#0B0B0C]",
className,
)}
>
{/* Header */}
<div className="flex items-center gap-2 border-b border-white/[0.06] px-4 py-3">
<Sparkles className="size-3.5 text-amber-400" strokeWidth={2} />
<h2 className="text-[11px] font-bold uppercase tracking-[0.14em] text-white/50">
Study guidance
</h2>
</div>
{/* Feature list */}
<div className="min-h-0 flex-1 overflow-y-auto px-2 py-2 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
{studyFeatures.map((feature) => {
const Icon = feature.icon;
const isActive = activeFeatureId === feature.id;
return (
<button
key={feature.id}
type="button"
onClick={() => onFeatureSelect(feature)}
className={cn(
"group flex w-full items-center gap-3 rounded-2xl px-3 py-2.5 text-left transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/20",
isActive
? "bg-white/[0.07]"
: "hover:bg-white/[0.045]",
)}
>
{/* Icon */}
<span
className={cn(
"grid size-9 shrink-0 place-items-center rounded-2xl",
isActive ? "bg-white/[0.10]" : "bg-white/[0.05]",
)}
>
<Icon
className={cn("size-4", isActive ? "text-white" : "text-white/50 group-hover:text-white/75")}
strokeWidth={1.9}
/>
</span>
{/* Text */}
<span className="min-w-0 flex-1">
<span
className={cn(
"block truncate text-[12.5px] font-semibold",
isActive ? "text-white" : "text-white/75 group-hover:text-white",
)}
>
{feature.title}
</span>
<span className="mt-0.5 block truncate text-[10.5px] text-white/38">
{feature.description}
</span>
</span>
{/* Chevron */}
<ChevronRight
className={cn(
"size-3.5 shrink-0 transition-transform",
isActive ? "text-white/60" : "text-white/20 group-hover:translate-x-0.5 group-hover:text-white/40",
)}
strokeWidth={2}
/>
</button>
);
})}
</div>
{/* Progress Overview */}
<div className="border-t border-white/[0.06] px-4 py-3">
<p className="mb-3 text-[10px] font-bold uppercase tracking-[0.14em] text-white/35">
Progress Overview
</p>
{/* Streak */}
<div className="mb-3 flex items-center gap-2">
<Flame className="size-3.5 text-orange-400" strokeWidth={2} />
<span className="text-[12px] font-bold text-white/80">{progress.streakDays} days streak</span>
</div>
{/* Week dots */}
<div className="mb-3 flex items-center gap-1.5">
{DAY_LABELS.map((label, idx) => {
const status = progress.weekDays[idx];
return (
<div key={`${label}-${idx}`} className="flex flex-1 flex-col items-center gap-1">
<div
className={cn(
"size-5 rounded-full border transition",
status === "done"
? "border-emerald-400/60 bg-emerald-500/25 shadow-[0_0_8px_rgba(52,211,153,0.3)]"
: status === "partial"
? "border-amber-400/50 bg-amber-500/15"
: status === "today"
? "border-white/30 bg-white/10"
: "border-white/10 bg-white/[0.03]",
)}
/>
<span className="text-[9px] font-semibold text-white/30">{label}</span>
</div>
);
})}
</div>
{/* Today's goal */}
<div className="mb-2 flex items-center justify-between">
<span className="text-[11.5px] font-semibold text-white/55">Today's Goal</span>
<span className="text-[11.5px] font-bold text-white/75">
{progress.todayCompleted}/{progress.todayTotal} tasks
</span>
</div>
<div className="mb-3 h-1.5 overflow-hidden rounded-full bg-white/[0.06]">
<div
className="h-full rounded-full bg-white/70 transition-all"
style={{ width: `${Math.round((progress.todayCompleted / Math.max(progress.todayTotal, 1)) * 100)}%` }}
/>
</div>
{/* Add task */}
<button
type="button"
onClick={onAddTask}
className="flex w-full items-center justify-center gap-1.5 rounded-xl bg-white py-2 text-[12px] font-bold text-black transition hover:bg-white/90"
>
<Plus className="size-3.5" strokeWidth={2.5} />
Add New Task
</button>
</div>
</LiquidGlass>
);
}
|