entari-plugin-hyw 2.2.5__py3-none-any.whl → 3.5.0rc6__py3-none-any.whl

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 (91) hide show
  1. entari_plugin_hyw/__init__.py +371 -315
  2. entari_plugin_hyw/assets/card-dist/index.html +396 -0
  3. entari_plugin_hyw/assets/card-dist/logos/anthropic.svg +1 -0
  4. entari_plugin_hyw/assets/card-dist/logos/cerebras.svg +9 -0
  5. entari_plugin_hyw/assets/card-dist/logos/deepseek.png +0 -0
  6. entari_plugin_hyw/assets/card-dist/logos/gemini.svg +1 -0
  7. entari_plugin_hyw/assets/card-dist/logos/google.svg +1 -0
  8. entari_plugin_hyw/assets/card-dist/logos/grok.png +0 -0
  9. entari_plugin_hyw/assets/card-dist/logos/huggingface.png +0 -0
  10. entari_plugin_hyw/assets/card-dist/logos/microsoft.svg +15 -0
  11. entari_plugin_hyw/assets/card-dist/logos/minimax.png +0 -0
  12. entari_plugin_hyw/assets/card-dist/logos/mistral.png +0 -0
  13. entari_plugin_hyw/assets/card-dist/logos/nvida.png +0 -0
  14. entari_plugin_hyw/assets/card-dist/logos/openai.svg +1 -0
  15. entari_plugin_hyw/assets/card-dist/logos/openrouter.png +0 -0
  16. entari_plugin_hyw/assets/card-dist/logos/perplexity.svg +24 -0
  17. entari_plugin_hyw/assets/card-dist/logos/qwen.png +0 -0
  18. entari_plugin_hyw/assets/card-dist/logos/xai.png +0 -0
  19. entari_plugin_hyw/assets/card-dist/logos/xiaomi.png +0 -0
  20. entari_plugin_hyw/assets/card-dist/logos/zai.png +0 -0
  21. entari_plugin_hyw/assets/card-dist/vite.svg +1 -0
  22. entari_plugin_hyw/assets/icon/anthropic.svg +1 -0
  23. entari_plugin_hyw/assets/icon/cerebras.svg +9 -0
  24. entari_plugin_hyw/assets/icon/deepseek.png +0 -0
  25. entari_plugin_hyw/assets/icon/gemini.svg +1 -0
  26. entari_plugin_hyw/assets/icon/google.svg +1 -0
  27. entari_plugin_hyw/assets/icon/grok.png +0 -0
  28. entari_plugin_hyw/assets/icon/huggingface.png +0 -0
  29. entari_plugin_hyw/assets/icon/microsoft.svg +15 -0
  30. entari_plugin_hyw/assets/icon/minimax.png +0 -0
  31. entari_plugin_hyw/assets/icon/mistral.png +0 -0
  32. entari_plugin_hyw/assets/icon/nvida.png +0 -0
  33. entari_plugin_hyw/assets/icon/openai.svg +1 -0
  34. entari_plugin_hyw/assets/icon/openrouter.png +0 -0
  35. entari_plugin_hyw/assets/icon/perplexity.svg +24 -0
  36. entari_plugin_hyw/assets/icon/qwen.png +0 -0
  37. entari_plugin_hyw/assets/icon/xai.png +0 -0
  38. entari_plugin_hyw/assets/icon/xiaomi.png +0 -0
  39. entari_plugin_hyw/assets/icon/zai.png +0 -0
  40. entari_plugin_hyw/card-ui/.gitignore +24 -0
  41. entari_plugin_hyw/card-ui/README.md +5 -0
  42. entari_plugin_hyw/card-ui/index.html +16 -0
  43. entari_plugin_hyw/card-ui/package-lock.json +2342 -0
  44. entari_plugin_hyw/card-ui/package.json +31 -0
  45. entari_plugin_hyw/card-ui/public/logos/anthropic.svg +1 -0
  46. entari_plugin_hyw/card-ui/public/logos/cerebras.svg +9 -0
  47. entari_plugin_hyw/card-ui/public/logos/deepseek.png +0 -0
  48. entari_plugin_hyw/card-ui/public/logos/gemini.svg +1 -0
  49. entari_plugin_hyw/card-ui/public/logos/google.svg +1 -0
  50. entari_plugin_hyw/card-ui/public/logos/grok.png +0 -0
  51. entari_plugin_hyw/card-ui/public/logos/huggingface.png +0 -0
  52. entari_plugin_hyw/card-ui/public/logos/microsoft.svg +15 -0
  53. entari_plugin_hyw/card-ui/public/logos/minimax.png +0 -0
  54. entari_plugin_hyw/card-ui/public/logos/mistral.png +0 -0
  55. entari_plugin_hyw/card-ui/public/logos/nvida.png +0 -0
  56. entari_plugin_hyw/card-ui/public/logos/openai.svg +1 -0
  57. entari_plugin_hyw/card-ui/public/logos/openrouter.png +0 -0
  58. entari_plugin_hyw/card-ui/public/logos/perplexity.svg +24 -0
  59. entari_plugin_hyw/card-ui/public/logos/qwen.png +0 -0
  60. entari_plugin_hyw/card-ui/public/logos/xai.png +0 -0
  61. entari_plugin_hyw/card-ui/public/logos/xiaomi.png +0 -0
  62. entari_plugin_hyw/card-ui/public/logos/zai.png +0 -0
  63. entari_plugin_hyw/card-ui/public/vite.svg +1 -0
  64. entari_plugin_hyw/card-ui/src/App.vue +412 -0
  65. entari_plugin_hyw/card-ui/src/assets/vue.svg +1 -0
  66. entari_plugin_hyw/card-ui/src/components/HelloWorld.vue +41 -0
  67. entari_plugin_hyw/card-ui/src/components/MarkdownContent.vue +386 -0
  68. entari_plugin_hyw/card-ui/src/components/SectionCard.vue +41 -0
  69. entari_plugin_hyw/card-ui/src/components/StageCard.vue +237 -0
  70. entari_plugin_hyw/card-ui/src/main.ts +5 -0
  71. entari_plugin_hyw/card-ui/src/style.css +29 -0
  72. entari_plugin_hyw/card-ui/src/test_regex.js +103 -0
  73. entari_plugin_hyw/card-ui/src/types.ts +52 -0
  74. entari_plugin_hyw/card-ui/tsconfig.app.json +16 -0
  75. entari_plugin_hyw/card-ui/tsconfig.json +7 -0
  76. entari_plugin_hyw/card-ui/tsconfig.node.json +26 -0
  77. entari_plugin_hyw/card-ui/vite.config.ts +16 -0
  78. entari_plugin_hyw/history.py +170 -0
  79. entari_plugin_hyw/image_cache.py +274 -0
  80. entari_plugin_hyw/misc.py +128 -0
  81. entari_plugin_hyw/pipeline.py +1338 -0
  82. entari_plugin_hyw/prompts.py +108 -0
  83. entari_plugin_hyw/render_vue.py +314 -0
  84. entari_plugin_hyw/search.py +696 -0
  85. entari_plugin_hyw-3.5.0rc6.dist-info/METADATA +116 -0
  86. entari_plugin_hyw-3.5.0rc6.dist-info/RECORD +88 -0
  87. entari_plugin_hyw/hyw_core.py +0 -555
  88. entari_plugin_hyw-2.2.5.dist-info/METADATA +0 -135
  89. entari_plugin_hyw-2.2.5.dist-info/RECORD +0 -6
  90. {entari_plugin_hyw-2.2.5.dist-info → entari_plugin_hyw-3.5.0rc6.dist-info}/WHEEL +0 -0
  91. {entari_plugin_hyw-2.2.5.dist-info → entari_plugin_hyw-3.5.0rc6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,412 @@
1
+ <script setup lang="ts">
2
+ import { ref, computed, onMounted } from 'vue'
3
+ import { Icon } from '@iconify/vue'
4
+
5
+ import type { RenderData } from './types'
6
+ import StageCard from './components/StageCard.vue'
7
+ import MarkdownContent from './components/MarkdownContent.vue'
8
+
9
+ // Get icon for card type
10
+ const getCardIcon = (contentType?: string): string => {
11
+ switch (contentType) {
12
+ case 'summary': return 'mdi:file-document-outline'
13
+ case 'code': return 'mdi:code-braces'
14
+ case 'table': return 'mdi:table'
15
+ default: return 'mdi:card-outline'
16
+ }
17
+ }
18
+
19
+ // Get display label for card
20
+ const getCardLabel = (contentType?: string, language?: string): string => {
21
+ switch (contentType) {
22
+ case 'summary': return 'Summary'
23
+ case 'code': return language ? language.charAt(0).toUpperCase() + language.slice(1) : 'Code'
24
+ case 'table': return 'Table'
25
+ default: return ''
26
+ }
27
+ }
28
+
29
+ declare global {
30
+ interface Window {
31
+ RENDER_DATA: RenderData
32
+ updateRenderData: (data: RenderData) => void
33
+ }
34
+ }
35
+
36
+ const data = ref<RenderData | null>(null)
37
+
38
+ // Expose update method for Python to call
39
+ window.updateRenderData = (newData: RenderData) => {
40
+ data.value = newData
41
+ }
42
+
43
+ const numSearchRefs = computed(() => data.value?.references?.length || 0)
44
+ const numPageRefs = computed(() => data.value?.page_references?.length || 0)
45
+
46
+ // Calculate the reference offset for each stage (for unified badge numbering)
47
+ const getRefOffset = (stageIndex: number): number => {
48
+ if (!data.value?.stages) return 0
49
+ let offset = 0
50
+ for (let i = 0; i < stageIndex; i++) {
51
+ const stage = data.value.stages[i]
52
+ if (stage) {
53
+ offset += (stage.references?.length || 0) + (stage.crawled_pages?.length || 0)
54
+ }
55
+ }
56
+ return offset
57
+ }
58
+
59
+ // Helper: Strips content before the first H1 heading (e.g., AI "thought" prefixes)
60
+ const stripPrefixBeforeH1 = (text: string): string => {
61
+ // Find the first line starting with "# " (H1)
62
+ const h1Match = text.match(/^#\s+/m)
63
+ if (h1Match && h1Match.index !== undefined) {
64
+ // If found, return everything starting from that H1
65
+ // This effectively discards any "thought" blocks or "### ASSISTANT" prefixes appearing before it.
66
+ return text.substring(h1Match.index)
67
+ }
68
+ // If no H1 found, return text as-is (fallback)
69
+ return text
70
+ }
71
+
72
+ const mainTitle = computed(() => {
73
+ const md = stripPrefixBeforeH1(data.value?.markdown || '')
74
+ const match = md.match(/^#\s+(.+)$/m)
75
+ return match && match[1] ? match[1].trim() : ''
76
+ })
77
+
78
+ // Process title to support <u> underline tags
79
+ const processedTitle = computed(() => {
80
+ return mainTitle.value.replace(/<u>([^<]*)<\/u>/g, (_, content) => {
81
+ return `<span class="underline decoration-[5px] underline-offset-8" style="text-decoration-color: var(--theme-color)">${content}</span>`
82
+ })
83
+ })
84
+
85
+
86
+
87
+
88
+ const dedent = (text: string) => {
89
+ const lines = text.split('\n')
90
+ // Find minimum indentation of non-empty lines
91
+ let minIndent = Infinity
92
+ for (const line of lines) {
93
+ if (line.trim().length === 0) continue
94
+ const leadingSpace = line.match(/^\s*/)?.[0].length || 0
95
+ if (leadingSpace < minIndent) minIndent = leadingSpace
96
+ }
97
+
98
+ if (minIndent === Infinity || minIndent === 0) return text
99
+
100
+ return lines.map(line => {
101
+ if (line.trim().length === 0) return ''
102
+ return line.substring(minIndent)
103
+ }).join('\n')
104
+ }
105
+
106
+
107
+ const themeColor = computed(() => data.value?.theme_color || '#ef4444')
108
+
109
+ // Calculate relative luminance to determine if color is light or dark
110
+ const getLuminance = (hex: string): number => {
111
+ const match = hex.replace('#', '').match(/.{2}/g)
112
+ if (!match) return 0
113
+ const [r, g, b] = match.map(x => {
114
+ const c = parseInt(x, 16) / 255
115
+ return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)
116
+ })
117
+ return 0.2126 * (r ?? 0) + 0.7152 * (g ?? 0) + 0.0722 * (b ?? 0)
118
+ }
119
+
120
+ // Auto text color: dark text on light bg, white text on dark bg
121
+ const headerTextColor = computed(() => {
122
+ const luminance = getLuminance(themeColor.value)
123
+ return luminance > 0.4 ? '#1f2937' : '#ffffff' // gray-800 or white
124
+ })
125
+
126
+ const themeStyle = computed(() => ({
127
+ '--theme-color': themeColor.value,
128
+ '--header-text-color': headerTextColor.value,
129
+ '--text-primary': '#2c2c2e', // Warm dark gray for headings (Apple HIG inspired)
130
+ '--text-body': '#3a3a3c', // Softer reading color for body text
131
+ '--text-muted': '#636366', // Muted secondary text
132
+ '--border-color': '#e5e7eb', // gray-200, for borders
133
+ '--bg-subtle': '#f9fafb' // gray-50, for subtle backgrounds
134
+ }))
135
+
136
+
137
+ const parsedSections = computed(() => {
138
+ const rawMd = data.value?.markdown || ''
139
+ if (!rawMd) return []
140
+
141
+ // Robustness: Strip any content (AI thoughts, system role prefixes) before the first H1 heading
142
+ // User request: "Match the first big header, ignore what comes before it" ("匹配第一个大标题 无视前面的")
143
+ const md = stripPrefixBeforeH1(rawMd)
144
+
145
+ let content = md.replace(/^#\s+.+$/m, '')
146
+ content = content.replace(/(?:^|\n)\s*(?:#{1,3}|\*\*)\s*(?:References|Citations|Sources)[\s\S]*$/i, '')
147
+ content = content.trim()
148
+
149
+ const sections: Array<{ type: 'markdown' | 'card', content: string, title?: string, contentType?: 'table' | 'code' | 'summary', language?: string }> = []
150
+
151
+ // Combine regex involves complexity, so we'll use a tokenizer approach
152
+ // split tokens by Code Block or Table
153
+ // split tokens by Code Block or Table or Summary
154
+ const combinedRegex = /(```[\s\S]*?```|((?:^|\n)\|[^\n]*\|(?:\n\|[^\n]*\|)*)|<summary>[\s\S]*?<\/summary>)/
155
+
156
+ let remaining = content
157
+
158
+ while (remaining) {
159
+ const match = remaining.match(combinedRegex)
160
+ if (!match) {
161
+ if (remaining.trim()) {
162
+ sections.push({ type: 'markdown', content: remaining.trim() })
163
+ }
164
+ break
165
+ }
166
+
167
+ const index = match.index!
168
+ const matchedStr = match[0]
169
+ const preText = remaining.substring(0, index)
170
+
171
+ if (preText.trim()) {
172
+ sections.push({ type: 'markdown', content: preText.trim() })
173
+ }
174
+
175
+ // Determine type
176
+ const isCode = matchedStr.startsWith('```')
177
+ const isSummary = matchedStr.startsWith('<summary>')
178
+ // Tables might match with a leading newline, trim it for checking but render carefully
179
+ const isTable = !isCode && !isSummary && matchedStr.trim().startsWith('|')
180
+
181
+ if (isCode || isTable || isSummary) {
182
+ let language = ''
183
+ let content = matchedStr.trim()
184
+
185
+ if (isCode) {
186
+ const match = matchedStr.match(/^```(\w+)/)
187
+ if (match && match[1]) language = match[1]
188
+ } else if (isSummary) {
189
+ // Strip tags
190
+ content = content.replace(/^<summary>/, '').replace(/<\/summary>$/, '')
191
+ content = dedent(content)
192
+ }
193
+
194
+ sections.push({
195
+ type: 'card',
196
+ title: isCode ? 'Code' : (isSummary ? 'Summary' : 'Table'),
197
+ content: content,
198
+ contentType: isCode ? 'code' : (isSummary ? 'summary' : 'table'),
199
+ language: language
200
+ })
201
+ } else {
202
+ // Should not happen if regex is correct, but safe fallback
203
+ sections.push({ type: 'markdown', content: matchedStr })
204
+ }
205
+
206
+ remaining = remaining.substring(index + matchedStr.length)
207
+ }
208
+
209
+ return sections
210
+ })
211
+
212
+ onMounted(() => {
213
+ if (window.RENDER_DATA && Object.keys(window.RENDER_DATA).length > 0) {
214
+ data.value = window.RENDER_DATA
215
+ } else {
216
+ // Demo data for development preview
217
+ data.value = {
218
+ markdown: `# 终极硬核整合包格雷科技新视野
219
+
220
+ <summary>
221
+ 《格雷科技:新视野》(GregTech: New Horizons,简称 GTNH)是一款基于 Minecraft 1.7.10 版本的深度硬核科技向整合包。它以 GregTech 5 Unofficial 为核心,通过超过 8 年的持续开发,将 300 多个模组深度集成,构建了极其严苛且逻辑严密的科技树,是公认的生存挑战巅峰之作。
222
+ </summary>
223
+
224
+ ## 核心机制与游戏体验
225
+ GTNH 的核心在于"格雷化"改造,几乎所有模组的合成表都经过重新设计,以匹配其严苛的阶级制度 [4][8]。玩家需要从原始的石器时代开始,历经蒸汽时代、电力时代,最终向星际航行迈进。其游戏过程极其漫长,旨在让玩家在每一毫秒的进度中感受工业发展的成就感 [3][7]。
226
+
227
+ ![GTNH 游戏场景](https://i.ytimg.com/vi/5T-oSWAgaMM/maxresdefault.jpg)
228
+
229
+ ## 科技阶层与任务系统
230
+ 整合包拥有 15 个清晰的科技等级(Tiers),最终目标是建造"星门"(Stargate)[2]。为了引导玩家不迷失在复杂的工业流程中,GTNH 内置了超过 3900 条任务的巨型任务书,涵盖了从基础生存到高阶多方块结构的详细指导 [4][7]。
231
+
232
+ - 15 个科技等级
233
+ - 任务数量:3900+
234
+ - 最终目标:建造"星门"
235
+
236
+ > 机动战士高达系列是日本动画史上最具影响力的动画作品之一,深受全球观众的喜爱。
237
+
238
+ | 特性 | 详细描述 |
239
+ | :--- | :--- |
240
+ | **基础版本** | Minecraft 1.7.10 (高度优化) |
241
+ | **任务数量** | 3900+ 任务引导 [7] |
242
+ | **科技阶层** | 15 个技术等级 [2] |
243
+ | **核心模组** | GregTech 5 Unofficial, Thaumcraft 等 [8] |
244
+
245
+ ## 安装与运行建议
246
+ 由于其高度集成的特性,官方强烈建议使用 **Prism Launcher** 进行安装和管理 [5]。在运行环境方面,虽然基于旧版 MC,但通过社区努力,目前推荐使用 **Java 17-25** 版本以获得最佳的内存管理和性能优化,确保大型自动化工厂运行流畅 [5]。
247
+
248
+ \`\`\`bash
249
+ curl -s https://raw.githubusercontent.com/GTNewHorizons/GT-New-Horizons-Modpack/master/README.md
250
+ java -version
251
+ java -Xmx1024M -Xms1024M -jar prism-launcher.jar
252
+ \`\`\``,
253
+ total_time: 8.5,
254
+ stages: [
255
+ {
256
+ name: 'instruct',
257
+ model: 'qwen/qwen3-235b-a22b-2507',
258
+ provider: 'Qwen',
259
+ time: 1.83,
260
+ cost: 0.0002,
261
+ },
262
+ {
263
+ name: 'search',
264
+ model: '',
265
+ provider: '',
266
+ time: 0.5,
267
+ cost: 0.0,
268
+ references: [
269
+ { title: 'GTNH 2025 Server Information', url: 'https://stonelegion.com/mc-gtnh-2026/' },
270
+ { title: 'GT New Horizons Wiki', url: 'https://gtnh.miraheze.org/wiki/Main_Page' },
271
+ { title: 'GT New Horizons - GitHub', url: 'https://github.com/GTNewHorizons/GT-New-Horizons-Modpack' },
272
+ { title: 'GT New Horizons - CurseForge', url: 'https://www.curseforge.com/minecraft/modpacks/gt-new-horizons' },
273
+ { title: 'Installing and Migrating - GTNH', url: 'https://gtnh.miraheze.org/wiki/Installing_and_Migrating' },
274
+ { title: 'Modlist - GT New Horizons', url: 'https://wiki.gtnewhorizons.com/wiki/Modlist' },
275
+ { title: 'GregTech: New Horizons - Home', url: 'https://www.gtnewhorizons.com/' },
276
+ { title: 'GT New Horizons - FTB Wiki', url: 'https://ftb.fandom.com/wiki/GT_New_Horizons' }
277
+ ],
278
+ image_references: [
279
+ { title: 'GTNH Live Lets Play', url: 'https://i.ytimg.com/vi/5T-oSWAgaMM/maxresdefault.jpg', thumbnail: 'https://tse4.mm.bing.net/th/id/OIP.b_56VnY4nyrzeqp1JetmFQHaEK?pid=Api' },
280
+ { title: 'GTNH Modpack Cover', url: 'https://i.mcmod.cn/modpack/cover/20240113/1705139595_29797_dSkE.jpg', thumbnail: 'https://tse1.mm.bing.net/th/id/OIP.KNKaZX1d_4Ueq6vpl1qJNAHaEo?pid=Api' },
281
+ { title: 'GTNH Steam Age', url: 'https://i.ytimg.com/vi/8IPwXxqB71w/maxresdefault.jpg', thumbnail: 'https://tse4.mm.bing.net/th/id/OIP.P-KrnI4GBH21yPgwpNPSzAHaEK?pid=Api' },
282
+ { title: 'GTNH MCMod Cover', url: 'https://i.mcmod.cn/post/cover/20230201/1675241030_2_VqDc.jpg', thumbnail: 'https://tse2.mm.bing.net/th/id/OIP.GvYz7YWrg-fnpAHjOiW3OAHaEo?pid=Api' },
283
+ { title: 'GTNH Tectech Tutorial', url: 'http://i0.hdslb.com/bfs/archive/1ed1e53341fd44018138f2823b2fe6c499fb9c9c.jpg', thumbnail: 'https://tse4.mm.bing.net/th/id/OIP.0Wg7xFHTjhxIV9hKuUo4xwHaEo?pid=Api' }
284
+ ]
285
+ },
286
+ {
287
+ name: 'crawler',
288
+ model: '',
289
+ provider: '',
290
+ time: 2.5,
291
+ cost: 0.0,
292
+ crawled_pages: [
293
+ { title: 'GregTech: New Horizons Official Wiki', url: 'https://gtnh.miraheze.org/wiki/Main_Page' },
294
+ { title: 'GT New Horizons Modpack Download', url: 'https://www.curseforge.com/minecraft/modpacks/gt-new-horizons' },
295
+ { title: 'Installing and Migrating Guide', url: 'https://gtnh.miraheze.org/wiki/Installing_and_Migrating' }
296
+ ]
297
+ },
298
+ {
299
+ name: 'agent',
300
+ model: 'google/gemini-3-flash-preview',
301
+ provider: 'Google',
302
+ time: 13.0,
303
+ cost: 0.0018,
304
+ }
305
+ ],
306
+ references: [
307
+ { title: 'GTNH 2025 Server Information', url: 'https://stonelegion.com/mc-gtnh-2026/' },
308
+ { title: 'GT New Horizons Wiki', url: 'https://gtnh.miraheze.org/wiki/Main_Page' },
309
+ { title: 'GT New Horizons - GitHub', url: 'https://github.com/GTNewHorizons/GT-New-Horizons-Modpack' },
310
+ { title: 'GT New Horizons - CurseForge', url: 'https://www.curseforge.com/minecraft/modpacks/gt-new-horizons' },
311
+ { title: 'Installing and Migrating - GTNH', url: 'https://gtnh.miraheze.org/wiki/Installing_and_Migrating' },
312
+ { title: 'Modlist - GT New Horizons', url: 'https://wiki.gtnewhorizons.com/wiki/Modlist' },
313
+ { title: 'GregTech: New Horizons - Home', url: 'https://www.gtnewhorizons.com/' },
314
+ { title: 'GT New Horizons - FTB Wiki', url: 'https://ftb.fandom.com/wiki/GT_New_Horizons' }
315
+ ],
316
+ page_references: [
317
+ { title: 'GregTech: New Horizons Official Wiki', url: 'https://gtnh.miraheze.org/wiki/Main_Page' },
318
+ { title: 'GT New Horizons Modpack Download', url: 'https://www.curseforge.com/minecraft/modpacks/gt-new-horizons' }
319
+ ],
320
+ image_references: [
321
+ { title: 'GTNH Live Lets Play', url: 'https://i.ytimg.com/vi/5T-oSWAgaMM/maxresdefault.jpg', thumbnail: 'https://tse4.mm.bing.net/th/id/OIP.b_56VnY4nyrzeqp1JetmFQHaEK?pid=Api' },
322
+ { title: 'GTNH Modpack Cover', url: 'https://i.mcmod.cn/modpack/cover/20240113/1705139595_29797_dSkE.jpg', thumbnail: 'https://tse1.mm.bing.net/th/id/OIP.KNKaZX1d_4Ueq6vpl1qJNAHaEo?pid=Api' },
323
+ { title: 'GTNH Steam Age', url: 'https://i.ytimg.com/vi/8IPwXxqB71w/maxresdefault.jpg', thumbnail: 'https://tse4.mm.bing.net/th/id/OIP.P-KrnI4GBH21yPgwpNPSzAHaEK?pid=Api' }
324
+ ],
325
+ stats: { total_time: 8.5 },
326
+ theme_color: '#ef4444'
327
+ }
328
+ }
329
+ })
330
+ </script>
331
+
332
+ <template>
333
+ <div class="bg-[#f2f2f2] flex justify-center" :style="themeStyle">
334
+ <!-- Main container with explicit background for screenshot capture -->
335
+ <div id="main-container" class="w-[540px] pt-16 pb-12 space-y-8 !bg-[#f2f2f2]" data-theme="light">
336
+
337
+ <!-- Title -->
338
+ <header v-if="mainTitle" class="px-6 mb-8">
339
+ <!-- Removed Time/Icon Badge as requested -->
340
+ <h1 class="text-4xl font-black leading-tight tracking-tighter uppercase tabular-nums" style="color: var(--text-primary)" v-html="processedTitle"></h1>
341
+ </header>
342
+
343
+ <!-- Content Sections -->
344
+ <template v-for="(section, idx) in parsedSections" :key="idx">
345
+
346
+ <!-- Standard Markdown -->
347
+ <div v-if="section.type === 'markdown'" class="px-7">
348
+ <MarkdownContent
349
+ :markdown="section.content"
350
+ :num-search-refs="numSearchRefs"
351
+ :num-page-refs="numPageRefs"
352
+ class="prose-h2:text-[26px] prose-h2:font-black prose-h2:uppercase prose-h2:tracking-tight prose-h2:mb-4 prose-h2:text-gray-800"
353
+ />
354
+ </div>
355
+
356
+ <!-- Special Card (Table/Code/Summary) -->
357
+ <div v-else-if="section.type === 'card'" class="mx-6 relative">
358
+ <!-- Corner Rectangle Badge with Icon and Label -->
359
+ <div
360
+ class="absolute -top-2 -left-2 h-7 px-2.5 z-10 flex items-center gap-1.5"
361
+ :style="{ backgroundColor: themeColor, color: headerTextColor, boxShadow: '0 2px 4px 0 rgba(0,0,0,0.15)' }"
362
+ >
363
+ <Icon :icon="getCardIcon(section.contentType)" class="text-base" />
364
+ <span class="text-xs font-bold uppercase tracking-wide">{{ getCardLabel(section.contentType, section.language) }}</span>
365
+ </div>
366
+ <div
367
+ class="shadow-sm shadow-black/10 bg-white"
368
+ :class="[
369
+ section.contentType === 'summary' ? 'pt-8 px-5 pb-3 text-base leading-relaxed' : '',
370
+ section.contentType === 'code' ? 'pt-7 pb-2' : '',
371
+ section.contentType === 'table' ? 'pt-5' : ''
372
+ ]"
373
+ >
374
+ <MarkdownContent
375
+ :markdown="section.content"
376
+ :bare="true"
377
+ :num-search-refs="numSearchRefs"
378
+ :num-page-refs="numPageRefs"
379
+ />
380
+ </div>
381
+ </div>
382
+
383
+ </template>
384
+
385
+ <!-- Workflow -->
386
+ <div v-if="data?.stages?.length" class="mx-6 relative">
387
+ <!-- Corner Rectangle Badge with Icon and Label -->
388
+ <div
389
+ class="absolute -top-2 -left-2 h-7 px-2.5 z-10 flex items-center gap-1.5"
390
+ :style="{ backgroundColor: themeColor, color: headerTextColor, boxShadow: '0 2px 4px 0 rgba(0,0,0,0.15)' }"
391
+ >
392
+ <Icon icon="mdi:link-variant" class="text-base" />
393
+ <span class="text-xs font-bold uppercase tracking-wide">Flow</span>
394
+ </div>
395
+ <div class="p-2 pt-5 bg-white shadow-sm shadow-black/10">
396
+ <StageCard
397
+ v-for="(stage, index) in data.stages"
398
+ :key="index"
399
+ :stage="stage"
400
+ :is-first="index === 0"
401
+ :is-last="index === data.stages.length - 1"
402
+ :prev-stage-name="index > 0 ? data.stages[index - 1]?.name : undefined"
403
+ :ref-offset="getRefOffset(index)"
404
+ />
405
+ </div>
406
+ </div>
407
+
408
+ </div>
409
+ </div>
410
+ </template>
411
+
412
+
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
@@ -0,0 +1,41 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+
4
+ defineProps<{ msg: string }>()
5
+
6
+ const count = ref(0)
7
+ </script>
8
+
9
+ <template>
10
+ <h1>{{ msg }}</h1>
11
+
12
+ <div class="card">
13
+ <button type="button" @click="count++">count is {{ count }}</button>
14
+ <p>
15
+ Edit
16
+ <code>components/HelloWorld.vue</code> to test HMR
17
+ </p>
18
+ </div>
19
+
20
+ <p>
21
+ Check out
22
+ <a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
23
+ >create-vue</a
24
+ >, the official Vue + Vite starter
25
+ </p>
26
+ <p>
27
+ Learn more about IDE Support for Vue in the
28
+ <a
29
+ href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
30
+ target="_blank"
31
+ >Vue Docs Scaling up Guide</a
32
+ >.
33
+ </p>
34
+ <p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
35
+ </template>
36
+
37
+ <style scoped>
38
+ .read-the-docs {
39
+ color: #888;
40
+ }
41
+ </style>