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.
- package/package.json +3 -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.
|
|
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",
|
package/slide-bottom.vue
ADDED
|
@@ -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>
|