slidev-theme-gtlabo 1.0.7 → 1.0.9

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.
@@ -37,11 +37,33 @@ const props = defineProps({
37
37
  }
38
38
  })
39
39
 
40
- // グローバル引用管理の初期化(引用番号のみ管理)
40
+ // グローバル引用管理の初期化
41
41
  if (!window.citationManager) {
42
42
  window.citationManager = {
43
- counter: 1,
44
- citations: new Map() // id -> { number, data, formatted }
43
+ citations: new Map(), // id -> { number, data, formatted }
44
+ citationKeys: Object.keys(citations), // frontmatterのキーの順番を保持
45
+ initialized: false
46
+ }
47
+ }
48
+
49
+ // frontmatterの順番でcitation番号を事前に割り当て
50
+ const initializeCitations = () => {
51
+ if (!window.citationManager.initialized) {
52
+ window.citationManager.citationKeys = Object.keys(citations)
53
+
54
+ window.citationManager.citationKeys.forEach((key, index) => {
55
+ if (!window.citationManager.citations.has(key)) {
56
+ const data = citations[key]
57
+ const newCitation = {
58
+ number: index + 1, // 1から開始
59
+ data: data,
60
+ formatted: formatCitation(data)
61
+ }
62
+ window.citationManager.citations.set(key, newCitation)
63
+ }
64
+ })
65
+
66
+ window.citationManager.initialized = true
45
67
  }
46
68
  }
47
69
 
@@ -59,24 +81,21 @@ const citationData = computed(() => {
59
81
  return data
60
82
  })
61
83
 
62
- // 引用番号を取得または生成
84
+ // 引用番号を取得
63
85
  const citationNumber = computed(() => {
64
86
  if (!citationData.value) {
65
87
  return '?'
66
88
  }
67
89
 
68
- if (!window.citationManager.citations.has(props.id)) {
69
- const newCitation = {
70
- number: window.citationManager.counter,
71
- data: citationData.value,
72
- formatted: formatCitation(citationData.value)
73
- }
74
- window.citationManager.citations.set(props.id, newCitation)
75
- window.citationManager.counter++
76
- }
90
+ // 初期化を確実に実行
91
+ initializeCitations()
77
92
 
78
93
  const citation = window.citationManager.citations.get(props.id)
79
- return citation.number
94
+ if (citation) {
95
+ return citation.number
96
+ }
97
+
98
+ return '?'
80
99
  })
81
100
 
82
101
  // フォーマットされた引用テキスト
