slidev-theme-gtlabo 2.1.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@
8
8
  </template>
9
9
 
10
10
  <script setup>
11
- import { computed, onMounted, onUnmounted, inject } from 'vue'
11
+ import { computed, inject, onMounted, onUnmounted } from 'vue'
12
12
  import { useSlideContext } from '@slidev/client'
13
13
 
14
14
  const { $slidev, $page } = useSlideContext()
@@ -32,65 +32,37 @@ const props = defineProps({
32
32
  }
33
33
  })
34
34
 
35
- // グローバル引用管理の初期化
36
- if (!window.citationManager) {
37
- window.citationManager = {
38
- citations: new Map(), // id -> { number, data, formatted }
39
- citationKeys: [], // frontmatterのキーの順番
40
- pageCitations: new Map(), // pageNumber -> Set of citation ids
41
- initialized: false,
42
- listeners: new Set() // 更新通知用リスナー
35
+ // ページごとの引用管理(slide-bottom.vue用)
36
+ if (!window.pageCitations) {
37
+ window.pageCitations = {
38
+ data: new Map(), // pageNumber -> Set of citation ids
39
+ listeners: new Set()
43
40
  }
44
41
  }
45
42
 
46
- // 更新を通知する関数
47
43
  const notifyListeners = () => {
48
- window.citationManager.listeners.forEach(listener => {
49
- try {
50
- listener()
51
- } catch (e) {
52
- // リスナーエラーを無視
53
- }
44
+ window.pageCitations.listeners.forEach(listener => {
45
+ try { listener() } catch (e) { /* ignore */ }
54
46
  })
55
47
  }
56
48
 
57
- // frontmatterの順番でcitation番号を事前に割り当て
58
- const initializeCitations = () => {
59
- if (!window.citationManager.initialized) {
60
- window.citationManager.citationKeys = Object.keys(citations)
61
-
62
- window.citationManager.citationKeys.forEach((key, index) => {
63
- if (!window.citationManager.citations.has(key)) {
64
- const data = citations[key]
65
- const newCitation = {
66
- number: index + 1,
67
- data: data,
68
- formatted: formatCitation(data)
69
- }
70
- window.citationManager.citations.set(key, newCitation)
71
- }
72
- })
73
-
74
- window.citationManager.initialized = true
75
- }
76
- }
77
-
78
49
  // 引用データを取得
79
50
  const citationData = computed(() => {
80
- return citations[props.id] || null
51
+ return citations.value[props.id] || null
81
52
  })
82
53
 
83
- // 引用番号を取得
54
+ // 引用番号を取得(シンプル版:毎回計算)
84
55
  const citationNumber = computed(() => {
85
- if (!citationData.value) {
56
+ const citationsData = citations.value
57
+ if (!citationsData || !citationData.value) {
86
58
  return '?'
87
59
  }
88
60
 
89
- initializeCitations()
61
+ const keys = Object.keys(citationsData)
62
+ const index = keys.indexOf(props.id)
90
63
 
91
- const citation = window.citationManager.citations.get(props.id)
92
- if (citation) {
93
- return citation.number
64
+ if (index >= 0) {
65
+ return index + 1
94
66
  }
95
67
 
96
68
  return '?'
@@ -101,12 +73,6 @@ const formattedCitation = computed(() => {
101
73
  if (!citationData.value) {
102
74
  return '引用情報が見つかりません'
103
75
  }
104
-
105
- const citation = window.citationManager.citations.get(props.id)
106
- if (citation && citation.formatted) {
107
- return citation.formatted
108
- }
109
-
110
76
  return formatCitation(citationData.value)
111
77
  })
112
78
 
@@ -161,17 +127,16 @@ const formatCitation = (data) => {
161
127
  return citation || '引用情報が不完全です'
162
128
  }
163
129
 
164
- // 現在のページに引用を登録
130
+ // 現在のページに引用を登録(slide-bottom.vue用)
165
131
  const registerCitation = () => {
166
- // $page はこのコンポーネントが配置されているスライドの番号(静的)
167
132
  const page = $page
168
133
  if (!page) return
169
134
 
170
- if (!window.citationManager.pageCitations.has(page)) {
171
- window.citationManager.pageCitations.set(page, new Set())
135
+ if (!window.pageCitations.data.has(page)) {
136
+ window.pageCitations.data.set(page, new Set())
172
137
  }
173
138
 
174
- const pageSet = window.citationManager.pageCitations.get(page)
139
+ const pageSet = window.pageCitations.data.get(page)
175
140
  if (!pageSet.has(props.id)) {
176
141
  pageSet.add(props.id)
177
142
  notifyListeners()
@@ -183,18 +148,17 @@ const unregisterCitation = () => {
183
148
  const page = $page
184
149
  if (!page) return
185
150
 
186
- const pageSet = window.citationManager.pageCitations.get(page)
151
+ const pageSet = window.pageCitations.data.get(page)
187
152
  if (pageSet) {
188
153
  pageSet.delete(props.id)
189
154
  if (pageSet.size === 0) {
190
- window.citationManager.pageCitations.delete(page)
155
+ window.pageCitations.data.delete(page)
191
156
  }
192
157
  notifyListeners()
193
158
  }
194
159
  }
195
160
 
196
161
  onMounted(() => {
197
- initializeCitations()
198
162
  registerCitation()
199
163
  })
200
164
 
@@ -147,12 +147,23 @@
147
147
  </template>
148
148
 
149
149
  <script setup>
150
- import { computed } from 'vue'
150
+ import { computed, inject } from 'vue'
151
151
  import { useSlideContext } from '@slidev/client'
152
152
 
153
153
  // Slidevコンテキストからconfigsにアクセス
154
154
  const { $slidev } = useSlideContext()
155
- const citations = $slidev.configs.citations || {}
155
+
156
+ // 方法1: frontmatterから取得(従来通り)
157
+ const frontmatterCitations = $slidev.configs.citations || {}
158
+
159
+ // 方法2: injectから取得(外部ファイル対応)
160
+ const injectedCitations = inject('citations', {})
161
+
162
+ // 両方をマージ(frontmatter優先)
163
+ const citations = computed(() => ({
164
+ ...injectedCitations,
165
+ ...frontmatterCitations
166
+ }))
156
167
 
157
168
  // プロパティ定義
158
169
  const props = defineProps({
@@ -177,16 +188,17 @@ const props = defineProps({
177
188
 
178
189
  // 参考文献リストを生成(frontmatterの順番を維持)
179
190
  const citationsList = computed(() => {
180
- if (!citations || typeof citations !== 'object') {
191
+ const citationsData = citations.value
192
+ if (!citationsData || typeof citationsData !== 'object') {
181
193
  return []
182
194
  }
183
195
 
184
196
  // frontmatterの記述順でキーを取得
185
- const originalKeys = Object.keys(citations)
197
+ const originalKeys = Object.keys(citationsData)
186
198
 
187
199
  const list = originalKeys.map((key, index) => ({
188
200
  key,
189
- data: citations[key],
201
+ data: citationsData[key],
190
202
  number: index + 1 // frontmatterの順番に基づく番号
191
203
  }))
192
204
 
@@ -1,4 +1,4 @@
1
- <!-- components/TableOfContents.vue -->
1
+ <!-- components/SectionDivider.vue -->
2
2
  <template>
3
3
  <div class="table-of-contents-container flex flex-col justify-start bg-white overflow-hidden relative">
4
4
  <!-- 厳密な背景グリッド - Swiss Styleの基礎 -->
@@ -160,12 +160,23 @@
160
160
  </template>
161
161
 
162
162
  <script setup>
163
- import { computed } from 'vue'
163
+ import { computed, inject } from 'vue'
164
164
  import { useSlideContext } from '@slidev/client'
165
165
 
166
166
  // Slidevコンテキストからconfigsにアクセス
167
167
  const { $slidev } = useSlideContext()
168
- const chapters = $slidev.configs.chapters || {}
168
+
169
+ // 方法1: frontmatterから取得(従来通り)
170
+ const frontmatterChapters = $slidev.configs.chapters || {}
171
+
172
+ // 方法2: injectから取得(外部ファイル対応)
173
+ const injectedChapters = inject('chapters', {})
174
+
175
+ // 両方をマージ(frontmatter優先)
176
+ const chapters = computed(() => ({
177
+ ...injectedChapters,
178
+ ...frontmatterChapters
179
+ }))
169
180
 
170
181
  const props = defineProps({
171
182
  nextChapter: {
@@ -188,7 +199,8 @@ const props = defineProps({
188
199
 
189
200
  // セクションの重複を除去する関数
190
201
  const getUniqueSections = (chapterKey) => {
191
- const chapter = chapters[chapterKey]
202
+ const chaptersData = chapters.value
203
+ const chapter = chaptersData[chapterKey]
192
204
  if (!chapter?.sections) return []
193
205
 
194
206
  const sections = chapter.sections
@@ -221,14 +233,15 @@ const isAppendixSection = computed(() => {
221
233
 
222
234
  // 通常の章リスト(refと付録を除外)
223
235
  const regularChapters = computed(() => {
224
- if (!chapters || typeof chapters !== 'object') {
236
+ const chaptersData = chapters.value
237
+ if (!chaptersData || typeof chaptersData !== 'object') {
225
238
  return []
226
239
  }
227
240
 
228
- return Object.keys(chapters)
241
+ return Object.keys(chaptersData)
229
242
  .filter(chapterKey => chapterKey !== 'ref' && !chapterKey.startsWith('ap'))
230
243
  .map(chapterKey => {
231
- const chapter = chapters[chapterKey]
244
+ const chapter = chaptersData[chapterKey]
232
245
  const sections = chapter?.sections || {}
233
246
  const sectionKeys = Object.keys(sections)
234
247
 
@@ -244,14 +257,15 @@ const regularChapters = computed(() => {
244
257
 
245
258
  // 付録の章リスト
246
259
  const appendixChapters = computed(() => {
247
- if (!chapters || typeof chapters !== 'object') {
260
+ const chaptersData = chapters.value
261
+ if (!chaptersData || typeof chaptersData !== 'object') {
248
262
  return []
249
263
  }
250
264
 
251
- return Object.keys(chapters)
265
+ return Object.keys(chaptersData)
252
266
  .filter(chapterKey => chapterKey.startsWith('ap'))
253
267
  .map(chapterKey => {
254
- const chapter = chapters[chapterKey]
268
+ const chapter = chaptersData[chapterKey]
255
269
  const sections = chapter?.sections || {}
256
270
  const sectionKeys = Object.keys(sections)
257
271
 
@@ -267,7 +281,8 @@ const appendixChapters = computed(() => {
267
281
 
268
282
  // セクションタイトルを取得
269
283
  const getSectionTitle = (chapterKey, sectionKey) => {
270
- const chapter = chapters[chapterKey]
284
+ const chaptersData = chapters.value
285
+ const chapter = chaptersData[chapterKey]
271
286
  const sectionData = chapter?.sections?.[sectionKey]
272
287
  return sectionData?.title || `セクション ${sectionKey}`
273
288
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slidev-theme-gtlabo",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "A Slidev theme for laboratory presentations with customizable components",
5
5
  "author": "mksmkss",
6
6
  "license": "MIT",
@@ -1,93 +0,0 @@
1
- <!-- components/ChapterItem.vue -->
2
- <template>
3
- <div
4
- class="flex flex-col"
5
- :class="isNext ? 'border-sky-500 border-l-8 pl-6' : 'border-slate-200 border-l-4 pl-7'"
6
- >
7
- <!-- 次の章インジケーター - sky-500アクセント -->
8
- <div
9
- v-if="isNext"
10
- :class="nextBadgeClasses"
11
- class="bg-sky-500 text-white font-bold uppercase tracking-widest leading-none"
12
- >
13
- NEXT
14
- </div>
15
-
16
- <!-- 章番号とタイトル - 左揃え、明確なヒエラルキー -->
17
- <div :class="chapterHeaderClasses">
18
- <div class="flex items-end space-x-3 w-full">
19
- <div :class="chapterNumberClasses" class="flex text-slate-900 font-bold tabular-nums leading-none">
20
- {{ chapterNumber }}
21
- </div>
22
- <div class="flex-1">
23
- <div class="border-b border-slate-900 mb-2">
24
- <span :class="chapterTitleClasses" class="text-slate-900 font-bold leading-tight">
25
- {{ chapter.title }}
26
- </span>
27
- </div>
28
- </div>
29
- </div>
30
- </div>
31
-
32
- <!-- セクション一覧 - 機能的な情報構造 -->
33
- <div :class="sectionListClasses">
34
- <div
35
- v-for="(sectionData, sectionIndex) in chapter.uniqueSections"
36
- :key="`${chapter.key}-${sectionIndex}`"
37
- class="flex items-start"
38
- >
39
- <span class="w-1 h-1 bg-slate-400 mr-2 mt-1.5 flex-shrink-0 rounded-full"></span>
40
- <span :class="sectionTextClasses" class="text-slate-600 leading-snug">
41
- {{ sectionData.title }}
42
- </span>
43
- </div>
44
- </div>
45
- </div>
46
- </template>
47
-
48
- <script setup>
49
- import { computed } from 'vue'
50
-
51
- const props = defineProps({
52
- chapter: {
53
- type: Object,
54
- required: true
55
- },
56
- index: {
57
- type: Number,
58
- required: true
59
- },
60
- isNext: {
61
- type: Boolean,
62
- default: false
63
- },
64
- isAppendix: {
65
- type: Boolean,
66
- default: false
67
- },
68
- size: {
69
- type: String,
70
- default: 'md'
71
- },
72
- config: {
73
- type: Object,
74
- required: true
75
- }
76
- })
77
-
78
- // 章番号の生成(通常章は "01", "02"、付録は "A1", "A2")
79
- const chapterNumber = computed(() => {
80
- if (props.isAppendix) {
81
- return `A${props.index + 1}`
82
- }
83
- return String(props.index + 1).padStart(2, '0')
84
- })
85
-
86
- // 動的クラス
87
- const chapterHeaderClasses = computed(() => props.config.chapterHeader)
88
- const chapterNumberClasses = computed(() => props.config.chapterNumber)
89
- const chapterTitleClasses = computed(() => props.config.chapterTitle)
90
- const sectionListClasses = computed(() => props.config.sectionList)
91
- const sectionTextClasses = computed(() => props.config.sectionText)
92
- const nextBadgeClasses = computed(() => props.config.nextBadge)
93
- </script>