slidev-theme-gtlabo 1.1.1 → 2.0.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.
@@ -0,0 +1,93 @@
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>
@@ -1,24 +1,278 @@
1
+ <!-- components/SectionDivider.vue -->
1
2
  <template>
2
- <!-- セクション区切り用の目次ページ -->
3
- <TableOfContents
4
- :next-chapter="nextChapter"
5
- :current-chapter="currentChapter"
6
- />
3
+ <div class="table-of-contents-container flex flex-col justify-start bg-white overflow-hidden relative">
4
+ <!-- 厳密な背景グリッド - Swiss Styleの基礎 -->
5
+ <div class="absolute inset-0 z-0 pointer-events-none opacity-10"
6
+ style="background-image: linear-gradient(#0f172a 1px, transparent 1px), linear-gradient(to right, #0f172a 1px, transparent 1px); background-size: 50px 50px;">
7
+ </div>
8
+
9
+ <!-- 非対称の幾何学的構成要素 - 左上の強調 -->
10
+ <div class="absolute top-0 left-0 w-2 h-32 bg-slate-900 z-5"></div>
11
+ <div class="absolute top-0 left-0 w-32 h-2 bg-slate-900 z-5"></div>
12
+
13
+ <!-- 非対称の幾何学的構成要素 - 右下のアクセント -->
14
+ <div class="absolute bottom-0 right-0 w-48 h-2 bg-slate-900 z-5"></div>
15
+ <div class="absolute bottom-12 right-0 w-1 h-48 bg-slate-900 opacity-30 z-5"></div>
16
+
17
+ <!-- 右側の装飾バー群 - cover.vueと同じスタイル -->
18
+ <div class="absolute right-0 top-0 w-1/4 h-full z-0 pointer-events-none">
19
+ <div class="absolute right-0 top-0 w-full h-full bg-gradient-to-l from-slate-200 to-slate-200/10" />
20
+ <div class="absolute right-[15%] top-0 w-32 h-[35%] bg-sky-600/10" />
21
+ <div class="absolute right-0 bottom-0 w-2 h-[40%] bg-slate-900" />
22
+ </div>
23
+
24
+ <!-- 機能的なsky-500のアクセントブロック -->
25
+ <div class="absolute right-0 top-1/4 w-[12%] h-24 bg-sky-500/30 z-5"></div>
26
+
27
+ <!-- ヘッダー - 付録セクション用 -->
28
+ <div
29
+ v-if="isAppendixSection"
30
+ :class="headerClasses"
31
+ class="relative z-10"
32
+ >
33
+ <div class="flex items-start space-x-6">
34
+ <div :class="headerTitleClasses" class="font-bold uppercase tracking-widest text-slate-800 leading-none">
35
+ APPENDIX
36
+ </div>
37
+ </div>
38
+ </div>
39
+
40
+ <!-- メインコンテンツ - 厳密なグリッドベース -->
41
+ <div :class="mainContentClasses" class="relative z-10">
42
+ <div class="max-w-full w-full">
43
+ <!-- 共通の目次表示 -->
44
+ <div :class="gridClasses">
45
+ <ChapterItem
46
+ v-for="(chapter, index) in displayChapters"
47
+ :key="chapter.key"
48
+ :chapter="chapter"
49
+ :index="index"
50
+ :is-next="isNextChapter(chapter.key)"
51
+ :is-appendix="isAppendixSection"
52
+ :size="size"
53
+ :config="currentConfig"
54
+ />
55
+ </div>
56
+ </div>
57
+ </div>
58
+
59
+ <!-- タイポグラフィックな署名 - 客観性の表明 -->
60
+ <div class="absolute bottom-4 left-6 text-[10px] font-mono text-slate-800 uppercase tracking-widest z-20">
61
+ CONTENTS
62
+ </div>
63
+ </div>
7
64
  </template>
8
-
65
+
9
66
  <script setup>
10
- import TableOfContents from './TableOfContents.vue'
67
+ import { computed } from 'vue'
68
+ import { useSlideContext } from '@slidev/client'
69
+ import ChapterItem from './ChapterItem.vue'
70
+
71
+ // Slidevコンテキストからconfigsにアクセス
72
+ const { $slidev } = useSlideContext()
73
+ const chapters = $slidev.configs.chapters || {}
11
74
 
