feat: remove cover page

This commit is contained in:
2026-06-16 07:14:39 -06:00
parent 085f70bd64
commit 7b95324649
15 changed files with 261 additions and 171 deletions

View File

@@ -0,0 +1,27 @@
import { mount } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import { createEmptyTeachingDesign } from '../domain/teachingDesign'
import A4Workspace from './A4Workspace.vue'
describe('A4Workspace', () => {
it('renders a selected lesson without cover state', () => {
const design = createEmptyTeachingDesign('1.md')
design.topic = 'CSS 弹性布局'
const wrapper = mount(A4Workspace, {
props: { selectedDesign: design },
})
expect(Object.keys(wrapper.props()).sort()).toEqual(['selectedDesign'])
expect(wrapper.find('.cover-page').exists()).toBe(false)
expect(wrapper.find('.teaching-design-page').exists()).toBe(true)
})
it('renders no page when no lesson is selected', () => {
const wrapper = mount(A4Workspace, {
props: { selectedDesign: null },
})
expect(wrapper.find('.page').exists()).toBe(false)
})
})

View File

@@ -1,16 +1,12 @@
<script setup lang="ts">
import type { BookCover, TeachingDesign } from '../domain/teachingDesign'
import CoverPage from './CoverPage.vue'
import type { TeachingDesign } from '../domain/teachingDesign'
import TeachingDesignPage from './TeachingDesignPage.vue'
defineProps<{
cover: BookCover
selectedId: string
selectedDesign: TeachingDesign | null
}>()
const emit = defineEmits<{
'update:cover': [patch: Partial<BookCover>]
'update:design': [design: TeachingDesign]
}>()
</script>
@@ -18,16 +14,8 @@ const emit = defineEmits<{
<template>
<div class="a4-workspace">
<div class="a4-paper">
<CoverPage
v-if="selectedId === 'cover'"
:course-name="cover.courseName"
:teacher-name="cover.teacherName"
:editable="true"
@update:course-name="emit('update:cover', { courseName: $event })"
@update:teacher-name="emit('update:cover', { teacherName: $event })"
/>
<TeachingDesignPage
v-else-if="selectedDesign"
v-if="selectedDesign"
:design="selectedDesign"
:editable="true"
@update:design="emit('update:design', $event)"

View File

@@ -1,40 +0,0 @@
<script setup lang="ts">
import EditableText from './EditableText.vue'
defineProps<{
courseName: string
teacherName: string
editable: boolean
}>()
defineEmits<{
'update:courseName': [value: string]
'update:teacherName': [value: string]
}>()
</script>
<template>
<section class="page cover-page">
<h1 class="cover-title">教学设计</h1>
<div class="cover-field">
<span class="cover-field-label">课程名称</span>
<EditableText
class="cover-field-value"
:model-value="courseName"
label="课程名称"
:editable="editable"
@update:model-value="$emit('update:courseName', $event)"
/>
</div>
<div class="cover-field">
<span class="cover-field-label">教师姓名</span>
<EditableText
class="cover-field-value"
:model-value="teacherName"
label="教师姓名"
:editable="editable"
@update:model-value="$emit('update:teacherName', $event)"
/>
</div>
</section>
</template>

View File

@@ -7,7 +7,7 @@ describe('LessonSidebar', () => {
it('emits a move when one lesson is dropped on another', async () => {
const designs = [createEmptyTeachingDesign('1.md'), createEmptyTeachingDesign('2.md')]
const wrapper = mount(LessonSidebar, {
props: { designs, selectedId: designs[0]?.id ?? 'cover' },
props: { designs, selectedId: designs[0]?.id ?? null },
})
await wrapper.get('[data-index="0"]').trigger('dragstart')
@@ -15,4 +15,14 @@ describe('LessonSidebar', () => {
expect(wrapper.emitted('move')?.[0]).toEqual([0, 1])
})
it('does not render a cover navigation item', () => {
const designs = [createEmptyTeachingDesign('1.md')]
const wrapper = mount(LessonSidebar, {
props: { designs, selectedId: null },
})
expect(wrapper.text()).not.toContain('封面')
expect(wrapper.find('.lesson-sidebar-cover').exists()).toBe(false)
})
})

View File

@@ -4,11 +4,11 @@ import type { DesignId, TeachingDesign } from '../domain/teachingDesign'
defineProps<{
designs: TeachingDesign[]
selectedId: 'cover' | DesignId
selectedId: DesignId | null
}>()
const emit = defineEmits<{
select: [id: 'cover' | DesignId]
select: [id: DesignId]
remove: [id: DesignId]
move: [from: number, to: number]
}>()
@@ -29,15 +29,6 @@ function onDrop(targetIndex: number): void {
<template>
<nav class="lesson-sidebar" aria-label="教案目录">
<button
type="button"
class="lesson-sidebar-item lesson-sidebar-cover"
:class="{ 'lesson-sidebar-item--active': selectedId === 'cover' }"
@click="emit('select', 'cover')"
>
封面
</button>
<ul class="lesson-sidebar-list">
<li
v-for="(design, index) in designs"

View File

@@ -74,6 +74,19 @@ describe('WorkspaceView', () => {
expect(wrapper.text()).toContain('CSS 弹性布局')
})
it('does not render cover navigation when lessons exist', async () => {
const data = createEmptyBook()
const design = createEmptyTeachingDesign('1.md')
data.designs.push(design)
data.selectedId = design.id
mockBook(data)
const wrapper = mount(WorkspaceView, { props: { bookId: 'b1' } })
await flushPromises()
expect(wrapper.text()).not.toContain('封面')
})
it('clears the lessons after confirmation', async () => {
const data = createEmptyBook()
data.designs.push(createEmptyTeachingDesign('1.md'))

View File

@@ -32,7 +32,6 @@ const {
selectPage,
moveDesign,
removeDesign,
updateCover,
updateDesign,
clearBook,
generateLesson,
@@ -298,10 +297,7 @@ function closeFixDialog(): void {
@move="moveDesign"
/>
<A4Workspace
:cover="book.cover"
:selected-id="book.selectedId"
:selected-design="selectedDesign"
@update:cover="updateCover"
@update:design="handleDesignUpdate"
/>
</div>