Compare commits
2 Commits
59d15108d6
...
9b704919cf
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b704919cf | |||
| 62d704dec0 |
@ -3,6 +3,7 @@ import { AuthFeature, TauriModrinthClient, VerboseLoggingFeature } from '@modrin
|
||||
import {
|
||||
ChangeSkinIcon,
|
||||
CompassIcon,
|
||||
GlobeIcon,
|
||||
DownloadIcon,
|
||||
ExternalIcon,
|
||||
FlaskConicalIcon,
|
||||
@ -735,6 +736,10 @@ const messages = defineMessages({
|
||||
id: 'app.navigation.skin-selector',
|
||||
defaultMessage: 'Skin selector',
|
||||
},
|
||||
starlightSkin: {
|
||||
id: 'app.navigation.starlight-skin',
|
||||
defaultMessage: '斯达莱特',
|
||||
},
|
||||
library: {
|
||||
id: 'app.navigation.library',
|
||||
defaultMessage: 'Library',
|
||||
@ -2314,6 +2319,13 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
>
|
||||
<ChangeSkinIcon />
|
||||
</NavButton>
|
||||
<NavButton
|
||||
v-tooltip.right="formatMessage(messages.starlightSkin)"
|
||||
data-onboarding-id="nav-starlight-skin"
|
||||
to="/starlight-skin"
|
||||
>
|
||||
<GlobeIcon />
|
||||
</NavButton>
|
||||
<NavButton
|
||||
v-tooltip.right="formatMessage(messages.library)"
|
||||
data-onboarding-id="nav-library"
|
||||
|
||||
108
apps/app-frontend/src/components/home/HomeLaunchProgress.vue
Normal file
108
apps/app-frontend/src/components/home/HomeLaunchProgress.vue
Normal file
@ -0,0 +1,108 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DownloadIcon } from '@modrinth/assets'
|
||||
import { defineMessages, useVIntl } from '@modrinth/ui'
|
||||
import { computed, onUnmounted, ref } from 'vue'
|
||||
|
||||
import { loading_listener } from '@/helpers/events'
|
||||
import type { LoadingBar } from '@/helpers/state'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'app.home.launch-progress.title', defaultMessage: '启动进度' },
|
||||
empty: { id: 'app.home.launch-progress.empty', defaultMessage: '启动游戏后,这里会显示进度。' },
|
||||
})
|
||||
|
||||
interface LoadingEventPayload {
|
||||
event: LoadingBar['bar_type']
|
||||
loader_uuid: string
|
||||
fraction: number | null
|
||||
message: string
|
||||
}
|
||||
|
||||
interface LaunchProgressItem {
|
||||
key: string
|
||||
message: string
|
||||
fraction: number | null
|
||||
}
|
||||
|
||||
// 启动相关(以及准备)阶段会发的 loading 类型;安装/下载也一并显示,便于用户看到进度
|
||||
const LAUNCH_BAR_TYPES = new Set([
|
||||
'minecraft_download',
|
||||
'instance_update',
|
||||
'zip_extract',
|
||||
'pack_download',
|
||||
'pack_file_download',
|
||||
])
|
||||
|
||||
const progressItems = ref<LaunchProgressItem[]>([])
|
||||
const activeMap = new Map<string, LaunchProgressItem>()
|
||||
|
||||
function isVisible(barType: LoadingBar['bar_type']): boolean {
|
||||
const type = barType?.type ?? ''
|
||||
return LAUNCH_BAR_TYPES.has(type)
|
||||
}
|
||||
|
||||
function applyEvent(payload: LoadingEventPayload) {
|
||||
// fraction 为 null 约定为「完成」,移除该进度条
|
||||
if (payload.fraction === null) {
|
||||
activeMap.delete(payload.loader_uuid)
|
||||
progressItems.value = Array.from(activeMap.values())
|
||||
return
|
||||
}
|
||||
if (!isVisible(payload.event)) return
|
||||
|
||||
activeMap.set(payload.loader_uuid, {
|
||||
key: payload.loader_uuid,
|
||||
message: payload.message,
|
||||
fraction: payload.fraction,
|
||||
})
|
||||
progressItems.value = Array.from(activeMap.values())
|
||||
}
|
||||
|
||||
const hasProgress = computed(() => progressItems.value.length > 0)
|
||||
|
||||
function percent(item: LaunchProgressItem): string {
|
||||
if (item.fraction == null || !Number.isFinite(item.fraction)) return ''
|
||||
return `${Math.round(Math.max(0, Math.min(1, item.fraction)) * 100)}%`
|
||||
}
|
||||
|
||||
const unlistenLoading = await loading_listener((payload: LoadingEventPayload) => {
|
||||
applyEvent(payload)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
unlistenLoading?.()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
v-if="hasProgress"
|
||||
class="flex min-w-0 flex-col gap-3 border-0 border-b-[1px] border-solid border-[--brand-gradient-border] p-4"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<DownloadIcon class="size-4 shrink-0 text-secondary" aria-hidden="true" />
|
||||
<h2 class="m-0 truncate text-lg">
|
||||
{{ formatMessage(messages.title) }}
|
||||
</h2>
|
||||
</div>
|
||||
<ul class="m-0 flex list-none flex-col gap-2 p-0">
|
||||
<li v-for="item in progressItems" :key="item.key" class="flex min-w-0 flex-col gap-1">
|
||||
<div class="flex min-w-0 items-center justify-between gap-2 text-sm text-primary">
|
||||
<span class="min-w-0 truncate">{{ item.message }}</span>
|
||||
<span v-if="percent(item)" class="shrink-0 tabular-nums text-secondary">
|
||||
{{ percent(item) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="h-1 w-full overflow-hidden rounded-full bg-surface-4">
|
||||
<div
|
||||
class="h-full rounded-full bg-brand transition-[width] duration-200"
|
||||
:style="{ width: percent(item) || '100%' }"
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</template>
|
||||
@ -21,7 +21,7 @@
|
||||
"name": "CodeZhangBorui",
|
||||
"avatarUrl": "https://avatars.githubusercontent.com/u/61909157?v=4&s=96",
|
||||
"url": "https://github.com/CodeZhangBorui",
|
||||
"contributions": 444
|
||||
"contributions": 446
|
||||
},
|
||||
{
|
||||
"name": "IMB11",
|
||||
@ -147,7 +147,7 @@
|
||||
"name": "xinvxueyuan",
|
||||
"avatarUrl": "https://avatars.githubusercontent.com/u/149921651?v=4&s=96",
|
||||
"url": "https://github.com/xinvxueyuan",
|
||||
"contributions": 42
|
||||
"contributions": 43
|
||||
},
|
||||
{
|
||||
"name": "piprett",
|
||||
|
||||
@ -30,6 +30,7 @@ import HomeDashboard from '@/components/home/HomeDashboard.vue'
|
||||
import HomeInstancePickerModal from '@/components/home/HomeInstancePickerModal.vue'
|
||||
import HomeMinecraftNews from '@/components/home/HomeMinecraftNews.vue'
|
||||
import HomeMinimal from '@/components/home/HomeMinimal.vue'
|
||||
import HomeLaunchProgress from '@/components/home/HomeLaunchProgress.vue'
|
||||
import HomePlayInsights from '@/components/home/HomePlayInsights.vue'
|
||||
import { useNetworkStatus } from '@/composables/useNetworkStatus'
|
||||
import { get_default_user, users } from '@/helpers/auth'
|
||||
@ -378,6 +379,7 @@ onUnmounted(() => {
|
||||
class="flex min-w-0 flex-col slide-enter-active"
|
||||
:class="{ 'slide-enter-from': !animateSidebarShow }"
|
||||
>
|
||||
<HomeLaunchProgress />
|
||||
<HomePlayInsights />
|
||||
<HomeDailyChallenge />
|
||||
<HomeMinecraftNews />
|
||||
|
||||
41
apps/app-frontend/src/pages/StarlightSkin.vue
Normal file
41
apps/app-frontend/src/pages/StarlightSkin.vue
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineMessages, useVIntl } from '@modrinth/ui'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const messages = defineMessages({
|
||||
title: {
|
||||
id: 'app.starlight-skin.title',
|
||||
defaultMessage: '斯达莱特',
|
||||
},
|
||||
frameTitle: {
|
||||
id: 'app.starlight-skin.frame-title',
|
||||
defaultMessage: 'StarLight Skin Site',
|
||||
},
|
||||
})
|
||||
|
||||
const SKIN_SITE_URL = 'https://skin.starlight.cool/'
|
||||
|
||||
const loading = ref(true)
|
||||
|
||||
function onLoad() {
|
||||
loading.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex h-full min-h-0 flex-col">
|
||||
<div v-if="loading" class="flex flex-1 items-center justify-center">
|
||||
<span class="text-secondary">{{ formatMessage(messages.title) }}…</span>
|
||||
</div>
|
||||
<iframe
|
||||
:src="SKIN_SITE_URL"
|
||||
:title="formatMessage(messages.frameTitle)"
|
||||
class="h-full min-h-0 w-full flex-1 border-0"
|
||||
:class="loading ? 'hidden' : ''"
|
||||
@load="onLoad"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -93,6 +93,14 @@ export default new createRouter({
|
||||
discordActivity: 'Changing skins...',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/starlight-skin',
|
||||
name: 'Starlight skin',
|
||||
component: () => import('@/pages/StarlightSkin.vue'),
|
||||
meta: {
|
||||
breadcrumb: [{ name: 'Starlight skin' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/multiplayer',
|
||||
name: 'Multiplayer',
|
||||
|
||||
@ -117,7 +117,8 @@
|
||||
"style-src": "'unsafe-inline' 'self'",
|
||||
"script-src": "'self' 'unsafe-eval' 'wasm-unsafe-eval'",
|
||||
"worker-src": "'self' blob:",
|
||||
"frame-src": "https://www.youtube.com https://www.youtube-nocookie.com https://discord.com 'self' http://axolotl-skin.localhost axolotl-skin://localhost",
|
||||
|
||||
"frame-src": "https://www.youtube.com https://www.youtube-nocookie.com https://discord.com 'self' http://axolotl-skin.localhost axolotl-skin://localhost https://skin.starlight.cool",
|
||||
"media-src": "'self' data: https://*.githubusercontent.com"
|
||||
},
|
||||
"csp": {
|
||||
@ -127,8 +128,7 @@
|
||||
"img-src": "https: 'unsafe-inline' 'self' asset: http://asset.localhost http://textures.minecraft.net blob: data:",
|
||||
"style-src": "'unsafe-inline' 'self'",
|
||||
"script-src": "'self' 'unsafe-eval' 'wasm-unsafe-eval'",
|
||||
"worker-src": "'self' blob:",
|
||||
"frame-src": "https://www.youtube.com https://www.youtube-nocookie.com https://discord.com 'self' axolotl-skin://localhost http://axolotl-skin.localhost",
|
||||
"frame-src": "https://www.youtube.com https://www.youtube-nocookie.com https://discord.com 'self' axolotl-skin://localhost http://axolotl-skin.localhost https://skin.starlight.cool",
|
||||
"media-src": "'self' data: https://*.githubusercontent.com"
|
||||
}
|
||||
}
|
||||
|
||||
59
tools/icon_work/add_nav.py
Normal file
59
tools/icon_work/add_nav.py
Normal file
@ -0,0 +1,59 @@
|
||||
|
||||
p = r"D:\Project\Starlight_Lancher\apps\app-frontend\src\App.vue"
|
||||
lines = open(p, encoding="utf-8").read().split("\n")
|
||||
|
||||
# 1) import 加 GlobeIcon:在第 5 行(CompassIcon)后、第 4 行(ChangeSkinIcon)开始那个块里
|
||||
# 找到 "CompassIcon," 那行,在其后插 "GlobeIcon,"
|
||||
imp_idx = None
|
||||
for i, ln in enumerate(lines):
|
||||
if ln.strip() == "CompassIcon,":
|
||||
imp_idx = i
|
||||
break
|
||||
assert imp_idx is not None, "找不到 CompassIcon import"
|
||||
lines.insert(imp_idx + 1, "\tGlobeIcon,")
|
||||
|
||||
# 2) messages 加 starlightSkin:在 skinSelector 块结束的 '},' (原737) 后插
|
||||
# 因为上面插了1行,行号+1。重新定位 skinSelector 块
|
||||
skin_msg_idx = None
|
||||
for i, ln in enumerate(lines):
|
||||
if "app.navigation.skin-selector" in ln:
|
||||
# 找它下面的 '},'
|
||||
for j in range(i, i + 5):
|
||||
if lines[j].strip() == "},":
|
||||
skin_msg_idx = j
|
||||
break
|
||||
break
|
||||
assert skin_msg_idx is not None, "找不到 skinSelector 消息块结尾"
|
||||
new_msg = [
|
||||
"\tstarlightSkin: {",
|
||||
"\t\tid: 'app.navigation.starlight-skin',",
|
||||
"\t\tdefaultMessage: '斯达莱特',",
|
||||
"\t},",
|
||||
]
|
||||
lines[skin_msg_idx + 1:skin_msg_idx + 1] = new_msg
|
||||
|
||||
# 3) 模板加 NavButton:在 skin selector 的 </NavButton> (原2316) 后
|
||||
# 找 'nav-skins' 的块结尾 </NavButton>
|
||||
nav_idx = None
|
||||
for i, ln in enumerate(lines):
|
||||
if 'data-onboarding-id="nav-skins"' in ln:
|
||||
for j in range(i, i + 10):
|
||||
if "</NavButton>" in lines[j]:
|
||||
nav_idx = j
|
||||
break
|
||||
break
|
||||
assert nav_idx is not None, "找不到 nav-skins 的 NavButton 结尾"
|
||||
new_nav = [
|
||||
"\t\t\t\t<NavButton",
|
||||
'\t\t\t\t\tv-tooltip.right="formatMessage(messages.starlightSkin)"',
|
||||
'\t\t\t\t\tdata-onboarding-id="nav-starlight-skin"',
|
||||
'\t\t\t\t\tto="/starlight-skin"',
|
||||
"\t\t\t\t>",
|
||||
"\t\t\t\t\t<GlobeIcon />",
|
||||
"\t\t\t\t</NavButton>",
|
||||
]
|
||||
lines[nav_idx + 1:nav_idx + 1] = new_nav
|
||||
|
||||
open(p, "w", encoding="utf-8", newline="\n").write("\n".join(lines))
|
||||
print("完成。")
|
||||
print("import 行:", lines[imp_idx], "->", lines[imp_idx+1])
|
||||
27
tools/icon_work/add_route.py
Normal file
27
tools/icon_work/add_route.py
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
p = r"D:\Project\Starlight_Lancher\apps\app-frontend\src\routes.js"
|
||||
lines = open(p, encoding="utf-8").read().split("\n")
|
||||
|
||||
# 在第 95 行 (idx 94) 的 '},' 之后插入新路由;即 idx 95 前插
|
||||
anchor_idx = 95 # 0-based, 原第96行 '{'
|
||||
# 校验
|
||||
assert lines[94].strip() == "},", f"第95行不是 '}},' 而是: {lines[94]!r}"
|
||||
assert lines[95].strip() == "{", f"第96行不是 '{{' 而是: {lines[95]!r}"
|
||||
|
||||
new_route = [
|
||||
"\t\t{",
|
||||
"\t\t\tpath: '/starlight-skin',",
|
||||
"\t\t\tname: 'Starlight skin',",
|
||||
"\t\t\tcomponent: () => import('@/pages/StarlightSkin.vue'),",
|
||||
"\t\t\tmeta: {",
|
||||
"\t\t\t\tbreadcrumb: [{ name: 'Starlight skin' }],",
|
||||
"\t\t\t},",
|
||||
"\t\t},",
|
||||
]
|
||||
lines[95:95] = new_route
|
||||
open(p, "w", encoding="utf-8", newline="\n").write("\n".join(lines))
|
||||
print("插入完成,新行数:", len(lines))
|
||||
print("--- 插入区 86-105 ---")
|
||||
for i in range(85, 106):
|
||||
if i < len(lines):
|
||||
print(f"{i+1}: {lines[i]}")
|
||||
8
tools/icon_work/check_exe_icon.py
Normal file
8
tools/icon_work/check_exe_icon.py
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
p = r"D:\Project\Starlight_Lancher\target\release\Starlight Launcher.exe"
|
||||
data = open(p, "rb").read()
|
||||
print("exe 大小:", len(data))
|
||||
print("内嵌 PNG 数量(粗估):", data.count(b"\x89PNG\r\n\x1a\n"))
|
||||
ico = open(r"D:\Project\Starlight_Lancher\apps\app\icons\icon.ico", "rb").read()
|
||||
print("icon.ico 大小:", len(ico))
|
||||
print("icon.ico 原样出现在 exe:", ico in data)
|
||||
42
tools/icon_work/extract_ico.py
Normal file
42
tools/icon_work/extract_ico.py
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
import struct
|
||||
|
||||
p = r"D:\Project\Starlight_Lancher\target\release\Starlight Launcher.exe"
|
||||
data = open(p, "rb").read()
|
||||
|
||||
# 粗解析 PE,找 .rsrc 段的 RT_GROUP_ICON 和 RT_ICON
|
||||
# 简化:直接找所有 PNG(现代 ico 用 png 存大图)和 BMP(ico用)
|
||||
# 提取第一个 PNG 看尺寸
|
||||
import io
|
||||
PNG_SIG = b"\x89PNG\r\n\x1a\n"
|
||||
results = []
|
||||
idx = 0
|
||||
while True:
|
||||
i = data.find(PNG_SIG, idx)
|
||||
if i < 0:
|
||||
break
|
||||
# PNG IHDR: 宽高在 sig 后 16 字节起 (8 sig + 4 len + 4 'IHDR' = 16)
|
||||
try:
|
||||
w = struct.unpack(">I", data[i+16:i+20])[0]
|
||||
h = struct.unpack(">I", data[i+20:i+24])[0]
|
||||
if 8 <= w <= 1024 and 8 <= h <= 1024:
|
||||
results.append((i, w, h))
|
||||
except Exception:
|
||||
pass
|
||||
idx = i + 8
|
||||
|
||||
print("找到疑似图标 PNG (offset,w,h) 前 30 个:")
|
||||
for r in results[:30]:
|
||||
print(r)
|
||||
|
||||
# 对比:icon.ico 里各图像尺寸
|
||||
ico = open(r"D:\Project\Starlight_Lancher\apps\app\icons\icon.ico", "rb").read()
|
||||
n = struct.unpack("<H", ico[4:6])[0]
|
||||
print(f"\nicon.ico 含 {n} 个图像:")
|
||||
off = 6
|
||||
for k in range(n):
|
||||
w = ico[off] or 256
|
||||
h = ico[off+1] or 256
|
||||
size = struct.unpack("<I", ico[off+8:off+12])[0]
|
||||
print(f" 图像{k}: {w}x{h}, {size} bytes")
|
||||
off += 16
|
||||
13
tools/icon_work/fix_csp.py
Normal file
13
tools/icon_work/fix_csp.py
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
p = r"D:\Project\Starlight_Lancher\apps\app\tauri.conf.json"
|
||||
lines = open(p, encoding="utf-8").read().split("\n")
|
||||
correct = ' "frame-src": "https://www.youtube.com https://www.youtube-nocookie.com https://discord.com \'self\' axolotl-skin://localhost http://axolotl-skin.localhost https://skin.starlight.cool",'
|
||||
print("BEFORE 129-135:")
|
||||
for i in range(128, 135):
|
||||
print(f"{i+1}: {lines[i]}")
|
||||
# 合并 131-134 (idx 130..133) 为一行
|
||||
lines[130:134] = [correct]
|
||||
open(p, "w", encoding="utf-8", newline="\n").write("\n".join(lines))
|
||||
print("AFTER 128-135:")
|
||||
for i in range(127, 135):
|
||||
print(f"{i+1}: {lines[i]}")
|
||||
26
tools/icon_work/fix_lp.py
Normal file
26
tools/icon_work/fix_lp.py
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
p = r"D:\Project\Starlight_Lancher\apps\app-frontend\src\components\home\HomeLaunchProgress.vue"
|
||||
t = open(p, encoding="utf-8").read()
|
||||
|
||||
# 1) 给最外层 section 加 v-if
|
||||
t = t.replace(
|
||||
'\t<section\n\t\tclass="flex min-w-0 flex-col gap-3 border-0 border-b-[1px] border-solid border-[--brand-gradient-border] p-4"\n\t>',
|
||||
'\t<section\n\t\tv-if="hasProgress"\n\t\tclass="flex min-w-0 flex-col gap-3 border-0 border-b-[1px] border-solid border-[--brand-gradient-border] p-4"\n\t>',
|
||||
)
|
||||
|
||||
# 2) 删空态 <p v-if="!hasProgress">...</p>
|
||||
import re
|
||||
t = re.sub(
|
||||
r'\t\t<p v-if="!hasProgress"[^>]*>\n\t\t\t\{\{ formatMessage\(messages\.empty\) \}\}\n\t\t</p>\n',
|
||||
"",
|
||||
t,
|
||||
)
|
||||
|
||||
# 3) <ul v-else ...> 改 <ul ...>
|
||||
t = t.replace('<ul v-else class="m-0 flex list-none flex-col gap-2 p-0">', '<ul class="m-0 flex list-none flex-col gap-2 p-0">')
|
||||
|
||||
open(p, "w", encoding="utf-8", newline="\n").write(t)
|
||||
print("done")
|
||||
print("--- 78-95 ---")
|
||||
for i, line in enumerate(t.split("\n")[77:95], 78):
|
||||
print(f"{i}: {line}")
|
||||
BIN
tools/icon_work/icon_test_copy.exe
Normal file
BIN
tools/icon_work/icon_test_copy.exe
Normal file
Binary file not shown.
6
tools/icon_work/read_emit.py
Normal file
6
tools/icon_work/read_emit.py
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
import glob
|
||||
for f in glob.glob("packages/app-lib/src/event/*.rs"):
|
||||
print("=== " + f + " ===")
|
||||
print(open(f, encoding="utf-8").read()[:4000])
|
||||
print()
|
||||
5
tools/icon_work/scan_launch.py
Normal file
5
tools/icon_work/scan_launch.py
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
l = open("packages/app-lib/src/launcher/mod.rs", encoding="utf-8").read().split("\n")
|
||||
for i, line in enumerate(l):
|
||||
if "init_loading" in line or "emit_loading" in line or "MinecraftDownload" in line or "InstanceUpdate" in line:
|
||||
print(f"{i+1}: {line.strip()}")
|
||||
29
tools/icon_work/wire_lp.py
Normal file
29
tools/icon_work/wire_lp.py
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
p = r"D:\Project\Starlight_Lancher\apps\app-frontend\src\pages\Index.vue"
|
||||
lines = open(p, encoding="utf-8").read().split("\n")
|
||||
|
||||
# 1) import:在 HomePlayInsights import 行后加一行
|
||||
imp_i = None
|
||||
for i, ln in enumerate(lines):
|
||||
if "import HomePlayInsights from '@/components/home/HomePlayInsights.vue'" in ln:
|
||||
imp_i = i
|
||||
break
|
||||
assert imp_i is not None, "找不到 HomePlayInsights import"
|
||||
lines.insert(imp_i, "import HomeLaunchProgress from '@/components/home/HomeLaunchProgress.vue'")
|
||||
|
||||
# 2) 模板:在 <HomePlayInsights /> 前插入 <HomeLaunchProgress />
|
||||
tpl_i = None
|
||||
for i, ln in enumerate(lines):
|
||||
if ln.strip() == "<HomePlayInsights />":
|
||||
tpl_i = i
|
||||
break
|
||||
assert tpl_i is not None, "找不到 <HomePlayInsights />"
|
||||
lines.insert(tpl_i, "\t\t\t<HomeLaunchProgress />")
|
||||
|
||||
open(p, "w", encoding="utf-8", newline="\n").write("\n".join(lines))
|
||||
print("done")
|
||||
for i in range(imp_i - 1, imp_i + 2):
|
||||
print(f"{i+1}: {lines[i]}")
|
||||
print("...")
|
||||
for i in range(tpl_i - 2, tpl_i + 3):
|
||||
print(f"{i+1}: {lines[i]}")
|
||||
Reference in New Issue
Block a user