slidev-theme-gtlabo 2.0.4 → 2.1.0

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.
@@ -1,34 +1,29 @@
1
1
  <template>
2
2
  <span>
3
3
  <!-- インライン引用番号 -->
4
- <sup class="text-blue-600 font-semibold">
4
+ <sup class="text-blue-600 font-semibold cursor-help" :title="formattedCitation">
5
5
  [{{ citationNumber }}]
6
6
  </sup>
7
-
8
- <!-- このコンポーネント専用の引用情報表示エリア -->
9
- <div
10
- v-if="shouldShowCitation"
11
- class="fixed bottom-0 left-0 right-0 bg-white border-t-2 border-gray-300 shadow-lg z-40 max-h-32 overflow-y-auto"
12
- style="pointer-events: none;"
13
- >
14
- <div class="max-w-7xl mx-auto px-4 py-2">
15
- <div class="space-y-1">
16
- <div class="text-xs text-gray-800">
17
- <span class="font-semibold">[{{ citationNumber }}]</span>
18
- {{ formattedCitation }}
19
- </div>
20
- </div>
21
- </div>
22
- </div>
23
7
  </span>
24
8
  </template>
25
9
 
26
10
  <script setup>
27
- import { computed, onMounted, onUnmounted, ref } from 'vue'
11
+ import { computed, onMounted, onUnmounted, inject } from 'vue'
28
12
  import { useSlideContext } from '@slidev/client'
29
13
 
30
- const { $slidev } = useSlideContext()
31
- const citations = $slidev.configs.citations || {}
14
+ const { $slidev, $page } = useSlideContext()
15
+
16
+ // 方法1: frontmatterから取得(従来通り)
17
+ const frontmatterCitations = $slidev.configs.citations || {}
18
+
19
+ // 方法2: injectから取得(外部ファイル対応)
20
+ const injectedCitations = inject('citations', {})
21
+
22
+ // 両方をマージ(frontmatter優先)
23
+ const citations = computed(() => ({
24
+ ...injectedCitations,
25
+ ...frontmatterCitations
26
+ }))
32
27
 
