slidev-theme-gtlabo 2.1.5 → 2.1.6

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.
Files changed (2) hide show
  1. package/package.json +3 -2
  2. package/slide-bottom.vue +191 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slidev-theme-gtlabo",
3
- "version": "2.1.5",
3
+ "version": "2.1.6",
4
4
  "description": "A Slidev theme for laboratory presentations with customizable components",
5
5
  "author": "mksmkss",
6
6
  "license": "MIT",
@@ -16,7 +16,8 @@
16
16
  "styles",
17
17
  "setup",
18
18
  "uno.config.ts",
19
- "index.js"
19
+ "index.js",
20
+ "slide-bottom.vue"
20
21
  ],
21
22
  "repository": {
22
23
  "type": "git",
@@ -0,0 +1,191 @@
1
+ <!-- slide-bottom.vue -->
2
+ <template>
3
+ <div
4
+ v-if="currentCitations.length > 0"
5
+ class="absolute bottom-0 left-0 right-0 bg-white/95 border-t border-gray-200 shadow-sm z-40"
6
+ >
7
+ <div class="max-w-7xl mx-auto px-4 py-2">
8
+ <div class="space-y-1">
9
+ <div
10
+ v-for="citation in currentCitations"
11
+ :key="citation.id"
12
+ class="text-xs text-gray-700 leading-relaxed"
13
+ >
14
+ <span class="font-semibold text-blue-600">[{{ citation.number }}]</span>
15
+ <span class="ml-1">{{ citation.formatted }}</span>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </template>
21
+
22
+ <script setup>
23
+ import { ref, computed, inject, onMounted, onUnmounted, isRef } from 'vue'
24
+ import { useSlideContext } from '@slidev/client'
25
+
26
+ const { $slidev, $page } = useSlideContext()
27
+
28
+ // $page を数値として取得するヘルパー
29
+ const getPageNumber = () => {
30
+ if (isRef($page)) {
31
+ return $page.value
32
+ }
33
+ return $page
34
+ }
35
+
36
+ // 方法1: frontmatterから取得(従来通り)
37
+ const frontmatterCitations = $slidev.configs.citations || {}
38
+
39
+ // 方法2: injectから取得(外部ファイル対応)
40
+ const injectedCitations = inject('citations', {})
41
+
42
+ // 両方をマージ(frontmatter優先)
43
+ const citations = computed(() => ({
44
+ ...injectedCitations,
45
+ ...frontmatterCitations
46
+ }))
47
+
48
+ // リアクティブな更新トリガー
49
+ const updateTrigger = ref(0)
50
+
51
+ // ページごとの引用管理の初期化
52
+ if (!window.pageCitations) {
53
+ window.pageCitations = {
54
+ data: new Map(),
55
+ listeners: new Set()
56
+ }
57
+ }
58
+
59
+ // 引用をフォーマット
60
+ const formatCitation = (data) => {
61
+ if (!data) {
62
+ return '引用情報が見つかりません'
63
+ }
64
+
65
+ let citation = ''
66
+
67
+ if (data.author) {
68
+ citation += data.author
69
+ }
70
+
71
+ if (data.title) {
72
+ citation += citation ? `, "${data.title}"` : `"${data.title}"`
73
+ }
74
+
75
+ if (data.journal) {
76
+ citation += citation ? `, ${data.journal}` : data.journal
77
+ }
78
+
79
+ if (data.volume && data.number) {
80
+ citation += `, Vol. ${data.volume}, No. ${data.number}`
81
+ } else if (data.volume) {
82
+ citation += `, Vol. ${data.volume}`
83
+ } else if (data.number) {
84
+ citation += `, No. ${data.number}`
85
+ }
86
+
87
+ if (data.pages) {
88
+ citation += `, pp. ${data.pages}`
89
+ }
90
+
91
+ if (data.year) {
92
+ citation += citation ? ` (${data.year})` : data.year
93
+ }
94
+
95
+ if (data.publisher) {
96
+ citation += citation ? `, ${data.publisher}` : data.publisher
97
+ }
98
+
99
+ if (data.url) {
100
+ citation += citation ? `, ${data.url}` : data.url
101
+ }
102
+
103
+ if (data.issn) {
104
+ citation += `, ISSN: ${data.issn}`
105
+ }
106
+
107
+ return citation || '引用情報が不完全です'
108
+ }
109
+
110
+ // 引用番号を取得
111
+ const getCitationNumber = (id) => {
112
+ const citationsData = citations.value
113
+ if (!citationsData) return '?'
114
+
115
+ const keys = Object.keys(citationsData)
116
+ const index = keys.indexOf(id)
117
+
118
+ return index >= 0 ? index + 1 : '?'
119
+ }
120
+
121
+ // 現在のページの引用リストを取得
122
+ const currentCitations = computed(() => {
123
+ // updateTriggerを参照して再計算をトリガー
124
+ const _ = updateTrigger.value
125
+ // citationsも参照してリアクティブにする
126
+ const citationsData = citations.value
127
+
128
+ const page = getPageNumber()
129
+
130
+ if (!page || !window.pageCitations?.data?.has(page)) {
131
+ return []
132
+ }
133
+
134
+ const pageSet = window.pageCitations.data.get(page)
135
+ const citationList = []
136
+
137
+ pageSet.forEach(id => {
138
+ const data = citationsData[id]
139
+ if (data) {
140
+ citationList.push({
141
+ id: id,
142
+ number: getCitationNumber(id),
143
+ formatted: formatCitation(data)
144
+ })
145
+ }
146
+ })
147
+
148
+ // 引用番号でソート
149
+ citationList.sort((a, b) => a.number - b.number)
150
+
151
+ return citationList
152
+ })
153
+
154
+ // 更新リスナー
155
+ const handleUpdate = () => {
156
+ updateTrigger.value++
157
+ }
158
+
159
+ onMounted(() => {
160
+ window.pageCitations.listeners.add(handleUpdate)
161
+
162
+ // 初期表示のために少し遅延して更新
163
+ setTimeout(() => {
164
+ updateTrigger.value++
165
+ }, 100)
166
+ })
167
+
168
+ onUnmounted(() => {
169
+ window.pageCitations.listeners.delete(handleUpdate)
170
+ })
171
+ </script>
172
+
173
+ <style scoped>
174
+ /* スクロールバーのスタイリング */
175
+ ::-webkit-scrollbar {
176
+ width: 4px;
177
+ }
178
+
179
+ ::-webkit-scrollbar-track {
180
+ background: #f1f1f1;
181
+ }
182
+
183
+ ::-webkit-scrollbar-thumb {
184
+ background: #c1c1c1;
185
+ border-radius: 2px;
186
+ }
187
+
188
+ ::-webkit-scrollbar-thumb:hover {
189
+ background: #a8a8a8;
190
+ }
191
+ </style>