|
1 | 1 | <script lang="ts"> |
2 | | - import { createEventDispatcher } from "svelte"; |
3 | | - import type { Arc, ModuleSlot } from "$lib/types/themis"; |
4 | | - import ModuleCard from "./ModuleCard.svelte"; |
5 | | -
|
6 | | - export let arc: Arc; |
7 | | - export let isExpanded: boolean; |
8 | | - export let generatingModuleId: string | null; |
9 | | -
|
10 | | - const dispatch = createEventDispatcher<{ |
11 | | - toggle: { arcId: string }; |
12 | | - generateModule: { module: ModuleSlot; arc: Arc }; |
13 | | - generateOverview: { module: ModuleSlot; arc: Arc }; |
14 | | - viewPreview: { moduleId: string }; |
15 | | - }>(); |
16 | | -
|
17 | | - $: completedCount = arc.modules.filter(m => m.status === 'complete').length; |
18 | | - $: canGenerate = generatingModuleId === null; |
19 | | -
|
20 | | - function handleToggle() { |
21 | | - dispatch('toggle', { arcId: arc.id }); |
22 | | - } |
23 | | -
|
24 | | - function handleGenerateModule(event: CustomEvent<{ module: ModuleSlot; arc: Arc }>) { |
25 | | - dispatch('generateModule', event.detail); |
26 | | - } |
27 | | -
|
28 | | - function handleGenerateOverview(event: CustomEvent<{ module: ModuleSlot; arc: Arc }>) { |
29 | | - dispatch('generateOverview', event.detail); |
30 | | - } |
31 | | -
|
32 | | - function handleViewPreview(event: CustomEvent<{ moduleId: string }>) { |
33 | | - dispatch('viewPreview', event.detail); |
34 | | - } |
| 2 | + import { createEventDispatcher } from "svelte"; |
| 3 | + import type { Arc, ModuleSlot } from "$lib/types/themis"; |
| 4 | + import ModuleCard from "./ModuleCard.svelte"; |
| 5 | +
|
| 6 | + export let arc: Arc; |
| 7 | + export let isExpanded: boolean; |
| 8 | + export let generatingModuleId: string | null; |
| 9 | +
|
| 10 | + const dispatch = createEventDispatcher<{ |
| 11 | + toggle: { arcId: string }; |
| 12 | + generateModule: { module: ModuleSlot; arc: Arc }; |
| 13 | + generateOverview: { module: ModuleSlot; arc: Arc }; |
| 14 | + viewPreview: { moduleId: string }; |
| 15 | + }>(); |
| 16 | +
|
| 17 | + $: completedCount = arc.modules.filter((m) => m.status === "complete").length; |
| 18 | + $: canGenerate = generatingModuleId === null; |
| 19 | +
|
| 20 | + function handleToggle() { |
| 21 | + dispatch("toggle", { arcId: arc.id }); |
| 22 | + } |
| 23 | +
|
| 24 | + function handleGenerateModule( |
| 25 | + event: CustomEvent<{ module: ModuleSlot; arc: Arc }>, |
| 26 | + ) { |
| 27 | + dispatch("generateModule", event.detail); |
| 28 | + } |
| 29 | +
|
| 30 | + function handleGenerateOverview( |
| 31 | + event: CustomEvent<{ module: ModuleSlot; arc: Arc }>, |
| 32 | + ) { |
| 33 | + dispatch("generateOverview", event.detail); |
| 34 | + } |
| 35 | +
|
| 36 | + function handleViewPreview(event: CustomEvent<{ moduleId: string }>) { |
| 37 | + dispatch("viewPreview", event.detail); |
| 38 | + } |
35 | 39 | </script> |
36 | 40 |
|
37 | 41 | <div class="arc-section"> |
38 | | - <button |
39 | | - class="arc-header" |
40 | | - on:click={handleToggle} |
41 | | - class:expanded={isExpanded} |
42 | | - > |
43 | | - <div class="arc-header-content"> |
44 | | - <h3> |
45 | | - <span class="arc-icon">{isExpanded ? '▼' : '▶'}</span> |
46 | | - Arc {arc.order}: {arc.title} |
47 | | - </h3> |
48 | | - <p class="arc-theme">{arc.theme}</p> |
49 | | - </div> |
50 | | - <div class="arc-meta"> |
51 | | - <span class="arc-modules-count"> |
52 | | - {completedCount}/{arc.modules.length} modules |
53 | | - </span> |
54 | | - </div> |
55 | | - </button> |
56 | | - |
57 | | - {#if isExpanded} |
58 | | - <div class="module-list"> |
59 | | - {#each arc.modules as module (module.id)} |
60 | | - <ModuleCard |
61 | | - {module} |
62 | | - {arc} |
63 | | - isGenerating={generatingModuleId === module.id} |
64 | | - canGenerate={canGenerate} |
65 | | - on:generate={handleGenerateModule} |
66 | | - on:generateOverview={handleGenerateOverview} |
67 | | - on:viewPreview={handleViewPreview} |
68 | | - /> |
69 | | - {/each} |
70 | | - </div> |
71 | | - {/if} |
| 42 | + <button |
| 43 | + class="arc-header" |
| 44 | + on:click={handleToggle} |
| 45 | + class:expanded={isExpanded} |
| 46 | + > |
| 47 | + <div class="arc-header-content"> |
| 48 | + <h3> |
| 49 | + <span class="arc-icon">{isExpanded ? "▼" : "▶"}</span> |
| 50 | + Arc {arc.order}: {arc.title} |
| 51 | + </h3> |
| 52 | + <p class="arc-theme">{arc.theme}</p> |
| 53 | + </div> |
| 54 | + <div class="arc-meta"> |
| 55 | + <span class="arc-modules-count"> |
| 56 | + {completedCount}/{arc.modules.length} modules |
| 57 | + </span> |
| 58 | + </div> |
| 59 | + </button> |
| 60 | + |
| 61 | + {#if isExpanded} |
| 62 | + <div class="module-list"> |
| 63 | + {#each arc.modules as module (module.id)} |
| 64 | + <ModuleCard |
| 65 | + {module} |
| 66 | + {arc} |
| 67 | + isGenerating={generatingModuleId === module.id} |
| 68 | + {canGenerate} |
| 69 | + on:generate={handleGenerateModule} |
| 70 | + on:generateOverview={handleGenerateOverview} |
| 71 | + on:viewPreview={handleViewPreview} |
| 72 | + /> |
| 73 | + {/each} |
| 74 | + </div> |
| 75 | + {/if} |
72 | 76 | </div> |
73 | 77 |
|
74 | 78 | <style> |
75 | | - .arc-section { |
76 | | - background: white; |
77 | | - border: 1px solid var(--palette-line); |
78 | | - border-radius: 8px; |
79 | | - overflow: hidden; |
80 | | - } |
81 | | -
|
82 | | - .arc-header { |
83 | | - width: 100%; |
84 | | - padding: 1.5rem; |
85 | | - background: var(--palette-bg-nav); |
86 | | - border: none; |
87 | | - cursor: pointer; |
88 | | - display: flex; |
89 | | - justify-content: space-between; |
90 | | - align-items: center; |
91 | | - transition: background-color 0.2s; |
92 | | - } |
93 | | -
|
94 | | - .arc-header:hover { |
95 | | - background: var(--palette-bg-subtle); |
96 | | - } |
97 | | -
|
98 | | - .arc-header.expanded { |
99 | | - background: var(--palette-bg-subtle); |
100 | | - } |
101 | | -
|
102 | | - .arc-header-content { |
103 | | - flex: 1; |
104 | | - text-align: left; |
105 | | - } |
106 | | -
|
107 | | - .arc-header h3 { |
108 | | - font-size: 1.25rem; |
109 | | - color: var(--palette-foreground); |
110 | | - margin: 0 0 0.5rem 0; |
111 | | - display: flex; |
112 | | - align-items: center; |
113 | | - gap: 0.5rem; |
114 | | - } |
115 | | -
|
116 | | - .arc-icon { |
117 | | - font-size: 0.875rem; |
118 | | - color: var(--palette-foreground-alt); |
119 | | - } |
120 | | -
|
121 | | - .arc-theme { |
122 | | - color: var(--palette-foreground-alt); |
123 | | - font-size: 0.9rem; |
124 | | - margin: 0; |
125 | | - font-style: italic; |
126 | | - } |
127 | | -
|
128 | | - .arc-meta { |
129 | | - display: flex; |
130 | | - align-items: center; |
131 | | - gap: 1rem; |
132 | | - } |
133 | | -
|
134 | | - .arc-modules-count { |
135 | | - font-size: 0.875rem; |
136 | | - color: var(--palette-foreground-alt); |
137 | | - font-weight: 500; |
138 | | - } |
139 | | -
|
140 | | - .module-list { |
141 | | - padding: 1rem; |
142 | | - display: flex; |
143 | | - flex-direction: column; |
144 | | - gap: 1rem; |
145 | | - } |
| 79 | + .arc-section { |
| 80 | + background: var(--palette-bg-subtle); |
| 81 | + border: 1px solid var(--palette-line); |
| 82 | + border-radius: 8px; |
| 83 | + overflow: hidden; |
| 84 | + } |
| 85 | +
|
| 86 | + .arc-header { |
| 87 | + width: 100%; |
| 88 | + padding: 1.5rem; |
| 89 | + background: var(--palette-bg-nav); |
| 90 | + border: none; |
| 91 | + cursor: pointer; |
| 92 | + display: flex; |
| 93 | + justify-content: space-between; |
| 94 | + align-items: center; |
| 95 | + transition: background-color 0.2s; |
| 96 | + } |
| 97 | +
|
| 98 | + .arc-header:hover { |
| 99 | + background: var(--palette-bg-subtle); |
| 100 | + } |
| 101 | +
|
| 102 | + .arc-header.expanded { |
| 103 | + background: var(--palette-bg-subtle); |
| 104 | + } |
| 105 | +
|
| 106 | + .arc-header-content { |
| 107 | + flex: 1; |
| 108 | + text-align: left; |
| 109 | + } |
| 110 | +
|
| 111 | + .arc-header h3 { |
| 112 | + font-size: 1.25rem; |
| 113 | + color: var(--palette-foreground); |
| 114 | + margin: 0 0 0.5rem 0; |
| 115 | + display: flex; |
| 116 | + align-items: center; |
| 117 | + gap: 0.5rem; |
| 118 | + } |
| 119 | +
|
| 120 | + .arc-icon { |
| 121 | + font-size: 0.875rem; |
| 122 | + color: var(--palette-foreground-alt); |
| 123 | + } |
| 124 | +
|
| 125 | + .arc-theme { |
| 126 | + color: var(--palette-foreground-alt); |
| 127 | + font-size: 0.9rem; |
| 128 | + margin: 0; |
| 129 | + font-style: italic; |
| 130 | + } |
| 131 | +
|
| 132 | + .arc-meta { |
| 133 | + display: flex; |
| 134 | + align-items: center; |
| 135 | + gap: 1rem; |
| 136 | + } |
| 137 | +
|
| 138 | + .arc-modules-count { |
| 139 | + font-size: 0.875rem; |
| 140 | + color: var(--palette-foreground-alt); |
| 141 | + font-weight: 500; |
| 142 | + } |
| 143 | +
|
| 144 | + .module-list { |
| 145 | + padding: 1rem; |
| 146 | + display: flex; |
| 147 | + flex-direction: column; |
| 148 | + gap: 1rem; |
| 149 | + } |
146 | 150 | </style> |
0 commit comments