33
28
  const props = defineProps({
34
29
  id: {
@@ -40,12 +35,25 @@ const props = defineProps({
40
35
  // グローバル引用管理の初期化
41
36
  if (!window.citationManager) {
42
37
  window.citationManager = {
43
- citations: new Map(), // id -> { number, data, formatted }
44
- citationKeys: Object.keys(citations), // frontmatterのキーの順番を保持
45
- initialized: false
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() // 更新通知用リスナー
46
43
  }
47
44
  }
48
45
 
46
+ // 更新を通知する関数
47
+ const notifyListeners = () => {
48
+ window.citationManager.listeners.forEach(listener => {
49
+ try {
50
+ listener()
51
+ } catch (e) {
52
+ // リスナーエラーを無視
53
+ }
54
+ })
55
+ }
56
+
49
57
  // frontmatterの順番でcitation番号を事前に割り当て
50
58
  const initializeCitations = () => {
51
59
  if (!window.citationManager.initialized) {
@@ -55,7 +63,7 @@ const initializeCitations = () => {
55
63
  if (!window.citationManager.citations.has(key)) {
56
64
  const data = citations[key]
57
65
  const newCitation = {
58
- number: index + 1, // 1から開始
66
+ number: index + 1,
59
67
  data: data,
60
68
  formatted: formatCitation(data)
61
69
  }
@@ -67,18 +75,9 @@ const initializeCitations = () => {
67
75
  }
68
76
  }
69
77
 
70
- const isMounted = ref(false)
71
-
72
- // 現在のページ番号を取得
73
- const currentPage = computed(() => {
74
- const page = $slidev.nav.currentPage
75
- return page
76
- })
77
-
78
78
  // 引用データを取得
79
79
  const citationData = computed(() => {
80
- const data = citations[props.id] || null
81
- return data
80
+ return citations[props.id] || null
82
81
  })
83
82
 
84
83
  // 引用番号を取得
@@ -87,7 +86,6 @@ const citationNumber = computed(() => {
87
86
  return '?'
88
87
  }
89
88
 
90
- // 初期化を確実に実行
91
89
  initializeCitations()
92
90
 
93
91
  const citation = window.citationManager.citations.get(props.id)
@@ -112,12 +110,6 @@ const formattedCitation = computed(() => {
112
110
  return formatCitation(citationData.value)
113
111
  })
114
112
 
115
- // 引用を表示すべきかどうか
116
- const shouldShowCitation = computed(() => {
117
- const shouldShow = isMounted.value && citationData.value !== null
118
- return shouldShow
119
- })
120
-
121
113
  // 引用をフォーマット
122
114
  const formatCitation = (data) => {
123
115
  if (!data) {
@@ -126,22 +118,18 @@ const formatCitation = (data) => {
126
118
 
127
119
  let citation = ''
128
120
 
129
- // 著者
130
121
  if (data.author) {
131
122
  citation += data.author
132
123
  }
133
124
 
134
- // タイトル
135
125
  if (data.title) {
136
126
  citation += citation ? `, "${data.title}"` : `"${data.title}"`
137
127
  }
138
128
 
139
- // ジャーナル
140
129
  if (data.journal) {
141
130
  citation += citation ? `, ${data.journal}` : data.journal
142
131
  }
143
132
 
144
- // ボリューム・ナンバー
145
133
  if (data.volume && data.number) {
146
134
  citation += `, Vol. ${data.volume}, No. ${data.number}`
147
135
  } else if (data.volume) {
@@ -150,82 +138,77 @@ const formatCitation = (data) => {
150
138
  citation += `, No. ${data.number}`
151
139
  }
152
140
 
153
- // ページ
154
141
  if (data.pages) {
155
142
  citation += `, pp. ${data.pages}`
156
143
  }
157
144
 
158
- // 年
159
145
  if (data.year) {
160
146
  citation += citation ? ` (${data.year})` : data.year
161
147
  }
162
148
 
163
- // 出版社
164
149
  if (data.publisher) {
165
150
  citation += citation ? `, ${data.publisher}` : data.publisher
166
151
  }
167
152
 
168
- // URL
169
153
  if (data.url) {
170
154
  citation += citation ? `, ${data.url}` : data.url
171
155
  }
172
156
 
173
- // ISSN
174
157
  if (data.issn) {
175
158
  citation += `, ISSN: ${data.issn}`
176
159
  }
177
160
 
178
- const formatted = citation || '引用情報が不完全です'
179
- return formatted
161
+ return citation || '引用情報が不完全です'
162
+ }
163
+
164
+ // 現在のページに引用を登録
165
+ const registerCitation = () => {
166
+ // $page はこのコンポーネントが配置されているスライドの番号(静的)
167
+ const page = $page
168
+ if (!page) return
169
+
170
+ if (!window.citationManager.pageCitations.has(page)) {
171
+ window.citationManager.pageCitations.set(page, new Set())
172
+ }
173
+
174
+ const pageSet = window.citationManager.pageCitations.get(page)
175
+ if (!pageSet.has(props.id)) {
176
+ pageSet.add(props.id)
177
+ notifyListeners()
178
+ }
180
179
  }
181
180
 
182
- // 全体のグローバル状態をデバッグ出力
183
- const debugGlobalState = () => {
184
- // デバッグ用(必要に応じてコメントアウト)
181
+ // 現在のページから引用を解除
182
+ const unregisterCitation = () => {
183
+ const page = $page
184
+ if (!page) return
185
+
186
+ const pageSet = window.citationManager.pageCitations.get(page)
187
+ if (pageSet) {
188
+ pageSet.delete(props.id)
189
+ if (pageSet.size === 0) {
190
+ window.citationManager.pageCitations.delete(page)
191
+ }
192
+ notifyListeners()
193
+ }
185
194
  }
186
195
 
187
- // コンポーネントのマウント時
188
196
  onMounted(() => {
189
- isMounted.value = true
190
-
191
- // 初期化を確実に実行
192
197
  initializeCitations()
193
-
194
- if (citationData.value) {
195
- // 引用番号を取得(副作用でglobal stateに保存される)
196
- const _ = citationNumber.value
197
- debugGlobalState()
198
- }
198
+ registerCitation()
199
199
  })
200
200
 
201
- // コンポーネントのアンマウント時
202
201
  onUnmounted(() => {
203
- isMounted.value = false
204
- debugGlobalState()
202
+ unregisterCitation()
205
203
  })
206
-
207
- // 開発用:グローバル状態確認用の関数をwindowに追加
208
- if (typeof window !== 'undefined') {
209
- window.debugCitationState = debugGlobalState
210
- }
211
204
  </script>
212
205
 
213
206
  <style scoped>
214
- /* スクロールバーのスタイリング */
215
- ::-webkit-scrollbar {
216
- width: 4px;
217
- }
218
-
219
- ::-webkit-scrollbar-track {
220
- background: #f1f1f1;
221
- }
222
-
223
- ::-webkit-scrollbar-thumb {
224
- background: #c1c1c1;
225
- border-radius: 2px;
226
- }
227
-
228
- ::-webkit-scrollbar-thumb:hover {
229
- background: #a8a8a8;
207
+ sup {
208
+ font-size: 0.75em;
209
+ line-height: 0;
210
+ position: relative;
211
+ vertical-align: baseline;
212
+ top: -0.5em;
230
213
  }
231
214
  </style>
@@ -97,12 +97,25 @@
97
97
  </template>
98
98
 
99
99
  <script setup>
100
- import { computed } from 'vue'
100
+ import { computed ,inject } from 'vue'
101
101
  import { useSlideContext } from '@slidev/client'
102
102
 
103
103
  // Slidevコンテキストからconfigsにアクセス
104
104
  const { $slidev } = useSlideContext()
105
- const chapters = $slidev.configs.chapters || {}
105
+
106
+ // 方法1: frontmatterから取得(従来通り)
107
+ const frontmatterChapters = $slidev.configs.chapters || {}
108
+
109
+ // 方法2: injectから取得(外部ファイル対応)
110
+ const injectedChapters = inject('chapters', {})
111
+
112
+ // 両方をマージ(frontmatter優先)
113
+ const chapters = computed(() => ({
114
+ ...injectedChapters,
115
+ ...frontmatterChapters
116
+ }))
117
+
118
+ console.log('Header2.vue - chapters:', chapters.value)
106
119
 
107
120
  const props = defineProps({
108
121
  // タイトル用のプロパティ
@@ -133,28 +146,45 @@ const isSection = computed(() => {
133
146
 
134
147
  // タイトル表示用のデータ
135
148
  const displayData = computed(() => {
149
+ console.log('=== displayData 計算開始 ===')
150
+ console.log('props.chapterData:', props.chapterData)
151
+ console.log('props.currentSection:', props.currentSection)
152
+ console.log('props.chapter:', props.chapter)
153
+ console.log('props.currentChapter:', props.currentChapter)
154
+ console.log('chapters.value:', chapters.value)
155
+
136
156
  // chapterDataが直接渡された場合はそれを使用
137
157
  if (props.chapterData) {
158
+ console.log('→ chapterData を使用')
138
159
  return props.chapterData
139
160
  }
140
161
 
141
162
  // currentSectionが指定されている場合、セクションデータを取得
142
163
  if (props.currentSection && (props.chapter || props.currentChapter)) {
143
164
  const chapterKey = props.chapter || props.currentChapter
144
- const chapterData = chapters[chapterKey]
165
+ console.log('→ セクション検索: chapterKey =', chapterKey)
166
+
167
+ const chapterData = chapters.value[chapterKey]
168
+ console.log('→ chapterData:', chapterData)
169
+ console.log('→ sections:', chapterData?.sections)
170
+ console.log('→ 検索するsection:', props.currentSection)
171
+ console.log('→ sectionData:', chapterData?.sections?.[props.currentSection])
172
+
145
173
  if (chapterData?.sections?.[props.currentSection]) {
146
174
  return chapterData.sections[props.currentSection]
147
175
  }
176
+ console.log('→ セクションが見つかりません')
148
177
  return null
149
178
  }
150
179
 
151
180
  // chapterキーが渡された場合は内部データから取得
152
181
  const chapterKey = props.chapter || props.currentChapter
153
- if (chapterKey && chapters[chapterKey]) {
154
- return chapters[chapterKey]
182
+ if (chapterKey && chapters.value[chapterKey]) {
183
+ console.log('→ 章データを使用')
184
+ return chapters.value[chapterKey]
155
185
  }
156
186
 
157
- // どちらも渡されなかった場合はnull
187
+ console.log('→ 何も見つかりません')
158
188
  return null
159
189
  })
160
190
 
@@ -172,14 +202,21 @@ const isCurrentPageAppendix = computed(() => {
172
202
 
173
203
  // 章リストを生成(refを除外し、appendixの表示を条件分岐)
174
204
  const chapterList = computed(() => {
175
- if (!chapters || typeof chapters !== 'object') {
205
+ const chaptersData = chapters.value
206
+ console.log('=== chapterList 計算 ===')
207
+ console.log('chaptersData:', chaptersData)
208
+ console.log('typeof chaptersData:', typeof chaptersData)
209
+ console.log('Object.keys:', chaptersData ? Object.keys(chaptersData) : 'null')
210
+
211
+ if (!chaptersData || typeof chaptersData !== 'object') {
212
+ console.log('→ chaptersData が無効')
176
213
  return []
177
214
  }
178
215
 
179
- return Object.keys(chapters)
180
- .filter(chapterKey => chapterKey !== 'ref') // refを除外
216
+ const result = Object.keys(chaptersData)
217
+ .filter(chapterKey => chapterKey !== 'ref')
181
218
  .map(chapterKey => {
182
- const chapter = chapters[chapterKey]
219
+ const chapter = chaptersData[chapterKey]
183
220
  const sections = chapter?.sections || {}
184
221
  const sectionKeys = Object.keys(sections)
185
222
 
@@ -191,17 +228,26 @@ const chapterList = computed(() => {
191
228
  isAppendix: chapterKey.startsWith('ap')
192
229
  }
193
230
  })
231
+
232
+ console.log('chapterList result:', result)
233
+ return result
194
234
  })
195
235
 
196
236
  // 表示する章リスト(appendixページかどうかで切り替え)
197
237
  const displayChapterList = computed(() => {
238
+ console.log('=== displayChapterList 計算 ===')
239
+ console.log('isCurrentPageAppendix:', isCurrentPageAppendix.value)
240
+ console.log('chapterList:', chapterList.value)
241
+
242
+ let result
198
243
  if (isCurrentPageAppendix.value) {
199
- // appendixページの場合はappendixのみ表示
200
- return chapterList.value.filter(chapter => chapter.isAppendix)
244
+ result = chapterList.value.filter(chapter => chapter.isAppendix)
201
245
  } else {
202
- // 通常ページの場合はappendixを除外
203
- return chapterList.value.filter(chapter => !chapter.isAppendix)
246
+ result = chapterList.value.filter(chapter => !chapter.isAppendix)
204
247
  }
248
+
249
+ console.log('displayChapterList result:', result)
250
+ return result
205
251
  })
206
252
 
207
253
  // appendixの開始ページを計算(SectionDivider考慮版)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slidev-theme-gtlabo",
3
- "version": "2.0.4",
3
+ "version": "2.1.0",
4
4
  "description": "A Slidev theme for laboratory presentations with customizable components",
5
5
  "author": "mksmkss",
6
6
  "license": "MIT",
@@ -12,7 +12,7 @@
12
12
  "main": "index.js",
13
13
  "files": [
14
14
  "components",
15
- "layouts",
15
+ "layouts",
16
16
  "styles",
17
17
  "setup",
18
18
  "uno.config.ts",
@@ -20,7 +20,7 @@
20
20
  ],
21
21
  "repository": {
22
22
  "type": "git",
23
- "url": "https://github.com/mksmkss/slidev-theme-gtlabo.git"
23
+ "url": "git+https://github.com/mksmkss/slidev-theme-gtlabo.git"
24
24
  },
25
25
  "homepage": "https://github.com/mksmkss/slidev-theme-gtlabo",
26
26
  "bugs": {
@@ -62,4 +62,4 @@
62
62
  "aspectRatio": "4/3"
63
63
  }
64
64
  }
65
- }
65
+ }