@@ -96,7 +115,6 @@ const formattedCitation = computed(() => {
96
115
  // 引用を表示すべきかどうか
97
116
  const shouldShowCitation = computed(() => {
98
117
  const shouldShow = isMounted.value && citationData.value !== null
99
-
100
118
  return shouldShow
101
119
  })
102
120
 
@@ -158,30 +176,30 @@ const formatCitation = (data) => {
158
176
  }
159
177
 
160
178
  const formatted = citation || '引用情報が不完全です'
161
-
162
179
  return formatted
163
180
  }
164
181
 
165
182
  // 全体のグローバル状態をデバッグ出力
166
183
  const debugGlobalState = () => {
184
+ // デバッグ用(必要に応じてコメントアウト)
167
185
  }
168
186
 
169
187
  // コンポーネントのマウント時
170
188
  onMounted(() => {
171
-
172
189
  isMounted.value = true
173
190
 
191
+ // 初期化を確実に実行
192
+ initializeCitations()
193
+
174
194
  if (citationData.value) {
175
- // 引用番号を生成(副作用でglobal stateに保存される)
195
+ // 引用番号を取得(副作用でglobal stateに保存される)
176
196
  const _ = citationNumber.value
177
197
  debugGlobalState()
178
- } else {
179
198
  }
180
199
  })
181
200
 
182
201
  // コンポーネントのアンマウント時
183
202
  onUnmounted(() => {
184
-
185
203
  isMounted.value = false
186
204
  debugGlobalState()
187
205
  })
@@ -17,9 +17,9 @@
17
17
  :key="citation.key"
18
18
  class="citation-item border-l-2 border-sky-400 pl-3 py-1"
19
19
  >
20
- <!-- 引用キー -->
20
+ <!-- 引用番号(frontmatterの順番に基づく) -->
21
21
  <div class="text-sm font-semibold text-sky-700 mb-1">
22
- [{{ citation.key }}]
22
+ [{{ citation.number }}]
23
23
  </div>
24
24
 
25
25
  <!-- 引用情報 -->
@@ -164,19 +164,23 @@ const props = defineProps({
164
164
  // 表示順序
165
165
  sortBy: {
166
166
  type: String,
167
- default: 'key', // 'key', 'author', 'year' など
167
+ default: 'frontmatter', // 'frontmatter', 'key', 'author', 'year' など
168
168
  }
169
169
  })
170
170
 
171
- // 参考文献リストを生成
171
+ // 参考文献リストを生成(frontmatterの順番を維持)
172
172
  const citationsList = computed(() => {
173
173
  if (!citations || typeof citations !== 'object') {
174
174
  return []
175
175
  }
176
176
 
177
- const list = Object.keys(citations).map(key => ({
177
+ // frontmatterの記述順でキーを取得
178
+ const originalKeys = Object.keys(citations)
179
+
180
+ const list = originalKeys.map((key, index) => ({
178
181
  key,
179
- data: citations[key]
182
+ data: citations[key],
183
+ number: index + 1 // frontmatterの順番に基づく番号
180
184
  }))
181
185
 
182
186
  // ソート処理
@@ -194,8 +198,11 @@ const citationsList = computed(() => {
194
198
  return yearB - yearA // 降順(新しい順)
195
199
  })
196
200
  case 'key':
197
- default:
198
201
  return list.sort((a, b) => a.key.localeCompare(b.key))
202
+ case 'frontmatter':
203
+ default:
204
+ // frontmatterの順番を維持(デフォルト)
205
+ return list
199
206
  }
200
207
  })
201
208
 
@@ -269,8 +269,8 @@ const sizeConfigs = {
269
269
  columns: 2,
270
270
  headerPadding: 'pt-14 pb-8 px-10',
271
271
  headerTitle: 'text-5xl',
272
- mainPadding: 'px-12 py-12',
273
- gridGap: 'gap-x-16 gap-y-8',
272
+ mainPadding: 'px-6 py-40',
273
+ gridGap: 'gap-x-12 gap-y-2',
274
274
  chapterNumber: 'text-6xl',
275
275
  chapterTitle: 'text-2xl',
276
276
  chapterHeader: 'mb-4',
package/layouts/cover.vue CHANGED
@@ -1,33 +1,54 @@
1
1
  <template>
2
- <div class="slidev-layout cover relative overflow-hidden bg-gradient-to-br from-white via-gray-100 to-sky-200">
3
- <!-- 大きな円形要素(右上) -->
4
- <div class="absolute -right-32 -top-32 w-96 h-96 bg-sky-300/70 rounded-full" />
5
- <div class="absolute right-8 top-24 w-64 h-64 bg-sky-400/60 rounded-full" />
2
+ <div class="slidev-layout cover relative overflow-hidden animated-gradient">
3
+ <!-- ランダムに動く大きな円形要素(右上) -->
4
+ <div
5
+ ref="circle1"
6
+ class="absolute -right-32 -top-32 w-96 h-96 bg-sky-300/70 rounded-full transition-all duration-[3000ms] ease-in-out"
7
+ :style="circleStyles[0]"
8
+ />
9
+ <div
10
+ ref="circle2"
11
+ class="absolute right-8 top-24 w-64 h-64 bg-sky-400/60 rounded-full transition-all duration-[4000ms] ease-in-out"
12
+ :style="circleStyles[1]"
13
+ />
6
14
 
7
- <!-- 左下の三角形要素 -->
8
- <div class="absolute left-16 bottom-16 w-0 h-0 border-l-48 border-r-48 border-b-80 border-transparent border-b-sky-400/50" />
9
- <div class="absolute left-32 bottom-32 w-0 h-0 border-l-32 border-r-32 border-b-56 border-transparent border-b-sky-500/55" />
15
+ <!-- ランダムに動く左下の三角形要素 -->
16
+ <div
17
+ class="absolute left-16 bottom-16 w-0 h-0 border-l-48 border-r-48 border-b-80 border-transparent border-b-sky-400/50 transition-all duration-[3500ms] ease-in-out"
18
+ :style="triangleStyles[0]"
19
+ />
20
+ <div
21
+ class="absolute left-32 bottom-32 w-0 h-0 border-l-32 border-r-32 border-b-56 border-transparent border-b-sky-500/55 transition-all duration-[4500ms] ease-in-out"
22
+ :style="triangleStyles[1]"
23
+ />
10
24
 
11
-
12
- <!-- 右下の斜線要素 -->
13
- <div class="absolute right-25 bottom-5 transform -translate-y-1/2 rotate-60 space-y-8">
14
- <div class="w-48 h-3 rounded-md bg-sky-500/70" />
15
- <div class="w-36 h-3 rounded-md bg-sky-500/70" />
16
- <div class="w-48 h-3 rounded-md bg-sky-500/70" />
17
- <div class="w-24 h-3 rounded-md bg-sky-500/70" />
25
+ <!-- ランダムに動く右下の斜線要素 -->
26
+ <div
27
+ class="absolute right-25 bottom-5 space-y-8 transition-all duration-[5000ms] ease-in-out"
28
+ :style="linesStyle"
29
+ >
30
+ <div
31
+ v-for="(width, index) in lineWidths"
32
+ :key="index"
33
+ class="h-3 rounded-md bg-sky-500/70 transition-all duration-[2000ms] ease-in-out"
34
+ :style="{ width: `${width}px` }"
35
+ />
18
36
  </div>
19
37
 
20
- <!-- 左上の円形グリッド(より濃く) -->
21
- <div class="absolute left-16 top-16 grid grid-cols-3 gap-3 opacity-60">
22
- <div class="w-8 h-8 bg-sky-600 rounded-full" />
23
- <div class="w-8 h-8 border-2 border-sky-700 rounded-full" />
24
- <div class="w-8 h-8 bg-sky-600 rounded-full" />
25
- <div class="w-8 h-8 bg-sky-600 rounded-full" />
26
- <div class="w-8 h-8 bg-sky-600 rounded-full" />
27
- <div class="w-8 h-8 border-2 border-sky-700 rounded-full" />
28
- <div class="w-8 h-8 border-2 border-sky-700 rounded-full" />
29
- <div class="w-8 h-8 bg-sky-600 rounded-full" />
30
- <div class="w-8 h-8 bg-sky-600 rounded-full" />
38
+ <!-- ランダムに動く左上の円形グリッド -->
39
+ <div
40
+ class="absolute left-16 top-16 grid grid-cols-3 gap-3 opacity-60 rotating-grid"
41
+ :style="gridStyle"
42
+ >
43
+ <div
44
+ v-for="(dot, index) in dots"
45
+ :key="index"
46
+ :class="[
47
+ 'w-8 h-8 rounded-full transition-all duration-[2500ms] ease-in-out',
48
+ dot.filled ? 'bg-sky-600' : 'border-2 border-sky-700'
49
+ ]"
50
+ :style="dot.style"
51
+ />
31
52
  </div>
32
53
 
33
54
  <!-- メインコンテンツ -->
@@ -38,10 +59,10 @@
38
59
  {{ $slidev.configs.meetingName }}
39
60
  </div>
40
61
 
41
- <!-- メインタイトル(サイズ指定可能) -->
62
+ <!-- メインタイトル -->
42
63
  <div
43
64
  :class="[
44
- 'font-bold text-slate-900 leading-tight',
65
+ 'font-bold text-slate-900 leading-tight ',
45
66
  getTitleSizeClass($slidev.configs.titleSize || 'large')
46
67
  ]"
47
68
  >
@@ -59,14 +80,24 @@
59
80
  </div>
60
81
 
61
82
  <!-- 著者情報 -->
62
- <div class="space-y-2">
63
- <div class="text-2xl font-semibold text-slate-800">
64
- {{ $slidev.configs.author.affiliation }}
65
- </div>
66
- <div class="text-2xl font-bold text-slate-900">
67
- {{ $slidev.configs.author.name }}
83
+ <div class="space-y-4">
84
+ <div class="flex flex-col items-end justify-between w-full w-full px-20">
85
+ <div class="text-2xl font-semibold text-slate-800 ">
86
+ {{ $slidev.configs.author.affiliation }}<span class="text-sky-600 ml-2">*</span>{{ $slidev.configs.author.name }}
87
+ </div>
88
+
89
+ <!-- 共著者 (存在する場合) -->
90
+ <div v-if="coAuthors.length > 0" class="space-y-1 flex flex-col items-end">
91
+ <div
92
+ v-for="(coAuthor, index) in coAuthors"
93
+ :key="index"
94
+ class="text-2xl font-semibold text-slate-800"
95
+ >
96
+ <span class="mr-2"> {{ coAuthor.affiliation }}</span> {{ coAuthor.name }}
97
+ </div>
98
+ </div>
68
99
  </div>
69
- <!-- 日付 -->
100
+
70
101
  <div class="text-xl font-semibold text-slate-700">
71
102
  {{ $slidev.configs.date }}
72
103
  </div>
@@ -82,6 +113,11 @@
82
113
  </template>
83
114
 
84
115
  <script setup>
116
+ import { ref, computed, onMounted, onUnmounted } from 'vue'
117
+ import { useSlideContext } from '@slidev/client'
118
+
119
+ const { $slidev } = useSlideContext()
120
+
85
121
  // タイトルサイズのクラスを返す関数
86
122
  function getTitleSizeClass(size) {
87
123
  const sizeMap = {
@@ -94,4 +130,150 @@ function getTitleSizeClass(size) {
94
130
 
95
131
  return sizeMap[size] || sizeMap['large']
96
132
  }
97
- </script>
133
+
134
+ // 共著者リストを取得
135
+ const coAuthors = computed(() => {
136
+ const configs = $slidev.configs
137
+ if (!configs || !configs.coAuthors || !Array.isArray(configs.coAuthors)) {
138
+ return []
139
+ }
140
+ console.log(configs.coAuthors)
141
+ // 最大4人まで
142
+ return configs.coAuthors.slice(0, 4)
143
+ })
144
+
145
+ // ランダムな値を生成する関数
146
+ const randomRange = (min, max) => Math.random() * (max - min) + min
147
+
148
+ // 初期状態でランダムな位置を設定
149
+ const circleStyles = ref([
150
+ { transform: `translate(${randomRange(-15, 15)}px, ${randomRange(-15, 15)}px) rotate(${randomRange(-5, 5)}deg)` },
151
+ { transform: `translate(${randomRange(-20, 20)}px, ${randomRange(-20, 20)}px) rotate(${randomRange(-8, 8)}deg)` }
152
+ ])
153
+
154
+ const triangleStyles = ref([
155
+ { transform: `translate(${randomRange(-10, 10)}px, ${randomRange(-10, 10)}px) rotate(${randomRange(-3, 3)}deg)` },
156
+ { transform: `translate(${randomRange(-12, 12)}px, ${randomRange(-12, 12)}px) rotate(${randomRange(-4, 4)}deg)` }
157
+ ])
158
+
159
+ const linesStyle = ref({
160
+ transform: `translate(${randomRange(-15, 15)}px, ${randomRange(-15, 15)}px) rotate(${randomRange(55, 65)}deg)`
161
+ })
162
+
163
+ const lineWidths = ref([
164
+ randomRange(180, 204),
165
+ randomRange(130, 158),
166
+ randomRange(180, 204),
167
+ randomRange(85, 107)
168
+ ])
169
+
170
+ const gridStyle = ref({})
171
+
172
+ const dots = ref([
173
+ { filled: true, style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
174
+ { filled: false, style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
175
+ { filled: true, style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
176
+ { filled: true, style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
177
+ { filled: true, style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
178
+ { filled: false, style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
179
+ { filled: false, style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
180
+ { filled: true, style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
181
+ { filled: true, style: { transform: `scale(${randomRange(0.85, 1.15)})` } }
182
+ ])
183
+
184
+ // アニメーション更新関数
185
+ const updateAnimations = () => {
186
+ // 円形要素をランダムに動かす
187
+ circleStyles.value[0] = {
188
+ transform: `translate(${randomRange(-15, 15)}px, ${randomRange(-15, 15)}px) rotate(${randomRange(-5, 5)}deg)`
189
+ }
190
+ circleStyles.value[1] = {
191
+ transform: `translate(${randomRange(-20, 20)}px, ${randomRange(-20, 20)}px) rotate(${randomRange(-8, 8)}deg)`
192
+ }
193
+
194
+ // 三角形要素をランダムに動かす
195
+ triangleStyles.value[0] = {
196
+ transform: `translate(${randomRange(-10, 10)}px, ${randomRange(-10, 10)}px) rotate(${randomRange(-3, 3)}deg)`
197
+ }
198
+ triangleStyles.value[1] = {
199
+ transform: `translate(${randomRange(-12, 12)}px, ${randomRange(-12, 12)}px) rotate(${randomRange(-4, 4)}deg)`
200
+ }
201
+
202
+ // 斜線要素をランダムに動かす
203
+ linesStyle.value = {
204
+ transform: `translate(${randomRange(-15, 15)}px, ${randomRange(-15, 15)}px) rotate(${randomRange(55, 65)}deg)`
205
+ }
206
+
207
+ // 斜線の幅をランダムに変更
208
+ lineWidths.value = [
209
+ randomRange(180, 204),
210
+ randomRange(130, 158),
211
+ randomRange(180, 204),
212
+ randomRange(85, 107)
213
+ ]
214
+
215
+ // ドットをランダムにスケール変更
216
+ dots.value = dots.value.map(dot => ({
217
+ ...dot,
218
+ style: {
219
+ transform: `scale(${randomRange(0.85, 1.15)})`
220
+ }
221
+ }))
222
+ }
223
+
224
+ let intervalId = null
225
+
226
+ onMounted(() => {
227
+ // 即座に最初のアニメーションを開始
228
+ setTimeout(() => {
229
+ updateAnimations()
230
+ }, 100)
231
+
232
+ // 定期的にアニメーションを更新(3秒ごと)
233
+ intervalId = setInterval(() => {
234
+ updateAnimations()
235
+ }, 3000)
236
+ })
237
+
238
+ onUnmounted(() => {
239
+ if (intervalId) {
240
+ clearInterval(intervalId)
241
+ }
242
+ })
243
+ </script>
244
+
245
+ <style scoped>
246
+ /* グラデーション背景のアニメーション */
247
+ @keyframes gradient-shift {
248
+ 0% {
249
+ background: linear-gradient(to bottom right, white, #f3f4f6, #e0f2fe);
250
+ }
251
+ 33% {
252
+ background: linear-gradient(to bottom right, white, #eff6ff, #dbeafe);
253
+ }
254
+ 66% {
255
+ background: linear-gradient(to bottom right, white, #f3f4f6, #dbeafe);
256
+ }
257
+ 100% {
258
+ background: linear-gradient(to bottom right, white, #f3f4f6, #e0f2fe);
259
+ }
260
+ }
261
+
262
+ .animated-gradient {
263
+ animation: gradient-shift 20s ease-in-out infinite;
264
+ }
265
+
266
+ /* グリッドの常時回転アニメーション */
267
+ @keyframes rotate-continuously {
268
+ from {
269
+ transform: rotate(0deg);
270
+ }
271
+ to {
272
+ transform: rotate(360deg);
273
+ }
274
+ }
275
+
276
+ .rotating-grid {
277
+ animation: rotate-continuously 120s linear infinite;
278
+ }
279
+ </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slidev-theme-gtlabo",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "A Slidev theme for laboratory presentations with customizable components",
5
5
  "author": "mksmkss",
6
6
  "license": "MIT",
package/uno.config.ts CHANGED
@@ -6,8 +6,8 @@ export default defineConfig({
6
6
  md: '1rem',
7
7
  },
8
8
  colors: {
9
- 'text-main': 'rgba(31, 41, 55, 1)',
10
- 'theme-color': 'rgba(2, 132, 199, 1)',
9
+ 'text-main': '#1f2937',
10
+ 'theme-color': '#0284c7',
11
11
  },
12
12
  },
13
13
  })