slidev-theme-gtlabo 1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 mksmkss
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,298 @@
1
+ # Slidev Theme GTlabo
2
+
3
+ [![NPM version](https://img.shields.io/npm/v/@mksmkss/slidev-theme-gtlabo?color=3AB9D4&label=)](https://www.npmjs.com/package/@mksmkss/slidev-theme-gtlabo)
4
+
5
+ 学術発表やプレゼンテーション用に設計されたSlidev用カスタムテーマ。引用管理、数式表示、階層リストなどの機能を提供します。
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @mksmkss/slidev-theme-gtlabo
11
+ ```
12
+ Add the following frontmatter to your `slides.md`. Start Slidev then it will prompt you to install the theme automatically.
13
+
14
+ <pre><code>
15
+ ---
16
+ theme: <b>gtlabo</b>
17
+ ---
18
+ </code></pre>
19
+
20
+ Learn more about [how to use a theme](https://sli.dev/guide/theme-addon#use-theme).
21
+
22
+ ## Layouts
23
+
24
+ This theme provides the following layouts:
25
+
26
+ > TODO:
27
+
28
+ ## Components
29
+
30
+ このテーマは以下のコンポーネントを提供します:
31
+
32
+ ### 1. Citation コンポーネント
33
+ インライン引用と参考文献の管理を行います。
34
+
35
+ ```vue
36
+ <Citation id="reference-key" />
37
+ ```
38
+
39
+ **機能:**
40
+ - インライン引用番号の表示(`[1]`形式)
41
+ - 画面下部に現在のページの引用情報を表示
42
+ - 引用番号の自動管理
43
+ - 複数ページにわたる引用の追跡
44
+
45
+ **使用例:**
46
+ ```markdown
47
+ この技術について<Citation id="smith2023" />の研究が参考になります。
48
+ ```
49
+
50
+ ### 2. CitationListPage コンポーネント
51
+ 参考文献一覧ページを生成します。
52
+
53
+ ```vue
54
+ <CitationListPage />
55
+ ```
56
+
57
+ **機能:**
58
+ - 全ての参考文献を一覧表示
59
+ - 学術スタイルでの引用フォーマット
60
+ - DOI、URL、ISSN等の情報表示
61
+ - ソート機能(キー、著者、年別)
62
+
63
+ **プロパティ:**
64
+ - `style`: 引用スタイル(`academic`、`ieee`、`apa`)
65
+ - `sortBy`: ソート基準(`key`、`author`、`year`)
66
+
67
+ ### 3. Header コンポーネント
68
+ プレゼンテーションのヘッダー部分を管理します。
69
+
70
+ ```vue
71
+ <Header
72
+ :chapter-data="{ title: 'セクションタイトル' }"
73
+ chapter="section1"
74
+ current-section="intro"
75
+ />
76
+ ```
77
+
78
+ **機能:**
79
+ - 章・セクションの進捗表示
80
+ - 現在位置の可視化
81
+ - ページ番号表示
82
+ - 動的なプログレスバー
83
+
84
+ **プロパティ:**
85
+ - `chapter`: 章のキー
86
+ - `chapterData`: 章の情報オブジェクト
87
+ - `currentSection`: 現在のセクション
88
+ - `currentChapter`: 現在の章
89
+
90
+
91
+ ### 4. MathText コンポーネント
92
+ 数式とテキストを統合表示します。
93
+
94
+ ```vue
95
+ <MathText
96
+ text="これは数式 $x^2 + y^2 = z^2$ を含むテキストです。"
97
+ container-tag="p"
98
+ :simple="false"
99
+ :disable-markdown="false"
100
+ />
101
+ ```
102
+
103
+ **機能:**
104
+ - LaTeX数式の自動レンダリング
105
+ - インライン数式(`$...$`)とブロック数式(`$$...$$`)
106
+ - Markdownサポート(太字、イタリック、リンク等)
107
+ - KaTeX による数式描画
108
+ - シンプルモード対応
109
+
110
+ **プロパティ:**
111
+ - `text`: 表示するテキスト
112
+ - `containerTag`: コンテナのHTMLタグ
113
+ - `simple`: シンプルモード(基本的な数式のみ)
114
+ - `disableMarkdown`: Markdownを無効化
115
+ - `customDelimiters`: カスタム区切り文字
116
+
117
+ ### 5. SectionTitle コンポーネント
118
+ セクションタイトルを表示します。
119
+
120
+ ```vue
121
+ <SectionTitle
122
+ title="セクションタイトル"
123
+ color="sky-800"
124
+ />
125
+ ```
126
+
127
+ **機能:**
128
+ - 左側のカラーバーと組み合わせたタイトル表示
129
+ - UnoCSS/Tailwindカラー対応
130
+ - カスタムカラー対応
131
+ - スロットコンテンツ対応
132
+
133
+ **プロパティ:**
134
+ - `title`: タイトルテキスト
135
+ - `color`: カラー(Tailwind形式またはHEX)
136
+
137
+ ### 6. SubSectionTitle コンポーネント
138
+ サブセクションタイトルを表示します。
139
+
140
+ ```vue
141
+ <SubSectionTitle
142
+ title="サブセクションタイトル"
143
+ color="sky-700"
144
+ />
145
+ ```
146
+
147
+ **機能:**
148
+ - 左側のアイコン(矢印)と組み合わせたタイトル表示
149
+ - UnoCSS/Tailwindカラー対応
150
+ - カスタムカラー対応
151
+
152
+ **プロパティ:**
153
+ - `title`: タイトルテキスト
154
+ - `color`: カラー(Tailwind形式またはHEX)
155
+
156
+ ### 7. TextColorBox コンポーネント
157
+ 色付きのテキストボックスを表示します。
158
+
159
+ ```vue
160
+ <TextColorBox
161
+ title="タイトル"
162
+ text="本文テキスト"
163
+ container-class="my-4"
164
+ />
165
+ ```
166
+
167
+ **機能:**
168
+ - タイトル付きのカラーボックス
169
+ - HTMLタグ対応
170
+ - マーキング機能(`v-mark`)
171
+ - カスタムスタイル適用
172
+
173
+ **プロパティ:**
174
+ - `title`: ボックスのタイトル
175
+ - `text`: ボックスの本文
176
+ - `containerClass`: 追加のCSSクラス
177
+
178
+
179
+ **機能:**
180
+ - SVGベースの入れ子円グラフ
181
+ - データ構造の階層表示
182
+ - アニメーション効果
183
+ - 課題提起セクション付き
184
+ - パーセンテージ表示
185
+
186
+ **特徴:**
187
+ - 外側の円:全体データの分類(構造化/非構造化)
188
+ - 内側の円:構造化データの詳細分類
189
+ - 自動アニメーション効果
190
+ - 完全にカスタマイズ可能なSVG
191
+
192
+ ## 🛠️ 設定方法
193
+
194
+ ### 1. 参考文献の設定
195
+
196
+ frontmatter に `citations` を追加:
197
+
198
+ ```yaml
199
+ ---
200
+ citations:
201
+ smith2023:
202
+ author: "Smith, J."
203
+ title: "Research on AI"
204
+ journal: "Journal of AI"
205
+ year: "2023"
206
+ doi: "10.1000/example"
207
+ jones2022:
208
+ author: "Jones, A."
209
+ title: "Machine Learning Basics"
210
+ publisher: "Tech Press"
211
+ year: "2022"
212
+ ---
213
+ ```
214
+
215
+ ### 2. 章・セクション構造の設定
216
+
217
+ ```yaml
218
+ ---
219
+ chapters:
220
+ intro:
221
+ title: "はじめに"
222
+ sections:
223
+ overview:
224
+ title: "概要"
225
+ objectives:
226
+ title: "目的"
227
+ method:
228
+ title: "手法"
229
+ sections:
230
+ approach:
231
+ title: "アプローチ"
232
+ implementation:
233
+ title: "実装"
234
+ ---
235
+ ```
236
+
237
+ ## 📱 使用例
238
+
239
+ ```vue
240
+ <template>
241
+ <div>
242
+ <!-- ヘッダー -->
243
+ <Header
244
+ :chapter-data="{ title: '研究手法' }"
245
+ chapter="method"
246
+ current-section="approach"
247
+ />
248
+
249
+ <!-- セクションタイトル -->
250
+ <SectionTitle title="提案手法" />
251
+
252
+ <!-- 数式を含むテキスト -->
253
+ <MathText
254
+ text="提案手法では、損失関数 $L = \frac{1}{n}\sum_{i=1}^{n}(y_i - \hat{y_i})^2$ を最小化します。"
255
+ />
256
+
257
+ <!-- 階層リスト -->
258
+ <HierarchyList>
259
+ - 手法の特徴
260
+ - 高精度
261
+ - 高速処理
262
+ - 省メモリ
263
+ </HierarchyList>
264
+
265
+ <!-- 引用 -->
266
+ <p>この手法は<Citation id="smith2023" />で提案されました。</p>
267
+
268
+ <!-- カラーボックス -->
269
+ <TextColorBox
270
+ title="重要なポイント"
271
+ text="この手法により従来手法より<strong>20%</strong>の性能向上を実現しました。"
272
+ />
273
+ </div>
274
+ </template>
275
+ ```
276
+
277
+ ## 🎨 スタイル
278
+
279
+ テーマは以下のカラーパレットを使用:
280
+ - プライマリ: Sky(`sky-600`、`sky-700`、`sky-800`)
281
+ - セカンダリ: Gray(`gray-600`、`gray-700`、`gray-800`)
282
+ - アクセント: Blue(`blue-500`、`blue-600`)
283
+
284
+ ## 📦 依存関係
285
+
286
+ - Vue 3
287
+ - Slidev
288
+ - UnoCSS/Tailwind CSS
289
+ - KaTeX(数式レンダリング)
290
+ - Lucide Icons
291
+
292
+ ## Contributing
293
+
294
+ - `npm install`
295
+ - `npm run dev` to start theme preview of `example.md`
296
+ - Edit the `example.md` and style to see the changes
297
+ - `npm run export` to generate the preview PDF
298
+ - `npm run screenshot` to generate the preview PNG
@@ -0,0 +1,253 @@
1
+ <template>
2
+ <span>
3
+ <!-- インライン引用番号 -->
4
+ <sup class="text-blue-600 font-semibold">
5
+ [{{ citationNumber }}]
6
+ </sup>
7
+
8
+ <!-- 引用情報表示エリア(画面下部に常時表示) -->
9
+ <div
10
+ v-if="hasCurrentPageCitations"
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
17
+ v-for="citation in sortedCurrentPageCitations"
18
+ :key="citation.id"
19
+ class="text-xs text-gray-800"
20
+ >
21
+ <span class="font-semibold">[{{ citation.number }}]</span>
22
+ {{ citation.formatted }}
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </span>
28
+ </template>
29
+
30
+ <script setup>
31
+ import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
32
+ import { useSlideContext } from '@slidev/client'
33
+
34
+ const { $slidev } = useSlideContext()
35
+ const citations = $slidev.configs.citations || {}
36
+
37
+ const props = defineProps({
38
+ id: {
39
+ type: String,
40
+ required: true
41
+ }
42
+ })
43
+
44
+ // グローバル引用管理の初期化
45
+ if (!window.citationManager) {
46
+ window.citationManager = {
47
+ counter: 1,
48
+ citations: new Map(), // id -> { number, data, formatted }
49
+ pageActiveCitations: new Map(), // pageNumber -> Set(citationIds)
50
+ components: new Set()
51
+ }
52
+ }
53
+
54
+ const forceUpdate = ref(0)
55
+
56
+ // 現在のページ番号を取得
57
+ const currentPage = computed(() => {
58
+ return $slidev.nav.currentPage
59
+ })
60
+
61
+ // 引用データを取得
62
+ const citationData = computed(() => {
63
+ return citations[props.id] || null
64
+ })
65
+
66
+ // 引用番号を取得または生成
67
+ const citationNumber = computed(() => {
68
+ if (!citationData.value) return '?'
69
+
70
+ if (!window.citationManager.citations.has(props.id)) {
71
+ window.citationManager.citations.set(props.id, {
72
+ number: window.citationManager.counter,
73
+ data: citationData.value,
74
+ formatted: formatCitation(citationData.value)
75
+ })
76
+ window.citationManager.counter++
77
+ }
78
+
79
+ return window.citationManager.citations.get(props.id).number
80
+ })
81
+
82
+ // 現在のページにアクティブな引用があるかチェック
83
+ const hasCurrentPageCitations = computed(() => {
84
+ forceUpdate.value // 依存関係を強制的に更新
85
+ const pageSet = window.citationManager.pageActiveCitations.get(currentPage.value)
86
+ return pageSet && pageSet.size > 0
87
+ })
88
+
89
+ // 現在のページのソートされた引用一覧
90
+ const sortedCurrentPageCitations = computed(() => {
91
+ forceUpdate.value // 依存関係を強制的に更新
92
+ const pageSet = window.citationManager.pageActiveCitations.get(currentPage.value)
93
+
94
+ if (!pageSet) return []
95
+
96
+ return Array.from(pageSet)
97
+ .map(id => ({
98
+ id,
99
+ ...window.citationManager.citations.get(id)
100
+ }))
101
+ .filter(citation => citation.data) // dataが存在するもののみ
102
+ .sort((a, b) => a.number - b.number)
103
+ })
104
+
105
+ // 引用をフォーマット
106
+ const formatCitation = (data) => {
107
+ if (!data) return '引用情報が見つかりません'
108
+
109
+ let citation = ''
110
+
111
+ // 著者
112
+ if (data.author) {
113
+ citation += data.author
114
+ }
115
+
116
+ // タイトル
117
+ if (data.title) {
118
+ citation += citation ? `, "${data.title}"` : `"${data.title}"`
119
+ }
120
+
121
+ // ジャーナル
122
+ if (data.journal) {
123
+ citation += citation ? `, ${data.journal}` : data.journal
124
+ }
125
+
126
+ // ボリューム・ナンバー
127
+ if (data.volume && data.number) {
128
+ citation += `, Vol. ${data.volume}, No. ${data.number}`
129
+ } else if (data.volume) {
130
+ citation += `, Vol. ${data.volume}`
131
+ } else if (data.number) {
132
+ citation += `, No. ${data.number}`
133
+ }
134
+
135
+ // ページ
136
+ if (data.pages) {
137
+ citation += `, pp. ${data.pages}`
138
+ }
139
+
140
+ // 年
141
+ if (data.year) {
142
+ citation += citation ? ` (${data.year})` : data.year
143
+ }
144
+
145
+ // 出版社
146
+ if (data.publisher) {
147
+ citation += citation ? `, ${data.publisher}` : data.publisher
148
+ }
149
+
150
+ // URL
151
+ if (data.url) {
152
+ citation += citation ? `, ${data.url}` : data.url
153
+ }
154
+
155
+ // ISSN
156
+ if (data.issn) {
157
+ citation += `, ISSN: ${data.issn}`
158
+ }
159
+
160
+ return citation || '引用情報が不完全です'
161
+ }
162
+
163
+ // 全コンポーネントの再描画をトリガー
164
+ const triggerGlobalUpdate = () => {
165
+ window.citationManager.components.forEach(component => {
166
+ if (component.updateForceUpdate) {
167
+ component.updateForceUpdate()
168
+ }
169
+ })
170
+ }
171
+
172
+ // 強制更新関数
173
+ const updateForceUpdate = () => {
174
+ forceUpdate.value++
175
+ }
176
+
177
+ // 現在のページに引用を追加
178
+ const addToCurrentPage = () => {
179
+ if (!citationData.value) return
180
+
181
+ const page = currentPage.value
182
+ if (!window.citationManager.pageActiveCitations.has(page)) {
183
+ window.citationManager.pageActiveCitations.set(page, new Set())
184
+ }
185
+ window.citationManager.pageActiveCitations.get(page).add(props.id)
186
+ }
187
+
188
+ // 現在のページから引用を削除
189
+ const removeFromCurrentPage = () => {
190
+ const page = currentPage.value
191
+ const pageSet = window.citationManager.pageActiveCitations.get(page)
192
+ if (pageSet) {
193
+ pageSet.delete(props.id)
194
+ if (pageSet.size === 0) {
195
+ window.citationManager.pageActiveCitations.delete(page)
196
+ }
197
+ }
198
+ }
199
+
200
+ // ページ変更を監視
201
+ watch(currentPage, (newPage, oldPage) => {
202
+ if (oldPage !== undefined) {
203
+ // 前のページから削除
204
+ const oldPageSet = window.citationManager.pageActiveCitations.get(oldPage)
205
+ if (oldPageSet) {
206
+ oldPageSet.delete(props.id)
207
+ if (oldPageSet.size === 0) {
208
+ window.citationManager.pageActiveCitations.delete(oldPage)
209
+ }
210
+ }
211
+ }
212
+
213
+ // 新しいページに追加
214
+ addToCurrentPage()
215
+ triggerGlobalUpdate()
216
+ })
217
+
218
+ // コンポーネントのマウント時
219
+ onMounted(() => {
220
+ if (citationData.value) {
221
+ addToCurrentPage()
222
+ window.citationManager.components.add({ updateForceUpdate })
223
+ triggerGlobalUpdate()
224
+ }
225
+ })
226
+
227
+ // コンポーネントのアンマウント時
228
+ onUnmounted(() => {
229
+ removeFromCurrentPage()
230
+ window.citationManager.components.delete({ updateForceUpdate })
231
+ triggerGlobalUpdate()
232
+ })
233
+ </script>
234
+
235
+ <style scoped>
236
+ /* スクロールバーのスタイリング */
237
+ ::-webkit-scrollbar {
238
+ width: 4px;
239
+ }
240
+
241
+ ::-webkit-scrollbar-track {
242
+ background: #f1f1f1;
243
+ }
244
+
245
+ ::-webkit-scrollbar-thumb {
246
+ background: #c1c1c1;
247
+ border-radius: 2px;
248
+ }
249
+
250
+ ::-webkit-scrollbar-thumb:hover {
251
+ background: #a8a8a8;
252
+ }
253
+ </style>