feat(release): bump version to 0.1.2

## 详细信息
- 升级项目版本号到 0.1.2
- 增强刷课稳定性(失败重试、心跳检测、状态自动纠正)
- 优化账号页与工作台紧凑布局,增加已学/未学区分与记录筛选
- 新增首次进入更新检查、更新日志弹窗与在线下载/回退 Release 跳转
This commit is contained in:
2026-04-02 22:33:04 +08:00
parent a061123e36
commit 58555c5043
12 changed files with 1569 additions and 413 deletions

View File

@@ -29,21 +29,23 @@ const AccountSidebar = (props: AccountSidebarProps) => {
return (
<section
class="flex min-h-0 flex-col overflow-hidden rounded-[28px] border border-white/80 bg-white/85 shadow-[0_18px_50px_-28px_rgba(15,23,42,0.3)] xl:shrink-0"
class="flex min-h-0 w-full flex-col overflow-hidden rounded-[24px] border border-white/80 bg-white/85 shadow-[0_14px_40px_-26px_rgba(15,23,42,0.28)] xl:shrink-0"
style={{
width: `${props.sidebarWidth}px`,
"min-width": `${props.sidebarWidth}px`,
width: `min(100%, ${props.sidebarWidth}px)`,
"min-width": "0px",
}}
>
<div class="flex items-center justify-between border-b border-zinc-200/80 px-5 py-4">
<div class="flex flex-col gap-2.5 border-b border-zinc-200/80 px-4 py-3 sm:flex-row sm:items-start sm:justify-between">
<div>
<p class="text-lg font-semibold text-zinc-900"></p>
<p class="mt-1 text-sm text-zinc-500"></p>
<p class="text-base font-semibold text-zinc-900"></p>
<p class="mt-1 text-xs text-zinc-500 sm:text-sm">
</p>
</div>
<button
type="button"
class="rounded-xl border border-zinc-200 bg-white px-3 py-2 text-sm text-zinc-700 transition hover:bg-zinc-100 disabled:cursor-not-allowed disabled:opacity-60"
class="self-start rounded-xl border border-zinc-200 bg-white px-3 py-1.5 text-xs text-zinc-700 transition hover:bg-zinc-100 disabled:cursor-not-allowed disabled:opacity-60 sm:self-auto sm:text-sm"
disabled={!props.selectedAccountId || props.isRefreshingAccount}
onClick={props.onRefreshAccount}
>
@@ -54,8 +56,8 @@ const AccountSidebar = (props: AccountSidebarProps) => {
<div
class={
compact()
? "flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto p-3"
: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-4"
? "flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto p-2.5"
: "flex min-h-0 flex-1 flex-col gap-2.5 overflow-y-auto p-3"
}
>
<For each={props.accounts}>
@@ -77,17 +79,19 @@ const AccountSidebar = (props: AccountSidebarProps) => {
const courseTypeLabel = selected()
? `当前筛选:${currentCourseLabel}`
: `登录类型:${statusLabel}`;
const badgeTypeLabel = selected() ? currentCourseLabel : statusLabel;
const badgeCountLabel = `${account.courses.length}`;
return (
<div
class={
selected()
? compact()
? "rounded-[22px] border border-cyan-300 bg-[linear-gradient(145deg,rgba(236,254,255,0.95),rgba(240,253,244,0.95))] px-3 py-3 shadow-sm"
: "rounded-3xl border border-cyan-300 bg-[linear-gradient(145deg,rgba(236,254,255,0.95),rgba(240,253,244,0.95))] px-4 py-4 shadow-sm"
? "rounded-[20px] border border-cyan-300 bg-[linear-gradient(145deg,rgba(236,254,255,0.95),rgba(240,253,244,0.95))] px-3 py-2.5 shadow-sm"
: "rounded-[22px] border border-cyan-300 bg-[linear-gradient(145deg,rgba(236,254,255,0.95),rgba(240,253,244,0.95))] px-3.5 py-3 shadow-sm"
: compact()
? "rounded-[22px] border border-zinc-200 bg-[linear-gradient(180deg,rgba(250,250,250,0.9),rgba(255,255,255,0.95))] px-3 py-3 shadow-sm transition hover:border-cyan-200 hover:bg-white"
: "rounded-3xl border border-zinc-200 bg-[linear-gradient(180deg,rgba(250,250,250,0.9),rgba(255,255,255,0.95))] px-4 py-4 shadow-sm transition hover:border-cyan-200 hover:bg-white"
? "rounded-[20px] border border-zinc-200 bg-[linear-gradient(180deg,rgba(250,250,250,0.9),rgba(255,255,255,0.95))] px-3 py-2.5 shadow-sm transition hover:border-cyan-200 hover:bg-white"
: "rounded-[22px] border border-zinc-200 bg-[linear-gradient(180deg,rgba(250,250,250,0.9),rgba(255,255,255,0.95))] px-3.5 py-3 shadow-sm transition hover:border-cyan-200 hover:bg-white"
}
>
<div class="flex items-start justify-between gap-3">
@@ -101,15 +105,23 @@ const AccountSidebar = (props: AccountSidebarProps) => {
<p
class={
compact()
? "truncate text-base font-semibold text-zinc-900"
: "truncate text-lg font-semibold text-zinc-900"
? "truncate text-[15px] font-semibold text-zinc-900"
: "truncate text-base font-semibold text-zinc-900"
}
>
{account.user.name} + {platformLabel}
</p>
<p class="mt-1 text-sm text-zinc-500">
<p class="mt-1 text-xs text-zinc-500 sm:text-sm">
{account.user.id}
</p>
<div class="mt-1.5 flex flex-wrap items-center gap-1">
<span class="rounded-full border border-cyan-200 bg-cyan-50 px-2 py-0.5 text-[11px] text-cyan-700">
{badgeTypeLabel}
</span>
<span class="rounded-full border border-zinc-200 bg-zinc-100 px-2 py-0.5 text-[11px] text-zinc-600">
{badgeCountLabel}
</span>
</div>
</div>
</div>
</button>
@@ -123,26 +135,26 @@ const AccountSidebar = (props: AccountSidebarProps) => {
</div>
<Show when={expanded()}>
<div class="mt-4 grid gap-2 border-t border-cyan-100 pt-4 text-sm text-zinc-600">
<div class="mt-2.5 grid gap-1 border-t border-cyan-100 pt-2.5 text-xs text-zinc-600 sm:grid-cols-2 sm:gap-1.5">
<p>{account.user.dept}</p>
<p>{account.user.class}</p>
<p>{account.user.gender}</p>
<p>{account.host}</p>
<p>{account.username || "-"}</p>
<p>{courseCountLabel}</p>
<p>{courseTypeLabel}</p>
<p class="sm:col-span-2">{courseTypeLabel}</p>
<div class="mt-2 flex gap-2">
<div class="mt-1.5 flex flex-wrap gap-1.5 sm:col-span-2">
<button
type="button"
class="rounded-xl border border-cyan-200 bg-white px-3 py-2 text-sm text-cyan-700 transition hover:bg-cyan-50"
class="rounded-xl border border-cyan-200 bg-white px-2.5 py-1 text-xs text-cyan-700 transition hover:bg-cyan-50"
onClick={() => props.onToggleExpand(account.id)}
>
</button>
<button
type="button"
class="rounded-xl border border-rose-200 bg-white px-3 py-2 text-sm text-rose-500 transition hover:bg-rose-50 disabled:cursor-not-allowed disabled:opacity-60"
class="rounded-xl border border-rose-200 bg-white px-2.5 py-1 text-xs text-rose-500 transition hover:bg-rose-50 disabled:cursor-not-allowed disabled:opacity-60"
disabled={props.loggingOutId === account.id}
onClick={(event) => {
event.stopPropagation();

View File

@@ -1,4 +1,11 @@
import { For, Show, createEffect, type JSX } from "solid-js";
import {
For,
Show,
createEffect,
createMemo,
createSignal,
type JSX,
} from "solid-js";
import type { CourseKind, RecordType } from "~/service/wk";
import type { AccountItem } from "~/store/account";
import type { CourseType } from "~/types/Course";
@@ -12,6 +19,7 @@ type CourseRecordTypeOption = {
label: string;
value: CourseKind;
};
type RecordFilter = "all" | "unlearned" | "learned";
interface CourseWorkspaceProps {
selectedAccount: AccountItem | null;
@@ -65,6 +73,7 @@ const stripTimestamp = (message: string) => {
const CourseWorkspace = (props: CourseWorkspaceProps) => {
let logContainerRef: HTMLDivElement | undefined;
const [recordFilter, setRecordFilter] = createSignal<RecordFilter>("all");
createEffect(() => {
props.studyLogs.length;
@@ -88,16 +97,44 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
});
const compact = () => props.densityMode === "compact";
const recordStats = createMemo(() => {
const learned = props.records.filter((record) => {
const stateText = props.renderRecordState(record.state) || "未知状态";
return stateText.includes("已学") || record.progress === "1.00";
}).length;
const total = props.records.length;
return {
total,
learned,
unlearned: Math.max(0, total - learned),
};
});
const filteredRecords = createMemo(() => {
if (recordFilter() === "all") {
return props.records;
}
return props.records.filter((record) => {
const stateText = props.renderRecordState(record.state) || "未知状态";
const learned = stateText.includes("已学") || record.progress === "1.00";
return recordFilter() === "learned" ? learned : !learned;
});
});
return (
<section class="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-[28px] border border-white/80 bg-white/85 shadow-[0_18px_50px_-28px_rgba(15,23,42,0.3)]">
<div class="flex items-center justify-between border-b border-zinc-200/80 px-5 py-4">
<section class="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-[22px] border border-white/80 bg-white/85 shadow-[0_12px_34px_-24px_rgba(15,23,42,0.26)]">
<div class="flex flex-col gap-1.5 border-b border-zinc-200/80 px-3 py-2.5 sm:flex-row sm:items-center sm:justify-between">
<div>
<p class="text-lg font-semibold text-zinc-900"></p>
<p class="mt-1 text-sm text-zinc-500"></p>
<p class="text-[15px] font-semibold text-zinc-900 sm:text-base">
</p>
<p class="mt-0.5 text-xs text-zinc-500 sm:text-sm">
</p>
</div>
<Show when={props.selectedAccount}>
<div class="rounded-full bg-cyan-50 px-3 py-1 text-sm text-cyan-700">
<div class="rounded-full bg-cyan-50 px-2 py-0.5 text-xs text-cyan-700">
{props.selectedAccount?.user.name}
</div>
</Show>
@@ -114,19 +151,21 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
<div
class={
compact()
? "grid min-h-0 flex-1 gap-3 p-3 xl:grid-cols-[320px_minmax(0,1fr)]"
: "grid min-h-0 flex-1 gap-4 p-4 xl:grid-cols-[340px_minmax(0,1fr)]"
? "grid min-h-0 flex-1 gap-1.5 p-1.5 lg:grid-cols-[280px_minmax(0,1fr)]"
: "grid min-h-0 flex-1 gap-2 p-2 lg:grid-cols-[300px_minmax(0,1fr)]"
}
>
<div class="flex min-h-0 flex-col overflow-hidden rounded-3xl border border-zinc-200 bg-[linear-gradient(180deg,rgba(248,250,252,0.9),rgba(255,255,255,0.95))]">
<div class="flex flex-wrap items-center justify-between gap-3 border-b border-zinc-200 px-4 py-3">
<div class="border-b border-zinc-200 px-4 py-3">
<p class="text-sm font-semibold text-zinc-800"></p>
<div class="flex min-h-0 flex-col overflow-hidden rounded-[18px] border border-zinc-200 bg-[linear-gradient(180deg,rgba(248,250,252,0.9),rgba(255,255,255,0.95))]">
<div class="flex flex-wrap items-center justify-between gap-1.5 border-b border-zinc-200 px-2.5 py-2">
<div>
<p class="text-xs font-semibold text-zinc-800 sm:text-sm">
</p>
<p class="mt-1 text-xs text-zinc-500"></p>
</div>
<div class="flex flex-wrap items-center gap-2">
<select
class="rounded-xl border border-zinc-200 bg-white px-3 py-2 text-sm transition outline-none focus:border-cyan-400"
class="rounded-lg border border-zinc-200 bg-white px-2 py-1 text-xs transition outline-none focus:border-cyan-400"
value={props.courseKind}
onChange={(event) =>
props.onChangeCourseRecordType(
@@ -140,7 +179,7 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
</select>
<button
type="button"
class="rounded-xl border border-zinc-200 bg-white px-3 py-2 text-sm text-zinc-700 transition hover:bg-zinc-100 disabled:cursor-not-allowed disabled:opacity-60"
class="rounded-lg border border-zinc-200 bg-white px-2 py-1 text-xs text-zinc-700 transition hover:bg-zinc-100 disabled:cursor-not-allowed disabled:opacity-60"
disabled={props.isRefreshingCourseRecords}
onClick={props.onRefreshCourseRecords}
>
@@ -149,13 +188,7 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
</div>
</div>
<div
class={
compact()
? "flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto p-2.5"
: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-3"
}
>
<div class={compact() ? "flex min-h-0 flex-1 flex-col gap-1 overflow-y-auto p-1.5" : "flex min-h-0 flex-1 flex-col gap-1.5 overflow-y-auto p-2"}>
<Show when={props.selectedCourseList.length === 0}>
<EmptyState>
{props.currentCourseKindLabel}
@@ -173,18 +206,18 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
class={
selected()
? compact()
? "rounded-[20px] border border-cyan-300 bg-[linear-gradient(145deg,rgba(236,254,255,0.95),rgba(240,253,244,0.95))] px-3 py-3 text-left shadow-sm"
: "rounded-[22px] border border-cyan-300 bg-[linear-gradient(145deg,rgba(236,254,255,0.95),rgba(240,253,244,0.95))] px-4 py-4 text-left shadow-sm"
? "rounded-[16px] border border-cyan-300 bg-[linear-gradient(145deg,rgba(236,254,255,0.95),rgba(240,253,244,0.95))] px-2 py-2 text-left shadow-sm"
: "rounded-[18px] border border-cyan-300 bg-[linear-gradient(145deg,rgba(236,254,255,0.95),rgba(240,253,244,0.95))] px-2.5 py-2.5 text-left shadow-sm"
: compact()
? "rounded-[20px] border border-zinc-200 bg-white px-3 py-3 text-left shadow-sm transition hover:border-cyan-200 hover:bg-cyan-50/30"
: "rounded-[22px] border border-zinc-200 bg-white px-4 py-4 text-left shadow-sm transition hover:border-cyan-200 hover:bg-cyan-50/30"
? "rounded-[16px] border border-zinc-200 bg-white px-2 py-2 text-left shadow-sm transition hover:border-cyan-200 hover:bg-cyan-50/30"
: "rounded-[18px] border border-zinc-200 bg-white px-2.5 py-2.5 text-left shadow-sm transition hover:border-cyan-200 hover:bg-cyan-50/30"
}
onClick={() => props.onSelectCourse(course.id)}
>
<p class="truncate text-base font-semibold text-zinc-900">
<p class="truncate text-sm font-semibold text-zinc-900">
{course.name}
</p>
<div class="mt-3 grid gap-1 text-sm text-zinc-600">
<div class="mt-1 grid gap-0.5 text-xs text-zinc-600">
<p>{course.id}</p>
<p>{course.teacher}</p>
<p>{course.progress}</p>
@@ -199,14 +232,16 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
<div
class={
compact()
? "grid min-h-0 gap-3 xl:grid-rows-[minmax(0,1fr)_240px]"
: "grid min-h-0 gap-4 xl:grid-rows-[minmax(0,1fr)_260px]"
? "grid min-h-0 gap-1.5 grid-rows-[minmax(0,1fr)_176px] xl:grid-rows-[minmax(0,1fr)_188px]"
: "grid min-h-0 gap-2 grid-rows-[minmax(0,1fr)_188px] xl:grid-rows-[minmax(0,1fr)_208px]"
}
>
<div class="flex min-h-0 flex-col overflow-hidden rounded-3xl border border-zinc-200 bg-[linear-gradient(180deg,rgba(248,250,252,0.9),rgba(255,255,255,0.95))]">
<div class="flex flex-wrap items-center justify-between gap-3 border-b border-zinc-200 px-4 py-3">
<div class="flex min-h-0 flex-col overflow-hidden rounded-[18px] border border-zinc-200 bg-[linear-gradient(180deg,rgba(248,250,252,0.9),rgba(255,255,255,0.95))]">
<div class="flex flex-wrap items-center justify-between gap-1.5 border-b border-zinc-200 px-2.5 py-2">
<div>
<p class="text-sm font-semibold text-zinc-800"></p>
<p class="text-xs font-semibold text-zinc-800 sm:text-sm">
</p>
<p class="mt-1 text-xs text-zinc-500">
{props.selectedCourse
? props.selectedCourse.name
@@ -221,10 +256,10 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
</Show>
</div>
<div class="flex flex-wrap items-center gap-2">
<div class="flex flex-wrap items-center gap-1.5">
<button
type="button"
class="rounded-xl border border-zinc-200 bg-white px-3 py-2 text-sm text-zinc-700 transition hover:bg-zinc-100 disabled:cursor-not-allowed disabled:opacity-60"
class="rounded-lg border border-zinc-200 bg-white px-2 py-1 text-xs text-zinc-700 transition hover:bg-zinc-100 disabled:cursor-not-allowed disabled:opacity-60"
disabled={
!props.selectedCourse || props.isRefreshingRecords
}
@@ -234,7 +269,7 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
</button>
<select
class="rounded-xl border border-zinc-200 bg-white px-3 py-2 text-sm transition outline-none focus:border-cyan-400"
class="rounded-lg border border-zinc-200 bg-white px-2 py-1 text-xs transition outline-none focus:border-cyan-400"
value={props.recordType}
onChange={(event) =>
props.onChangeRecordType(
@@ -252,7 +287,7 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
<Show when={props.recordType === ""}>
<button
type="button"
class="rounded-xl border border-cyan-200 bg-cyan-50 px-3 py-2 text-sm text-cyan-700 transition hover:bg-cyan-100"
class="rounded-lg border border-cyan-200 bg-cyan-50 px-2 py-1 text-xs text-cyan-700 transition hover:bg-cyan-100"
onClick={
props.isRunningStudy
? props.onStopStudy
@@ -264,12 +299,40 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
</Show>
</div>
</div>
<div class="flex flex-wrap items-center justify-between gap-1.5 border-b border-zinc-200/70 px-2.5 py-1.5">
<div class="flex flex-wrap items-center gap-1.5 text-xs">
<button
type="button"
class={recordFilter() === "all" ? "rounded-full border border-zinc-200 bg-zinc-100 px-2.5 py-0.5 font-medium text-zinc-700" : "rounded-full border border-zinc-200 bg-white px-2.5 py-0.5 text-zinc-600 transition hover:bg-zinc-100"}
onClick={() => setRecordFilter("all")}
>
{recordStats().total}
</button>
<button
type="button"
class={recordFilter() === "unlearned" ? "rounded-full border border-amber-200 bg-amber-100 px-2.5 py-0.5 font-medium text-amber-700" : "rounded-full border border-amber-200 bg-white px-2.5 py-0.5 text-amber-700 transition hover:bg-amber-50"}
onClick={() => setRecordFilter("unlearned")}
>
{recordStats().unlearned}
</button>
<button
type="button"
class={recordFilter() === "learned" ? "rounded-full border border-emerald-200 bg-emerald-100 px-2.5 py-0.5 font-medium text-emerald-700" : "rounded-full border border-emerald-200 bg-white px-2.5 py-0.5 text-emerald-700 transition hover:bg-emerald-50"}
onClick={() => setRecordFilter("learned")}
>
{recordStats().learned}
</button>
</div>
<p class="text-xs text-zinc-500">
{recordFilter() === "all" ? "全部" : recordFilter() === "unlearned" ? "未学" : "已学"}
</p>
</div>
<div
class={
compact()
? "min-h-0 flex-1 overflow-y-auto p-2.5"
: "min-h-0 flex-1 overflow-y-auto p-3"
? "min-h-0 flex-1 overflow-y-auto p-1.5"
: "min-h-0 flex-1 overflow-y-auto p-2"
}
>
<Show when={props.recordsLoading}>
@@ -297,56 +360,78 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
!props.recordsLoading &&
!props.recordError &&
props.selectedCourse &&
props.records.length === 0
filteredRecords().length === 0
}
>
<EmptyState></EmptyState>
<EmptyState>
{props.records.length === 0
? "当前分类下没有记录。"
: "当前筛选下没有记录。"}
</EmptyState>
</Show>
<div class="flex flex-col gap-3">
<For each={props.records}>
{(record) => (
<div
class={
compact()
? "rounded-[20px] border border-zinc-200 bg-white px-3 py-3 shadow-sm"
: "rounded-[22px] border border-zinc-200 bg-white px-4 py-4 shadow-sm"
}
>
<div class="flex flex-wrap items-start justify-between gap-3">
<div class="min-w-0 flex-1">
<p class="truncate text-base font-semibold text-zinc-900">
{record.name}
</p>
<p class="mt-1 text-sm text-zinc-500">
ID{record.id} | {record.chapterId}
</p>
</div>
<span class="rounded-full bg-zinc-100 px-3 py-1 text-xs font-medium text-zinc-700">
{props.renderRecordState(record.state) ||
"未知状态"}
</span>
</div>
<div class={compact() ? "flex flex-col gap-1.5" : "flex flex-col gap-2"}>
<For each={filteredRecords()}>
{(record) => {
const stateText =
props.renderRecordState(record.state) || "未知状态";
const learned =
stateText.includes("已学") || record.progress === "1.00";
<div class="mt-4 grid gap-2 text-sm text-zinc-600 md:grid-cols-2 xl:grid-cols-3">
<p>{record.videoDuration}</p>
<p>{record.duration}</p>
<p>{record.progress}</p>
<p>{record.beginTime || "-"}</p>
<p>{record.finalTime || "-"}</p>
<p>{record.viewCount}</p>
return (
<div
class={
learned
? compact()
? "rounded-[16px] border border-emerald-200 bg-emerald-50/35 px-2 py-1.5 shadow-sm"
: "rounded-[18px] border border-emerald-200 bg-emerald-50/35 px-2.5 py-2.5 shadow-sm"
: compact()
? "rounded-[16px] border border-amber-200 bg-amber-50/35 px-2 py-1.5 shadow-sm"
: "rounded-[18px] border border-amber-200 bg-amber-50/35 px-2.5 py-2.5 shadow-sm"
}
>
<div class="flex flex-wrap items-start justify-between gap-2">
<div class="min-w-0 flex-1">
<p class="truncate text-sm font-semibold text-zinc-900">
{record.name}
</p>
<p class="mt-1 text-xs text-zinc-500">
ID{record.id} | {record.chapterId}
</p>
</div>
<span
class={
learned
? "rounded-full bg-emerald-100 px-3 py-1 text-xs font-medium text-emerald-700"
: "rounded-full bg-amber-100 px-3 py-1 text-xs font-medium text-amber-700"
}
>
{stateText}
</span>
</div>
<div class="mt-2 grid gap-1 text-xs text-zinc-600 md:grid-cols-2 xl:grid-cols-3">
<p>{record.videoDuration}</p>
<p>{record.duration}</p>
<p>{record.progress}</p>
<p>{record.beginTime || "-"}</p>
<p>{record.finalTime || "-"}</p>
<p>{record.viewCount}</p>
</div>
</div>
</div>
)}
);
}}
</For>
</div>
</div>
</div>
<div class="flex min-h-0 flex-col overflow-hidden rounded-3xl border border-zinc-200 bg-white">
<div class="flex items-center justify-between border-b border-zinc-200 px-4 py-3">
<div class="flex min-h-0 flex-col overflow-hidden rounded-[18px] border border-zinc-200 bg-white">
<div class="flex items-center justify-between border-b border-zinc-200 px-2.5 py-2">
<div>
<p class="text-sm font-semibold text-zinc-800"></p>
<p class="text-xs font-semibold text-zinc-800 sm:text-sm">
</p>
<p class="mt-1 text-xs text-zinc-500">
</p>
@@ -355,7 +440,7 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
<div class="flex items-center gap-2">
<button
type="button"
class="rounded-lg border border-zinc-200 px-3 py-1 text-xs text-zinc-700 transition hover:bg-zinc-100 disabled:cursor-not-allowed disabled:opacity-60"
class="rounded-lg border border-zinc-200 px-2 py-0.5 text-xs text-zinc-700 transition hover:bg-zinc-100 disabled:cursor-not-allowed disabled:opacity-60"
disabled={props.isRefreshingLogs}
onClick={props.onRefreshLogs}
>
@@ -363,7 +448,7 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
</button>
<button
type="button"
class="rounded-lg border border-zinc-200 px-3 py-1 text-xs text-zinc-700 transition hover:bg-zinc-100"
class="rounded-lg border border-zinc-200 px-2 py-0.5 text-xs text-zinc-700 transition hover:bg-zinc-100"
onClick={props.onClearLogs}
>
@@ -373,13 +458,13 @@ const CourseWorkspace = (props: CourseWorkspaceProps) => {
<div
ref={logContainerRef}
class="min-h-0 flex-1 overflow-y-auto bg-zinc-950 px-4 py-3 font-mono text-emerald-300"
class="min-h-0 flex-1 overflow-y-auto bg-zinc-950 px-2 py-1.5 font-mono text-emerald-300"
>
<Show
when={props.studyLogs.length > 0}
fallback={<p></p>}
>
<div class="space-y-2">
<div class="space-y-1">
<For each={props.studyLogs}>
{(log, index) => (
<p>