style(题目): 题目页照设计稿「机房(方案 B)」重排——顶满的两栏、带底色的上下文条、下划线页签、新的结果和题面样式
Deploy / deploy (push) Canceled after 0s
Deploy / deploy (push) Canceled after 0s
原来实施时只照了设计文档,没对照设计稿,一路套 Naive 现成的分段页签、提示框、单选组, 功能对了、样子差很多。这次逐块对着设计稿的画板改: - 两栏顶满内容区,中间一条 1px 分隔线;上下文条、页签行、工具栏下面各一道分隔线 - 上下文条:课堂浅绿、题单浅蓝、比赛浅黄三种底色;‹ › 是不带边框的箭头;比赛的题号是方角、 做错的是红色 ✕;手机上不摆一排题号,写「这节课 做完 2/5 · 这是第 3 道」配 44px 的箭头 - 「题目 / 结果」是下划线页签,右边「统计 / 点评 / 我的提交」是胶囊按钮 - 抽屉盖住整个左栏(连上下文条、页签行),顶上有自己的「我的提交 / 统计 / 点评」页签,Esc 能关 - 结果页签:三个分段是胶囊,选中的深色实心、带时间(「提交结果 · 10:42」);标题是圆形图标 + 大字 + 灰字(「答案错误 在例子 1 上就错了」),不再套整块彩色提示框;答错的对比三栏并排、 只把不一样的那几个字标红;「题目要求的输出」是一行小字;「让 AI 分析我的代码」是描边按钮; 答对后的「下一题」是浅绿卡片里 44px 的大按钮 - 工具栏:语言、运行例子(描边)、提交(实心,就叫「提交」)靠左,求助、⋯ 推到最右; 交对之后「提交」变成绿色描边;协作条换成设计稿的深蓝 - 题面:标题下「简单 · 还没交过」,流程图过关的加「流程图 A 级」;代码要求压成一行; 小标题不带图标;输入、输出左右两栏;参考流程图是一行可以点开的条;例子表带「例子 1」和「复制」 - 去掉「限时 1 秒」:执行时间、内存对中职学生只会添迷惑(和设计稿不同,用户定的) - 我的提交:一整块带框的列表,结果用彩色文字;展开的代码先露 5 行;题单锁住的几次合成一行 - 错在隐藏测试点时「去自己输入」给的数跳过例子里出现过的 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
83b6b7a81a
commit
1fd9bf67c2
17 files changed
+1800
-706
No files matched your search
@@ -5,8 +5,9 @@ import type { RouteLocationRaw } from "vue-router"
|
||||
/**
|
||||
* 上下文条里的一排题号(课堂、比赛共用)。只放题号,题目名在鼠标停上去时给。
|
||||
*
|
||||
* 状态用图标区分,不只靠颜色:✓ 做完(实心绿)/ ! 做过没对(橙)/ 灰底 没做;当前题描边。
|
||||
* 一节课一般 5 道以内,一行放得下;多了(比赛、老师一次布置了一长串)就横向滚动,
|
||||
* 状态用图标区分,不只靠颜色:✓ 做完(实心绿)/ 做过没对(课堂是橙色 !,比赛是红色 ✕)/
|
||||
* 灰底 没做;当前题描边,做完了的当前题实心绿再套一圈。课堂是圆角胶囊、比赛是方角
|
||||
* (设计稿「上下文条与协作状态」)。一节课一般 5 道以内,一行放得下;多了就横向滚动,
|
||||
* 当前题保持在视野里。
|
||||
*/
|
||||
export interface ChipItem {
|
||||
@@ -19,17 +20,22 @@ export interface ChipItem {
|
||||
const props = defineProps<{
|
||||
items: ChipItem[]
|
||||
current: string
|
||||
variant: "lesson" | "contest"
|
||||
}>()
|
||||
|
||||
const theme = useThemeVars()
|
||||
/**
|
||||
* 「做完」的实心绿上用什么字色。暗色主题的成功色是浅薄荷绿,白字几乎看不见 ——
|
||||
* 和 Naive 自己的主按钮一样,暗色下换深色字
|
||||
*/
|
||||
/** 「做完」的实心绿上用什么字色:暗色主题的成功色是浅薄荷绿,白字几乎看不见 */
|
||||
const isDark = useDark()
|
||||
const doneText = computed(() => (isDark.value ? "rgba(0, 0, 0, 0.85)" : "#fff"))
|
||||
|
||||
const STATUS_TEXT = { done: "做完了", tried: "做过,还没对", none: "还没做" } as const
|
||||
const STATUS_TEXT = computed(
|
||||
() =>
|
||||
({
|
||||
done: "做完了",
|
||||
tried: props.variant === "contest" ? "交过,还没对" : "做过,还没对",
|
||||
none: "还没做",
|
||||
}) as const,
|
||||
)
|
||||
|
||||
const isCurrent = (item: ChipItem) => item.displayId.toLowerCase() === props.current.toLowerCase()
|
||||
|
||||
@@ -49,7 +55,8 @@ watch(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="scroller" class="chips">
|
||||
<!-- 类名带前缀:父组件(ContextBar)的 .lesson / .contest 会作用到子组件根元素上 -->
|
||||
<div ref="scroller" class="chips" :class="`chips-${variant}`">
|
||||
<n-tooltip v-for="item in items" :key="item.displayId" :delay="300">
|
||||
<template #trigger>
|
||||
<router-link
|
||||
@@ -59,9 +66,48 @@ watch(
|
||||
:aria-label="`${item.displayId} ${item.title}(${STATUS_TEXT[item.status]})`"
|
||||
:aria-current="isCurrent(item) ? 'page' : undefined"
|
||||
>
|
||||
<!-- 用字符不用图标:图标是从 Iconify 源现拉的,拉不到时状态就只剩颜色 -->
|
||||
<span v-if="item.status === 'done'" aria-hidden="true">✓</span>
|
||||
<span v-else-if="item.status === 'tried'" aria-hidden="true">!</span>
|
||||
<!-- 内嵌 SVG,不走 Iconify:图标源拉不到时状态就只剩颜色了 -->
|
||||
<svg
|
||||
v-if="item.status === 'done'"
|
||||
width="11"
|
||||
height="11"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M5 12l5 5 9-10" />
|
||||
</svg>
|
||||
<svg
|
||||
v-else-if="item.status === 'tried' && variant === 'contest'"
|
||||
width="11"
|
||||
height="11"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M6 6l12 12M18 6L6 18" />
|
||||
</svg>
|
||||
<svg
|
||||
v-else-if="item.status === 'tried'"
|
||||
width="11"
|
||||
height="11"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M12 7v6" />
|
||||
<path d="M12 17h.01" />
|
||||
</svg>
|
||||
<span>{{ item.displayId }}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
@@ -78,9 +124,13 @@ watch(
|
||||
flex: 0 1 auto;
|
||||
min-width: 0;
|
||||
overflow-x: auto;
|
||||
scrollbar-width: thin;
|
||||
/* 描边的外圈别被裁掉 */
|
||||
padding: 3px 2px;
|
||||
scrollbar-width: none;
|
||||
/* 当前题外面那一圈别被裁掉 */
|
||||
padding: 4px 3px;
|
||||
}
|
||||
|
||||
.chips::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.chip {
|
||||
@@ -89,14 +139,19 @@ watch(
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
height: 26px;
|
||||
padding: 0 9px;
|
||||
box-sizing: border-box;
|
||||
padding: 0 8px;
|
||||
border-radius: 13px;
|
||||
border: 1.5px solid transparent;
|
||||
font-size: 13px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
text-decoration: none;
|
||||
color: v-bind("theme.textColor2");
|
||||
background-color: rgba(128, 128, 128, 0.12);
|
||||
border: 1px solid transparent;
|
||||
background-color: rgba(128, 128, 128, 0.14);
|
||||
}
|
||||
|
||||
.chips-contest .chip {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.chip.done {
|
||||
@@ -105,23 +160,36 @@ watch(
|
||||
}
|
||||
|
||||
.chip.tried {
|
||||
color: v-bind("theme.warningColor");
|
||||
color: v-bind("theme.warningColorPressed");
|
||||
background-color: rgba(240, 160, 32, 0.12);
|
||||
border-color: rgba(240, 160, 32, 0.5);
|
||||
border: 1px solid rgba(240, 160, 32, 0.45);
|
||||
}
|
||||
|
||||
.chip.current {
|
||||
border-color: v-bind("theme.primaryColor");
|
||||
box-shadow: 0 0 0 1px v-bind("theme.primaryColor");
|
||||
font-weight: 600;
|
||||
.chips-contest .chip.tried {
|
||||
color: v-bind("theme.errorColorPressed");
|
||||
background-color: rgba(208, 48, 80, 0.12);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.chip.current:not(.done) {
|
||||
color: v-bind("theme.primaryColorPressed");
|
||||
background-color: v-bind("theme.cardColor");
|
||||
border: 1.5px solid v-bind("theme.primaryColor");
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.chips-contest .chip.current:not(.done) {
|
||||
color: v-bind("theme.warningColorPressed");
|
||||
border-color: v-bind("theme.warningColor");
|
||||
}
|
||||
|
||||
/* 当前题做完了:实心绿,外面再套一圈(中间隔一道底色) */
|
||||
.chip.done.current {
|
||||
border-color: v-bind("theme.successColor");
|
||||
font-weight: 700;
|
||||
border-color: v-bind("theme.primaryColorPressed");
|
||||
box-shadow:
|
||||
0 0 0 2px v-bind("theme.bodyColor"),
|
||||
0 0 0 3px v-bind("theme.successColor");
|
||||
0 0 0 2px v-bind("theme.cardColor"),
|
||||
0 0 0 3.5px v-bind("theme.primaryColorPressed");
|
||||
}
|
||||
|
||||
.chip:hover {
|
||||
|
||||
Reference in new issue
Block a user