12
75
  const props = defineProps({
13
- nextChapter: {
76
+ nextChapter: {
14
77
  type: String,
15
78
  required: true,
16
79
  description: '次に始まる章のキー(例: "c2", "c3", "ap1")'
17
- },
18
- currentChapter: {
80
+ },
81
+ currentChapter: {
19
82
  type: String,
20
83
  required: false,
21
84
  description: '現在の章のキー(進捗表示用)'
85
+ },
86
+ size: {
87
+ type: String,
88
+ default: 'md',
89
+ validator: (value) => ['xs', 'sm', 'md', 'lg', 'xl'].includes(value),
90
+ description: '目次のサイズ(xs, sm, md, lg, xl)'
91
+ }
92
+ })
93
+
94
+ // セクションの重複を除去する関数
95
+ const getUniqueSections = (chapterKey) => {
96
+ const chapter = chapters[chapterKey]
97
+ if (!chapter?.sections) return []
98
+
99
+ const sections = chapter.sections
100
+ const sectionKeys = Object.keys(sections)
101
+ const uniqueSections = []
102
+ let previousTitle = null
103
+
104
+ for (const sectionKey of sectionKeys) {
105
+ const sectionData = sections[sectionKey]
106
+ const currentTitle = sectionData?.title || `セクション ${sectionKey}`
107
+
108
+ // 前のセクションと同じタイトルでない場合のみ追加
109
+ if (currentTitle !== previousTitle) {
110
+ uniqueSections.push({
111
+ key: sectionKey,
112
+ title: currentTitle,
113
+ originalData: sectionData
114
+ })
115
+ previousTitle = currentTitle
116
+ }
117
+ }
118
+
119
+ return uniqueSections
22
120
  }
121
+
122
+ // 次の章が付録かどうかを判定
123
+ const isAppendixSection = computed(() => {
124
+ return props.nextChapter.startsWith('ap')
23
125
  })
24
- </script>
126
+
127
+ // 章リストを取得する共通関数
128
+ const getChapterList = (filterFn) => {
129
+ if (!chapters || typeof chapters !== 'object') {
130
+ return []
131
+ }
132
+
133
+ return Object.keys(chapters)
134
+ .filter(filterFn)
135
+ .map(chapterKey => {
136
+ const chapter = chapters[chapterKey]
137
+ const sections = chapter?.sections || {}
138
+ const sectionKeys = Object.keys(sections)
139
+
140
+ return {
141
+ key: chapterKey,
142
+ title: chapter?.title || `章 ${chapterKey}`,
143
+ sections: sectionKeys,
144
+ sectionData: sections,
145
+ uniqueSections: getUniqueSections(chapterKey)
146
+ }
147
+ })
148
+ }
149
+
150
+ // 通常の章リスト(refと付録を除外)
151
+ const regularChapters = computed(() =>
152
+ getChapterList(chapterKey => chapterKey !== 'ref' && !chapterKey.startsWith('ap'))
153
+ )
154
+
155
+ // 付録の章リスト
156
+ const appendixChapters = computed(() =>
157
+ getChapterList(chapterKey => chapterKey.startsWith('ap'))
158
+ )
159
+
160
+ // 表示する章リスト(条件に応じて切り替え)
161
+ const displayChapters = computed(() =>
162
+ isAppendixSection.value ? appendixChapters.value : regularChapters.value
163
+ )
164
+
165
+ // 次の章かどうかを判定
166
+ const isNextChapter = (chapterKey) => {
167
+ return props.nextChapter === chapterKey
168
+ }
169
+
170
+ // サイズ設定
171
+ const sizeConfigs = {
172
+ xs: {
173
+ columns: 4,
174
+ headerPadding: 'pt-3 pb-1 px-6',
175
+ headerTitle: 'text-lg',
176
+ mainPadding: 'px-6 py-6',
177
+ gridGap: 'gap-x-4 gap-y-4',
178
+ chapterNumber: 'text-2xl',
179
+ chapterTitle: 'text-[11px]',
180
+ chapterHeader: 'mb-2',
181
+ sectionList: 'mt-2 space-y-1',
182
+ sectionText: 'text-[9px]',
183
+ appendixNumber: 'text-xl',
184
+ nextBadge: 'mb-2 px-1.5 py-0.5 text-[8px]'
185
+ },
186
+ sm: {
187
+ columns: 3,
188
+ headerPadding: 'pt-6 pb-2 px-8',
189
+ headerTitle: 'text-xl',
190
+ mainPadding: 'px-8 py-8',
191
+ gridGap: 'gap-x-6 gap-y-5',
192
+ chapterNumber: 'text-3xl',
193
+ chapterTitle: 'text-xs',
194
+ chapterHeader: 'mb-2.5',
195
+ sectionList: 'mt-2.5 space-y-1',
196
+ sectionText: 'text-[10px]',
197
+ appendixNumber: 'text-2xl',
198
+ nextBadge: 'mb-2.5 px-2 py-0.5 text-[9px]'
199
+ },
200
+ md: {
201
+ columns: 2,
202
+ headerPadding: 'pt-12 px-12',
203
+ headerTitle: 'text-3xl',
204
+ mainPadding: 'px-12 py-14',
205
+ gridGap: 'gap-x-12 gap-y-6',
206
+ chapterNumber: 'text-6xl',
207
+ chapterTitle: 'text-2xl',
208
+ chapterHeader: 'mb-3',
209
+ sectionList: 'mt-3 space-y-1.5',
210
+ sectionText: 'text-lg',
211
+ appendixNumber: 'text-4xl',
212
+ nextBadge: 'mb-3 px-2.5 py-1 text-md'
213
+ },
214
+ lg: {
215
+ columns: 2,
216
+ headerPadding: 'pt-8 pb-4 px-16',
217
+ headerTitle: 'text-4xl',
218
+ mainPadding: 'px-16 py-18',
219
+ gridGap: 'gap-x-16 gap-y-8',
220
+ chapterNumber: 'text-7xl',
221
+ chapterTitle: 'text-xl',
222
+ chapterHeader: 'mb-4',
223
+ sectionList: 'mt-4 space-y-2',
224
+ sectionText: 'text-base',
225
+ appendixNumber: 'text-5xl',
226
+ nextBadge: 'mb-4 px-3 py-1.5 text-xs'
227
+ },
228
+ xl: {
229
+ columns: 1,
230
+ headerPadding: 'pt-10 pb-5 px-20',
231
+ headerTitle: 'text-6xl',
232
+ mainPadding: 'px-20 py-24',
233
+ gridGap: 'gap-x-20 gap-y-12',
234
+ chapterNumber: 'text-8xl',
235
+ chapterTitle: 'text-3xl',
236
+ chapterHeader: 'mb-6',
237
+ sectionList: 'mt-6 space-y-3',
238
+ sectionText: 'text-xl',
239
+ appendixNumber: 'text-7xl',
240
+ nextBadge: 'mb-6 px-4 py-2 text-sm'
241
+ }
242
+ }
243
+
244
+ const currentConfig = computed(() => sizeConfigs[props.size])
245
+
246
+ // 動的クラス
247
+ const headerClasses = computed(() => `text-left ${currentConfig.value.headerPadding}`)
248
+ const headerTitleClasses = computed(() => currentConfig.value.headerTitle)
249
+ const mainContentClasses = computed(() => `flex-1 ${currentConfig.value.mainPadding}`)
250
+ const gridClasses = computed(() => `grid grid-cols-${currentConfig.value.columns} ${currentConfig.value.gridGap}`)
251
+ </script>
252
+
253
+ <style scoped>
254
+ /* このコンポーネント専用のスタイル */
255
+ .table-of-contents-container {
256
+ position: absolute !important;
257
+ top: 0 !important;
258
+ left: 50% !important;
259
+ transform: translateX(-50%) !important;
260
+ width: 100% !important;
261
+ height: 100% !important;
262
+ margin: 0 !important;
263
+ box-sizing: border-box !important;
264
+ z-index: 0 !important;
265
+ }
266
+
267
+ /* タイポグラフィの最適化 - Swiss Styleの核心 */
268
+ div, span, h2, p {
269
+ font-feature-settings: "palt", "kern";
270
+ -webkit-font-smoothing: antialiased;
271
+ -moz-osx-font-smoothing: grayscale;
272
+ }
273
+
274
+ /* タブラーナンバーの最適化 */
275
+ .tabular-nums {
276
+ font-variant-numeric: tabular-nums;
277
+ }
278
+ </style>
@@ -1,3 +1,4 @@
1
+ <!-- components/TableOfContents.vue -->
1
2
  <template>
2
3
  <div class="table-of-contents-container flex flex-col justify-center bg-theme-color">
3
4
  <!-- ヘッダー -->
package/layouts/cover.vue CHANGED
@@ -1,279 +1,194 @@
1
1
  <template>
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
- />
2
+ <div class="slidev-layout cover relative w-full h-full !p-0 bg-white overflow-hidden font-sans text-slate-900 selection:bg-sky-200 selection:text-sky-900">
14
3
 
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
- />
24
-
25
- <!-- ランダムに動く右下の斜線要素 -->
26
- <div
27
- class="absolute right-25 bottom-5 space-y-8 transition-all duration-[5000ms] ease-in-out"
28
- :style="linesStyle"
29
- >
4
+ <div class="absolute inset-0 z-0 pointer-events-none opacity-10"
5
+ style="background-image: linear-gradient(#0f172a 1px, transparent 1px), linear-gradient(to right, #0f172a 1px, transparent 1px); background-size: 50px 50px;">
6
+ </div>
7
+
8
+ <div class="absolute -top-[20%] -right-[10%] w-[80vh] h-[80vh] z-0 pointer-events-none opacity-20">
9
+ <div class="absolute inset-0 border-3 border-dashed border-slate-700 rounded-full animate-spin-super-slow"></div>
10
+ <div class="absolute inset-[15%] border-3 border-dotted border-sky-700 rounded-full animate-reverse-spin-slow"></div>
11
+
12
+ </div>
13
+
14
+ <div class="absolute bottom-[10%] left-[5%] w-32 h-32 z-0 pointer-events-none opacity-30">
15
+ <svg class="w-full h-full animate-spin-slow text-sky-800" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
16
+ <circle cx="50" cy="50" r="48" stroke="currentColor" stroke-width="0.8" stroke-dasharray="4 4" />
17
+ <rect x="49.5" y="10" width="1" height="80" fill="currentColor" />
18
+ <rect x="10" y="49.5" width="80" height="1" fill="currentColor" />
19
+ </svg>
20
+ </div>
21
+ <div class="absolute right-0 top-0 w-1/3 h-full z-0 pointer-events-none">
30
22
  <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` }"
23
+ class="absolute right-0 top-0 w-full h-full bg-slate-50 transform origin-right transition-transform duration-[1500ms] ease-expo-out"
24
+ :class="mounted ? 'scale-x-100' : 'scale-x-0'"
25
+ />
26
+ <div
27
+ class="absolute right-[15%] top-0 w-32 h-full bg-sky-600/10 transform origin-top transition-transform duration-[2000ms] ease-expo-out delay-100"
28
+ :class="mounted ? 'scale-y-100' : 'scale-y-0'"
35
29
  />
36
- </div>
37
-
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
30
  <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"
31
+ class="absolute right-[25%] bottom-0 w-4 h-2/3 bg-slate-900 transform origin-bottom transition-transform duration-[2000ms] ease-expo-out delay-300"
32
+ :class="mounted ? 'scale-y-100' : 'scale-y-0'"
33
+ />
34
+ <div
35
+ class="absolute right-0 top-1/4 w-1/2 h-24 bg-sky-500 transform origin-right transition-all duration-[2500ms] ease-in-out delay-500"
36
+ :class="mounted ? 'translate-x-0 opacity-100' : 'translate-x-full opacity-0'"
51
37
  />
52
38
  </div>
53
-
54
- <!-- メインコンテンツ -->
55
- <div class="relative z-10 flex flex-col justify-center items-start px-8 py-12">
56
- <div class="max-w-4xl w-full space-y-6">
57
- <!-- 会議名 -->
58
- <div class="text-2xl font-semibold text-slate-700">
59
- {{ $slidev.configs.meetingName }}
60
- </div>
39
+
40
+ <div class="relative z-10 flex flex-col justify-between h-full pl-16 pr-12 py-16 w-full">
41
+
42
+ <div class="flex flex-col items-start space-y-4">
43
+ <div
44
+ class="w-24 h-2 bg-slate-900 transition-all duration-1000 ease-out"
45
+ :class="mounted ? 'w-24 opacity-100' : 'w-0 opacity-0'"
46
+ />
61
47
 
62
- <!-- メインタイトル -->
48
+ <div class="space-y-2 ml-4">
49
+ <div class="overflow-hidden">
50
+ <div
51
+ class="text-lg font-bold tracking-widest uppercase text-slate-800 transition-transform duration-1000 ease-out delay-300"
52
+ :class="mounted ? 'translate-y-0' : 'translate-y-full'"
53
+ >
54
+ {{ $slidev.configs.meetingName }}
55
+ </div>
56
+ </div>
57
+ <div class="overflow-hidden">
58
+ <div
59
+ class="text-base font-mono text-sky-800 transition-transform duration-1000 ease-out delay-400"
60
+ :class="mounted ? 'translate-y-0' : 'translate-y-full'"
61
+ >
62
+ {{ $slidev.configs.date }}
63
+ </div>
64
+ </div>
65
+ </div>
66
+ </div>
67
+
68
+ <div class="space-y-6 py-8 w-full">
63
69
  <div
64
70
  :class="[
65
- 'font-bold text-slate-900 leading-tight ',
66
- getTitleSizeClass($slidev.configs.titleSize || 'large')
71
+ 'font-bold text-slate-900 leading-[0.9] tracking-tight transition-all duration-1000 ease-out delay-500 w-full !max-w-none break-words space-y-6',
72
+ getTitleSizeClass($slidev.configs.titleSize || 'large'),
73
+ mounted ? 'opacity-100 translate-x-0' : 'opacity-0 -translate-x-8'
67
74
  ]"
68
75
  >
69
76
  <template v-if="Array.isArray($slidev.configs.coverTitle)">
70
- <span v-for="(line, index) in $slidev.configs.coverTitle" :key="index">
77
+ <span v-for="(line, index) in $slidev.configs.coverTitle" :key="index" class="block">
71
78
  {{ line }}
72
- <br v-if="index < $slidev.configs.coverTitle.length - 1">
73
79
  </span>
74
80
  </template>
75
81
  <template v-else>
76
- {{ $slidev.configs.coverTitle.first }}
77
- <br>
78
- {{ $slidev.configs.coverTitle.second }}
82
+ <span class="block">{{ $slidev.configs.coverTitle.first }}</span>
83
+ <span class="block text-slate-500">{{ $slidev.configs.coverTitle.second }}</span>
79
84
  </template>
80
85
  </div>
86
+ </div>
87
+
88
+ <div class="flex flex-col space-y-6 pt-8 transition-opacity duration-1000 delay-700 w-full"
89
+ :class="mounted ? 'opacity-100' : 'opacity-0'">
81
90
 
82
- <!-- 著者情報 -->
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 }}
91
+ <div class="grid grid-cols-2 gap-12">
92
+ <div>
93
+ <div class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-1">Presenter</div>
94
+ <div class="text-2xl font-bold text-slate-900 whitespace-nowrap">
95
+ {{ $slidev.configs.author.name }}
96
+ </div>
97
+ <div class="text-sm font-medium text-sky-700 mt-1">
98
+ {{ $slidev.configs.author.affiliation }}
87
99
  </div>
88
-
89
- <!-- 共著者 (存在する場合) -->
90
- <div v-if="coAuthors.length > 0" class="space-y-1 flex flex-col items-end">
100
+ </div>
101
+
102
+ <div v-if="coAuthors.length > 0">
103
+ <div class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-1">Co-Authors</div>
104
+ <div class="space-y-2">
91
105
  <div
92
106
  v-for="(coAuthor, index) in coAuthors"
93
107
  :key="index"
94
- class="text-2xl font-semibold text-slate-800"
108
+ class="flex flex-col"
95
109
  >
96
- <span class="mr-2"> {{ coAuthor.affiliation }}</span> {{ coAuthor.name }}
110
+ <span class="text-lg font-semibold text-slate-800 whitespace-nowrap">{{ coAuthor.name }}</span>
111
+ <span class="text-xs text-slate-500">{{ coAuthor.affiliation }}</span>
97
112
  </div>
98
113
  </div>
99
114
  </div>
100
-
101
- <div class="text-xl font-semibold text-slate-700">
102
- {{ $slidev.configs.date }}
103
- </div>
104
115
  </div>
105
116
  </div>
106
117
  </div>
107
-
108
- <!-- 左下のコピーライト風エリア -->
109
- <div class="absolute bottom-4 left-8 text-slate-700 text-sm font-medium">
110
- {{ new Date().getFullYear() }} {{ $slidev.configs.author.affiliation }}
118
+
119
+ <div class="absolute bottom-4 right-4 text-[10px] font-mono text-slate-800 z-20 writing-vertical-rl">
120
+ © {{ new Date().getFullYear() }} {{ $slidev.configs.author.affiliation }}
111
121
  </div>
122
+
112
123
  </div>
113
124
  </template>
114
125
 
115
126
  <script setup>
116
- import { ref, computed, onMounted, onUnmounted } from 'vue'
127
+ import { ref, computed, onMounted } from 'vue'
117
128
  import { useSlideContext } from '@slidev/client'
118
129
 
119
130
  const { $slidev } = useSlideContext()
131
+ const mounted = ref(false)
132
+
133
+ onMounted(() => {
134
+ setTimeout(() => {
135
+ mounted.value = true
136
+ }, 100)
137
+ })
120
138
 
121
- // タイトルサイズのクラスを返す関数
122
139
  function getTitleSizeClass(size) {
123
140
  const sizeMap = {
124
141
  'small': 'text-4xl',
125
142
  'medium': 'text-5xl',
126
- 'large': 'text-6xl',
127
- 'xlarge': 'text-7xl',
128
- 'xxlarge': 'text-8xl'
143
+ 'large': 'text-8xl',
144
+ 'xlarge': 'text-9xl',
145
+ 'xxlarge': 'text-[10rem]'
129
146
  }
130
-
131
147
  return sizeMap[size] || sizeMap['large']
132
148
  }
133
149
 
134
- // 共著者リストを取得
135
150
  const coAuthors = computed(() => {
136
151
  const configs = $slidev.configs
137
152
  if (!configs || !configs.coAuthors || !Array.isArray(configs.coAuthors)) {
138
153
  return []
139
154
  }
140
- console.log(configs.coAuthors)
141
- // 最大4人まで
142
155
  return configs.coAuthors.slice(0, 4)
143
156
  })
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
157
  </script>
244
158
 
245
159
  <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
- }
160
+ .slidev-layout {
161
+ padding: 0 !important;
260
162
  }
261
163
 
262
- .animated-gradient {
263
- animation: gradient-shift 20s ease-in-out infinite;
164
+ .ease-expo-out {
165
+ transition-timing-function: cubic-bezier(0.19, 1, 0.22, 1);
166
+ }
167
+ .writing-vertical-rl {
168
+ writing-mode: vertical-rl;
169
+ }
170
+ div {
171
+ font-feature-settings: "palt", "kern";
264
172
  }
265
173
 
266
- /* グリッドの常時回転アニメーション */
267
- @keyframes rotate-continuously {
268
- from {
269
- transform: rotate(0deg);
270
- }
271
- to {
272
- transform: rotate(360deg);
273
- }
174
+ /* === カスタムアニメーション定義 === */
175
+ @keyframes spin-slow {
176
+ from { transform: rotate(0deg); }
177
+ to { transform: rotate(360deg); }
178
+ }
179
+ @keyframes reverse-spin-slow {
180
+ from { transform: rotate(360deg); }
181
+ to { transform: rotate(0deg); }
274
182
  }
275
183
 
276
- .rotating-grid {
277
- animation: rotate-continuously 120s linear infinite;
184
+ /* Tailwindのデフォルトspinより遥かに遅く設定し、上品さを出す */
185
+ .animate-spin-super-slow {
186
+ animation: spin-slow 80s linear infinite;
187
+ }
188
+ .animate-reverse-spin-slow {
189
+ animation: reverse-spin-slow 40s linear infinite;
190
+ }
191
+ .animate-spin-slow {
192
+ animation: spin-slow 30s linear infinite;
278
193
  }
279
194
  </style>
package/layouts/end.vue CHANGED
@@ -1,104 +1,106 @@
1
1
  <template>
2
- <div class="slidev-layout thank-you relative overflow-hidden animated-gradient">
3
- <!-- 中央の大きな円形要素 -->
2
+ <div class="slidev-layout end relative w-full h-full !p-0 bg-white overflow-hidden font-sans text-slate-900 selection:bg-sky-200 selection:text-sky-900">
3
+
4
+ <div class="absolute inset-0 z-0 pointer-events-none opacity-10"
5
+ style="background-image: linear-gradient(#0f172a 1px, transparent 1px), linear-gradient(to right, #0f172a 1px, transparent 1px); background-size: 50px 50px;">
6
+ </div>
7
+
4
8
  <div
5
- class="absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-80 h-80 bg-sky-200/50 rounded-full transition-all duration-[3000ms] ease-in-out"
9
+ class="absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-[60vh] h-[60vh] z-0 pointer-events-none transition-all duration-[3000ms] ease-in-out"
6
10
  :style="centerCircleStyles[0]"
7
- />
11
+ >
12
+ <div class="w-full h-full border-2 border-dashed border-slate-300 rounded-full opacity-50"></div>
13
+ </div>
8
14
  <div
9
- class="absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-64 h-64 bg-sky-300/60 rounded-full transition-all duration-[3500ms] ease-in-out"
15
+ class="absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-[45vh] h-[45vh] z-0 pointer-events-none transition-all duration-[3500ms] ease-in-out"
10
16
  :style="centerCircleStyles[1]"
11
- />
17
+ >
18
+ <div class="w-full h-full border-2 border-dotted border-sky-700 rounded-full opacity-30"></div>
19
+ </div>
12
20
 
13
- <!-- 左上の波形要素 -->
14
- <div class="absolute left-0 top-0 w-96 h-96 overflow-hidden">
21
+ <div class="absolute left-0 top-0 w-96 h-96 overflow-hidden pointer-events-none z-0">
15
22
  <div
16
- class="absolute -left-24 -top-24 w-80 h-80 bg-sky-400/40 rounded-full transition-all duration-[4000ms] ease-in-out"
23
+ class="absolute -left-12 -top-12 w-64 h-64 border border-slate-200 transition-all duration-[4000ms] ease-in-out"
17
24
  :style="topLeftCircleStyles[0]"
18
25
  />
19
26
  <div
20
- class="absolute left-8 top-8 w-48 h-48 bg-sky-500/30 rounded-full transition-all duration-[3500ms] ease-in-out"
27
+ class="absolute left-12 top-12 w-32 h-32 bg-sky-200/80 transition-all duration-[3500ms] ease-in-out"
21
28
  :style="topLeftCircleStyles[1]"
22
29
  />
23
30
  </div>
24
31
 
25
- <!-- 右下の幾何学的要素 -->
26
- <div class="absolute right-0 bottom-0 w-80 h-80 overflow-hidden">
32
+ <div class="absolute right-0 bottom-0 w-80 h-80 overflow-hidden pointer-events-none z-0">
27
33
  <div
28
- class="absolute right-16 bottom-16 w-32 h-32 bg-sky-400/50 transform rotate-45 transition-all duration-[3000ms] ease-in-out"
34
+ class="absolute right-16 bottom-16 w-32 h-32 bg-slate-900/5 transform rotate-45 transition-all duration-[3000ms] ease-in-out"
29
35
  :style="bottomRightSquareStyles[0]"
30
36
  />
31
37
  <div
32
- class="absolute right-32 bottom-32 w-24 h-24 bg-sky-500/40 transform rotate-45 transition-all duration-[3500ms] ease-in-out"
38
+ class="absolute right-32 bottom-32 w-24 h-24 border border-sky-500/30 transform rotate-45 transition-all duration-[3500ms] ease-in-out"
33
39
  :style="bottomRightSquareStyles[1]"
34
40
  />
35
41
  <div
36
- class="absolute right-8 bottom-8 w-16 h-16 bg-sky-600/50 transform rotate-45 transition-all duration-[4000ms] ease-in-out"
42
+ class="absolute right-8 bottom-8 w-16 h-16 bg-sky-800/10 transform rotate-45 transition-all duration-[4000ms] ease-in-out"
37
43
  :style="bottomRightSquareStyles[2]"
38
44
  />
39
45
  </div>
40
46
 
41
- <!-- 左下のドット要素 -->
42
47
  <div
43
- class="absolute left-8 bottom-8 grid grid-cols-4 gap-4 opacity-50 transition-all duration-[2500ms] ease-in-out"
48
+ class="absolute left-12 bottom-12 grid grid-cols-4 gap-3 opacity-60 transition-all duration-[2500ms] ease-in-out z-0"
44
49
  :style="dotsGridStyle"
45
50
  >
46
51
  <div
47
52
  v-for="(dot, index) in dots"
48
53
  :key="index"
49
- :class="['w-4 h-4 rounded-full transition-all duration-[2500ms] ease-in-out', dot.color]"
54
+ :class="['w-1.5 h-1.5 transition-all duration-[2500ms] ease-in-out', dot.colorClass]"
50
55
  :style="dot.style"
51
56
  />
52
57
  </div>
53
58
 
54
- <!-- 右上の線形要素 -->
55
59
  <div
56
- class="absolute right-8 top-8 transform rotate-12 space-y-3 opacity-60 transition-all duration-[4500ms] ease-in-out"
60
+ class="absolute right-12 top-12 transform rotate-0 space-y-2 opacity-60 transition-all duration-[4500ms] ease-in-out z-0"
57
61
  :style="topRightLinesStyle"
58
62
  >
59
63
  <div
60
64
  v-for="(width, index) in lineWidths"
61
65
  :key="index"
62
- :class="['h-2 rounded-full transition-all duration-[2000ms] ease-in-out', index % 2 === 0 ? 'bg-sky-500/70' : 'bg-sky-600/70']"
66
+ :class="['h-1 transition-all duration-[2000ms] ease-in-out', index % 2 === 0 ? 'bg-slate-900' : 'bg-sky-600']"
63
67
  :style="{ width: `${width}px` }"
64
68
  />
65
69
  </div>
66
70
 
67
- <!-- メインコンテンツ -->
68
- <div class="relative z-10 flex flex-col justify-center items-center h-full px-8">
69
- <div class="text-center space-y-8">
70
- <!-- メインメッセージ -->
71
- <div class="text-5xl font-bold text-slate-800 leading-tight tracking-wide">
72
- ご清聴ありがとうございました
73
- </div>
71
+ <div class="relative z-10 flex flex-col justify-center items-center h-full px-16 w-full">
72
+ <div class="flex flex-col items-start space-y-8 max-w-4xl">
74
73
 
75
- <!-- サブメッセージ(オプション) -->
76
- <div class="mt-12 text-2xl font-medium text-slate-600">
77
- {{ $slidev.configs.thankYouMessage || 'Thank you for your attention' }}
74
+ <div class="w-24 h-2 bg-slate-900"></div>
75
+
76
+ <div class="text-7xl font-bold text-slate-900 leading-[0.9] tracking-tight">
77
+ <span class="block">THANK YOU</span>
78
+ <span class="block text-slate-400">FOR LISTENING</span>
78
79
  </div>
79
80
 
80
- <!-- 連絡先情報(オプション) -->
81
- <div class="mt-8 text-lg text-slate-600 space-y-2" v-if="$slidev.configs.contact">
82
- <div v-if="$slidev.configs.contact.email">
83
- <lucide-mail class="inline-block w-5 h-5 mr-1" />
84
- {{ $slidev.configs.contact.email }}
81
+ <p class="pt-4 text-xl font-mono text-sky-800 tracking-wide leading-normal">
82
+ {{ $slidev.configs.thankYouMessage || 'ご清聴ありがとうございました' }}
83
+ </p>
84
+
85
+ <div class="pt-8 grid grid-cols-1 gap-4 text-base text-slate-600" v-if="$slidev.configs.contact">
86
+ <div v-if="$slidev.configs.contact.email" class="flex items-center space-x-3">
87
+ <span class="w-8 h-[1px] bg-slate-400"></span>
88
+ <span class="font-semibold text-slate-900">EMAIL</span>
89
+ <span>{{ $slidev.configs.contact.email }}</span>
90
+ </div>
91
+ <div v-if="$slidev.configs.contact.twitter" class="flex items-center space-x-3">
92
+ <span class="w-8 h-[1px] bg-slate-400"></span>
93
+ <span class="font-semibold text-slate-900">X / TWITTER</span>
94
+ <span>{{ $slidev.configs.contact.twitter }}</span>
85
95
  </div>
86
96
  </div>
87
97
  </div>
88
98
  </div>
89
99
 
90
- <!-- 右下の著者情報 -->
91
- <div class="absolute bottom-6 right-8 text-right text-slate-700">
92
- <div class="text-lg font-semibold">
93
- {{ $slidev.configs.author.name }}
94
- </div>
95
- <div class="text-base font-medium">
96
- {{ $slidev.configs.author.affiliation }}
97
- </div>
98
- <div class="text-sm">
99
- {{ $slidev.configs.date }}
100
- </div>
100
+ <div class="absolute bottom-4 right-4 text-[10px] font-mono text-slate-800 z-20 writing-vertical-rl">
101
+ {{ $slidev.configs.author.name }} / {{ $slidev.configs.author.affiliation }}
101
102
  </div>
103
+
102
104
  </div>
103
105
  </template>
104
106
 
@@ -108,47 +110,41 @@ import { useSlideContext } from '@slidev/client'
108
110
 
109
111
  const { $slidev } = useSlideContext()
110
112
 
111
- // ランダムな値を生成する関数
112
113
  const randomRange = (min, max) => Math.random() * (max - min) + min
113
114
 
114
- // 中央の円形要素のスタイル
115
115
  const centerCircleStyles = ref([
116
- { transform: `translate(${randomRange(-20, 20)}px, ${randomRange(-20, 20)}px) scale(${randomRange(0.95, 1.05)})` },
117
- { transform: `translate(${randomRange(-15, 15)}px, ${randomRange(-15, 15)}px) scale(${randomRange(0.95, 1.05)})` }
116
+ { transform: `translate(${randomRange(-20, 20)}px, ${randomRange(-20, 20)}px) scale(${randomRange(0.98, 1.02)})` },
117
+ { transform: `translate(${randomRange(-15, 15)}px, ${randomRange(-15, 15)}px) scale(${randomRange(0.98, 1.02)})` }
118
118
  ])
119
119
 
120
- // 左上の円形要素のスタイル
121
120
  const topLeftCircleStyles = ref([
122
- { transform: `translate(${randomRange(-15, 15)}px, ${randomRange(-15, 15)}px) scale(${randomRange(0.9, 1.1)})` },
123
- { transform: `translate(${randomRange(-10, 10)}px, ${randomRange(-10, 10)}px) scale(${randomRange(0.9, 1.1)})` }
121
+ { transform: `translate(${randomRange(-15, 15)}px, ${randomRange(-15, 15)}px)` },
122
+ { transform: `translate(${randomRange(-10, 10)}px, ${randomRange(-10, 10)}px)` }
124
123
  ])
125
124
 
126
- // 右下の正方形要素のスタイル
127
125
  const bottomRightSquareStyles = ref([
128
126
  { transform: `translate(${randomRange(-10, 10)}px, ${randomRange(-10, 10)}px) rotate(${randomRange(40, 50)}deg)` },
129
127
  { transform: `translate(${randomRange(-12, 12)}px, ${randomRange(-12, 12)}px) rotate(${randomRange(40, 50)}deg)` },
130
128
  { transform: `translate(${randomRange(-8, 8)}px, ${randomRange(-8, 8)}px) rotate(${randomRange(40, 50)}deg)` }
131
129
  ])
132
130
 
133
- // 左下のドットグリッドのスタイル
134
131
  const dotsGridStyle = ref({
135
- transform: `translate(${randomRange(-8, 8)}px, ${randomRange(-8, 8)}px) rotate(${randomRange(-5, 5)}deg)`
132
+ transform: `translate(${randomRange(-8, 8)}px, ${randomRange(-8, 8)}px)`
136
133
  })
137
134
 
138
135
  const dots = ref([
139
- { color: 'bg-sky-500', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
140
- { color: 'bg-sky-600', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
141
- { color: 'bg-sky-500', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
142
- { color: 'bg-sky-600', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
143
- { color: 'bg-sky-600', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
144
- { color: 'bg-sky-500', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
145
- { color: 'bg-sky-600', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
146
- { color: 'bg-sky-500', style: { transform: `scale(${randomRange(0.85, 1.15)})` } }
136
+ { colorClass: 'bg-slate-900', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
137
+ { colorClass: 'bg-sky-600', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
138
+ { colorClass: 'bg-slate-900', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
139
+ { colorClass: 'bg-sky-600', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
140
+ { colorClass: 'bg-sky-600', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
141
+ { colorClass: 'bg-slate-900', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
142
+ { colorClass: 'bg-sky-600', style: { transform: `scale(${randomRange(0.85, 1.15)})` } },
143
+ { colorClass: 'bg-slate-900', style: { transform: `scale(${randomRange(0.85, 1.15)})` } }
147
144
  ])
148
145
 
149
- // 右上の線形要素のスタイル
150
146
  const topRightLinesStyle = ref({
151
- transform: `translate(${randomRange(-10, 10)}px, ${randomRange(-10, 10)}px) rotate(${randomRange(7, 17)}deg)`
147
+ transform: `translate(${randomRange(-10, 10)}px, ${randomRange(-10, 10)}px)`
152
148
  })
153
149
 
154
150
  const lineWidths = ref([
@@ -158,25 +154,21 @@ const lineWidths = ref([
158
154
  randomRange(105, 125)
159
155
  ])
160
156
 
161
- // アニメーション更新関数
162
157
  const updateAnimations = () => {
163
- // 中央の円形要素
164
158
  centerCircleStyles.value[0] = {
165
- transform: `translate(${randomRange(-20, 20)}px, ${randomRange(-20, 20)}px) scale(${randomRange(0.95, 1.05)})`
159
+ transform: `translate(${randomRange(-20, 20)}px, ${randomRange(-20, 20)}px) scale(${randomRange(0.98, 1.02)})`
166
160
  }
167
161
  centerCircleStyles.value[1] = {
168
- transform: `translate(${randomRange(-15, 15)}px, ${randomRange(-15, 15)}px) scale(${randomRange(0.95, 1.05)})`
162
+ transform: `translate(${randomRange(-15, 15)}px, ${randomRange(-15, 15)}px) scale(${randomRange(0.98, 1.02)})`
169
163
  }
170
164
 
171
- // 左上の円形要素
172
165
  topLeftCircleStyles.value[0] = {
173
- transform: `translate(${randomRange(-15, 15)}px, ${randomRange(-15, 15)}px) scale(${randomRange(0.9, 1.1)})`
166
+ transform: `translate(${randomRange(-15, 15)}px, ${randomRange(-15, 15)}px)`
174
167
  }
175
168
  topLeftCircleStyles.value[1] = {
176
- transform: `translate(${randomRange(-10, 10)}px, ${randomRange(-10, 10)}px) scale(${randomRange(0.9, 1.1)})`
169
+ transform: `translate(${randomRange(-10, 10)}px, ${randomRange(-10, 10)}px)`
177
170
  }
178
171
 
179
- // 右下の正方形要素
180
172
  bottomRightSquareStyles.value[0] = {
181
173
  transform: `translate(${randomRange(-10, 10)}px, ${randomRange(-10, 10)}px) rotate(${randomRange(40, 50)}deg)`
182
174
  }
@@ -187,9 +179,8 @@ const updateAnimations = () => {
187
179
  transform: `translate(${randomRange(-8, 8)}px, ${randomRange(-8, 8)}px) rotate(${randomRange(40, 50)}deg)`
188
180
  }
189
181
 
190
- // 左下のドットグリッド
191
182
  dotsGridStyle.value = {
192
- transform: `translate(${randomRange(-8, 8)}px, ${randomRange(-8, 8)}px) rotate(${randomRange(-5, 5)}deg)`
183
+ transform: `translate(${randomRange(-8, 8)}px, ${randomRange(-8, 8)}px)`
193
184
  }
194
185
 
195
186
  dots.value = dots.value.map(dot => ({
@@ -199,9 +190,8 @@ const updateAnimations = () => {
199
190
  }
200
191
  }))
201
192
 
202
- // 右上の線形要素
203
193
  topRightLinesStyle.value = {
204
- transform: `translate(${randomRange(-10, 10)}px, ${randomRange(-10, 10)}px) rotate(${randomRange(7, 17)}deg)`
194
+ transform: `translate(${randomRange(-10, 10)}px, ${randomRange(-10, 10)}px)`
205
195
  }
206
196
 
207
197
  lineWidths.value = [
@@ -215,12 +205,10 @@ const updateAnimations = () => {
215
205
  let intervalId = null
216
206
 
217
207
  onMounted(() => {
218
- // 即座に最初のアニメーションを開始
219
208
  setTimeout(() => {
220
209
  updateAnimations()
221
210
  }, 100)
222
211
 
223
- // 定期的にアニメーションを更新(3秒ごと)
224
212
  intervalId = setInterval(() => {
225
213
  updateAnimations()
226
214
  }, 3000)
@@ -234,27 +222,15 @@ onUnmounted(() => {
234
222
  </script>
235
223
 
236
224
  <style scoped>
237
- /* グラデーション背景のアニメーション */
238
- @keyframes gradient-shift {
239
- 0% {
240
- background: linear-gradient(to top right, #e0f2fe, white, #f0f9ff);
241
- }
242
- 33% {
243
- background: linear-gradient(to top right, #dbeafe, white, #eff6ff);
244
- }
245
- 66% {
246
- background: linear-gradient(to top right, #e0f2fe, #f3f4f6, white);
247
- }
248
- 100% {
249
- background: linear-gradient(to top right, #e0f2fe, white, #f0f9ff);
250
- }
225
+ .slidev-layout {
226
+ padding: 0 !important;
251
227
  }
252
228
 
253
- .animated-gradient {
254
- animation: gradient-shift 20s ease-in-out infinite;
229
+ .writing-vertical-rl {
230
+ writing-mode: vertical-rl;
255
231
  }
256
232
 
257
- .thank-you {
258
- font-family: 'Hiragino Sans', 'Yu Gothic', 'Meiryo', sans-serif;
233
+ div, p {
234
+ font-feature-settings: "palt", "kern";
259
235
  }
260
- </style>
236
+ </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slidev-theme-gtlabo",
3
- "version": "1.1.1",
3
+ "version": "2.0.0",
4
4
  "description": "A Slidev theme for laboratory presentations with customizable components",
5
5
  "author": "mksmkss",
6
6
  "license": "MIT",