Compare commits

...
Author SHA1 Message Date
AxTps d2c32ed14f style: 修正 feature_flags 反序列化处的 rustfmt 格式,修复 release preflight 失败
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
Starlight release / Release preflight (push) Has been cancelled
Prepare pnpm cache / prepare (push) Has been cancelled
Starlight release / Build (Windows x64) (push) Has been cancelled
Starlight release / Build (Linux arm64) (push) Has been cancelled
Starlight release / Build (Linux x64) (push) Has been cancelled
Starlight release / Build (macOS universal) (push) Has been cancelled
Starlight release / Verify and publish (push) Has been cancelled
2026-10-02 20:47:19 +08:00
AxTps 4b9b9ebf47 docs: 添加 1.0.1-beta10 更新公告
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
Starlight release / Release preflight (push) Has been cancelled
Starlight release / Build (Windows x64) (push) Has been cancelled
Starlight release / Build (Linux arm64) (push) Has been cancelled
Starlight release / Build (Linux x64) (push) Has been cancelled
Starlight release / Build (macOS universal) (push) Has been cancelled
Starlight release / Verify and publish (push) Has been cancelled
Prepare pnpm cache / prepare (push) Has been cancelled
2026-10-02 20:42:12 +08:00
AxTps 457dfd8c30 refactor: App.vue 整包写回改为始终基于最新设置,彻底消除旧快照覆盖隐患
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
2026-10-02 20:38:31 +08:00
AxTps 8ec5cf104c chore: 补充实例页导览四步的 en-US 文案
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
2026-10-02 20:29:12 +08:00
AxTps 306328367e feat: 重做实例页导览为内容/文件/世界/日志四步,并修复 inspect 步点导览气泡无法继续的问题 2026-10-02 20:24:20 +08:00
AxTps 3901749d93 fix: 皮肤站内嵌 iframe 显式委派 clipboard-write/read 权限,修复无法复制 2026-10-02 20:06:24 +08:00
AxTps cee0c3bbd4 fix: 批量编辑分组失败时改用 handleError 提示,不再静默吞掉异常 2026-10-02 20:04:07 +08:00
AxTps 63ca20db04 fix: edit_to_core 仅在相关字段变更时才带 content_set/launch_overrides patch,修复无 content set 的实例改分组失败 2026-10-02 20:00:49 +08:00
AxTps 0388e339db feat: 安装位置选到盘符根时自动追加 Starlight 子目录,避免文件散落根目录
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
2026-10-02 19:44:45 +08:00
AxTps d4554b0f4c fix: onboarding/locale 整包写回前用 themeStore 回填 feature_flags,避免功能开关被旧快照覆盖 2026-10-02 19:27:57 +08:00
AxTps d5471bb36c fix: feature_flags 反序列化忽略未知开关,避免前后端枚举不同步导致启动崩溃 2026-10-02 19:16:45 +08:00
AxTps f238eeae0e fix: 界面缩放持久化被 onboarding/locale 整包写回覆盖,保存前用最新 uiScale 回填 2026-10-02 19:02:48 +08:00
AxTps ae9a762439 fix: 修复 routes.js 中多人联机子路由缺失对象起始括号导致的语法错误
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
Starlight release / Release preflight (push) Has been cancelled
Prepare pnpm cache / prepare (push) Has been cancelled
Starlight release / Build (Windows x64) (push) Has been cancelled
Starlight release / Build (Linux arm64) (push) Has been cancelled
Starlight release / Build (Linux x64) (push) Has been cancelled
Starlight release / Build (macOS universal) (push) Has been cancelled
Starlight release / Verify and publish (push) Has been cancelled
2026-10-02 15:07:58 +08:00
AxTps 8480927b99 docs: 添加 1.0.1-beta9 更新公告
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
Starlight release / Release preflight (push) Has been cancelled
Starlight release / Build (Windows x64) (push) Has been cancelled
Starlight release / Build (Linux arm64) (push) Has been cancelled
Starlight release / Build (Linux x64) (push) Has been cancelled
Starlight release / Build (macOS universal) (push) Has been cancelled
Starlight release / Verify and publish (push) Has been cancelled
Prepare pnpm cache / prepare (push) Has been cancelled
2026-10-02 14:24:25 +08:00
AxTps 24f5761317 fix: 补齐 FeatureFlag 枚举的 MultiplayerInApp,修复极简主页 settings_set 反序列化报错
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
2026-10-02 13:43:34 +08:00
AxTps 3d003f9b31 fix: 多人游戏根路径重定向到房间页
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
2026-10-02 13:23:37 +08:00
AxTps 1b487da5c2 fix: 修复截图中心菜单/编辑不可用与导航项缺中文
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
2026-10-02 13:20:04 +08:00
AxTps b310018c38 docs: 添加 1.0.1-beta8 更新公告
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
Sync LobeHub models / sync (push) Has been cancelled
Starlight release / Release preflight (push) Has been cancelled
Prepare pnpm cache / prepare (push) Has been cancelled
Starlight release / Build (Windows x64) (push) Has been cancelled
Starlight release / Build (Linux arm64) (push) Has been cancelled
Starlight release / Build (Linux x64) (push) Has been cancelled
Starlight release / Build (macOS universal) (push) Has been cancelled
Starlight release / Verify and publish (push) Has been cancelled
2026-10-02 11:03:59 +08:00
AxTps fbde37f5a0 fix: 补全新增 command 的 Tauri 权限
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
2026-10-02 10:58:11 +08:00
AxTps e6f9987694 fix: 修复侧边栏导航项损坏与 hosted_has_game_account 权限缺失 2026-10-02 10:50:53 +08:00
AxTps 5a08a1ed3a fix: 修复公告目录缺失的对象起始括号
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
Starlight release / Release preflight (push) Has been cancelled
Prepare pnpm cache / prepare (push) Has been cancelled
Starlight release / Build (Windows x64) (push) Has been cancelled
Starlight release / Build (Linux arm64) (push) Has been cancelled
Starlight release / Build (Linux x64) (push) Has been cancelled
Starlight release / Build (macOS universal) (push) Has been cancelled
Starlight release / Verify and publish (push) Has been cancelled
2026-10-02 09:09:53 +08:00
AxTps e51abeb5ad docs: 添加 1.0.1-beta7 更新公告
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
2026-10-02 08:26:24 +08:00
Ap_Tx 4c13f849eb Merge pull request #5 from ApTx2012/feat/screenshot-center
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
Prepare pnpm cache / prepare (push) Has been cancelled
feat: 移植截图中心(浏览/分组/编辑/导出)
2026-10-02 08:21:07 +08:00
18 changed files with 453 additions and 81 deletions

No files matched your search

+5 -5
View File
@@ -764,13 +764,13 @@ const messages = defineMessages({
defaultMessage: 'Library', defaultMessage: 'Library',
}, },
multiplayer: { multiplayer: {
screenshots: {
id: 'app.navigation.screenshots',
defaultMessage: 'Screenshots',
},
id: 'app.navigation.multiplayer', id: 'app.navigation.multiplayer',
defaultMessage: 'Multiplayer', defaultMessage: 'Multiplayer',
}, },
screenshots: {
id: 'app.navigation.screenshots',
defaultMessage: 'Screenshots',
},
downloads: { downloads: {
id: 'app.navigation.downloads', id: 'app.navigation.downloads',
defaultMessage: 'Downloads', defaultMessage: 'Downloads',
@@ -1260,7 +1260,7 @@ async function replayOnboarding(mode) {
async function finishOnboarding() { async function finishOnboarding() {
const wasReplay = onboardingReplay.value const wasReplay = onboardingReplay.value
const settings = onboardingSettings.value ?? (await getSettings()) const settings = await getSettings()
if (!onboardingReplay.value) { if (!onboardingReplay.value) {
if (onboardingMode.value === 'instance') { if (onboardingMode.value === 'instance') {
settings.onboarding_instance_tour_completed = true settings.onboarding_instance_tour_completed = true
@@ -32,6 +32,143 @@ export const ANNOUNCEMENT_CHANGE_TYPES: readonly AnnouncementChangeType[] = [
] ]
export const launcherAnnouncements: readonly LauncherAnnouncement[] = [ export const launcherAnnouncements: readonly LauncherAnnouncement[] = [
{
id: 'launcher-1.0.1-beta10',
version: '1.0.1-beta10',
publishedAt: '2026-10-02',
title: {
'en-US': 'Starlight Launcher 1.0.1-beta10',
'zh-CN': 'Starlight Launcher 1.0.1-beta10',
},
changes: {
added: [
{
'en-US': 'Reworked the instance-page tour into four steps covering content, files, worlds, and logs.',
'zh-CN': '重做实例页导览,分为内容、文件、世界、日志四步。',
},
{
'en-US': 'When the install location is a drive root, the installer now creates a Starlight subfolder automatically.',
'zh-CN': '安装位置选到盘符根目录时,安装器会自动创建 Starlight 子文件夹。',
},
],
fixed: [
{
'en-US': 'Fixed the launcher UI scale reverting after a restart.',
'zh-CN': '修复启动器界面缩放重启后恢复原状的问题。',
},
{
'en-US': 'Fixed developer feature flags not saving.',
'zh-CN': '修复开发者功能开关无法保存的问题。',
},
{
'en-US': 'Fixed instance group edits not saving for instances without an applied content set.',
'zh-CN': '修复没有应用内容集的实例无法保存分组修改的问题。',
},
{
'en-US': 'Fixed the launcher crashing on startup when feature flags were out of sync between the frontend and backend.',
'zh-CN': '修复前后端功能开关不同步导致启动器启动崩溃的问题。',
},
{
'en-US': 'Fixed being unable to copy text inside the embedded skin site.',
'zh-CN': '修复内嵌皮肤站中无法复制文本的问题。',
},
{
'en-US': 'Fixed the onboarding prompt not dismissing when clicking anywhere.',
'zh-CN': '修复导览提示点击任意位置无法关闭的问题。',
},
],
},
},
{
id: 'launcher-1.0.1-beta9',
version: '1.0.1-beta9',
publishedAt: '2026-10-02',
title: {
'en-US': 'Starlight Launcher 1.0.1-beta9',
'zh-CN': 'Starlight Launcher 1.0.1-beta9',
},
changes: {
fixed: [
{
'en-US':
'Fixed a crash on the minimal home layout caused by an unrecognized multiplayer feature flag (missing backend enum variant).',
'zh-CN': '修复多人联机功能开关缺少后端枚举变体、导致精简主页报错的问题。',
},
],
},
},
{
id: 'launcher-1.0.1-beta8',
version: '1.0.1-beta8',
publishedAt: '2026-10-02',
title: {
'en-US': 'Starlight Launcher 1.0.1-beta8',
'zh-CN': 'Starlight Launcher 1.0.1-beta8',
},
changes: {
fixed: [
{
'en-US':
'Fixed the sidebar navigation entries breaking after the screenshot center was added.',
'zh-CN': '修复添加截图中心后侧边栏导航项损坏的问题。',
},
{
'en-US':
'Fixed being unable to install the StarLight hosted pack even after signing in (missing command permission).',
'zh-CN': '修复登录后仍无法安装 StarLight 实例的问题(命令权限缺失)。',
},
{
'en-US':
'Fixed the launcher UI scaling not applying when changed (missing command permission).',
'zh-CN': '修复修改启动器界面缩放后不生效的问题(命令权限缺失)。',
},
{
'en-US':
'Fixed several screenshot center actions failing due to missing command permissions.',
'zh-CN': '修复截图中心部分操作因命令权限缺失而失败的问题。',
},
],
},
},
{
id: 'launcher-1.0.1-beta7',
version: '1.0.1-beta7',
publishedAt: '2026-10-02',
title: {
'en-US': 'Starlight Launcher 1.0.1-beta7',
'zh-CN': 'Starlight Launcher 1.0.1-beta7',
},
changes: {
added: [
{
'en-US':
'Added a screenshot center: browse screenshots across every instance, group them (custom groups, by instance, or by date), preview, edit (crop, rotate, annotate, censor), and export as ZIP.',
'zh-CN':
'新增截图中心:跨实例浏览截图,支持自定义/按实例/按日期分组,可预览、编辑(裁剪、标注、打码等)并导出为 ZIP。',
},
{
'en-US':
'Added the multiplayer (Terracotta) entry to the sidebar, behind a feature flag.',
'zh-CN': '侧边栏新增多人联机(陶瓦)入口,由功能开关控制。',
},
],
changed: [
{
'en-US':
'Launcher UI scaling is now persisted in the backend and applied via native webview zoom, so it scales embedded pages correctly and keeps onboarding anchors aligned.',
'zh-CN':
'启动器界面缩放改为后端持久化,并通过原生 webview 缩放应用,可正确缩放内嵌页面且导览锚点不再偏移。',
},
],
fixed: [
{
'en-US':
'Fixed the onboarding tour skipping its first step when the target anchor was missing.',
'zh-CN': '修复导览首步在目标锚点缺失时被自动跳过的问题。',
},
],
},
},
{ {
id: 'launcher-1.0.1-beta6', id: 'launcher-1.0.1-beta6',
version: '1.0.1-beta6', version: '1.0.1-beta6',
@@ -16,6 +16,7 @@ const messages = defineMessages({
<template> <template>
<iframe <iframe
:src="skinSiteFrameUrl" :src="skinSiteFrameUrl"
allow="clipboard-write; clipboard-read"
:title="formatMessage(messages.frameTitle)" :title="formatMessage(messages.frameTitle)"
class="block h-full min-h-0 w-full border-0" class="block h-full min-h-0 w-full border-0"
/> />
@@ -61,6 +61,7 @@ import {
ButtonStyled, ButtonStyled,
commonMessages, commonMessages,
defineMessages, defineMessages,
injectNotificationManager,
NewModal, NewModal,
RadioButtons, RadioButtons,
StyledInput, StyledInput,
@@ -72,6 +73,7 @@ import { edit, list } from '@/helpers/instance'
import type { GameInstance } from '@/helpers/types' import type { GameInstance } from '@/helpers/types'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const { handleError } = injectNotificationManager()
const props = defineProps<{ const props = defineProps<{
instanceIds: string[] instanceIds: string[]
@@ -148,7 +150,7 @@ async function deleteGroup(group: string) {
for (const instance of allInstances.value) { for (const instance of allInstances.value) {
if (instance.groups.includes(group)) { if (instance.groups.includes(group)) {
const newGroups = instance.groups.filter((g) => g !== group) const newGroups = instance.groups.filter((g) => g !== group)
await edit(instance.id, { groups: newGroups }).catch(() => {}) await edit(instance.id, { groups: newGroups }).catch(handleError)
instance.groups = newGroups instance.groups = newGroups
} }
} }
@@ -167,7 +169,7 @@ async function confirm() {
const groups = selectedGroup.value ? [selectedGroup.value.trim().substring(0, 32)] : [] const groups = selectedGroup.value ? [selectedGroup.value.trim().substring(0, 32)] : []
for (const instanceId of props.instanceIds) { for (const instanceId of props.instanceIds) {
await edit(instanceId, { groups }).catch(() => {}) await edit(instanceId, { groups }).catch(handleError)
} }
emit('applied') emit('applied')
@@ -35,7 +35,7 @@ const progressWidth = computed(() => `${Math.min(100, (props.current / props.tot
<h2 :id="`onboarding-title-${step.id}`">{{ formatMessage(step.title) }}</h2> <h2 :id="`onboarding-title-${step.id}`">{{ formatMessage(step.title) }}</h2>
</div> </div>
<ButtonStyled circular type="transparent"> <ButtonStyled circular type="transparent">
<button :aria-label="formatMessage(onboardingMessages.skip)" @click.stop="$emit('skip')"> <button data-onboarding-skip :aria-label="formatMessage(onboardingMessages.skip)" @click.stop="$emit('skip')">
<XIcon /> <XIcon />
</button> </button>
</ButtonStyled> </ButtonStyled>
@@ -252,6 +252,42 @@ export const onboardingMessages = defineMessages({
id: 'app.onboarding.instance-tabs.description', id: 'app.onboarding.instance-tabs.description',
defaultMessage: 'Use these tabs for content, files, screenshots, worlds, and logs. Tidy chaos.', defaultMessage: 'Use these tabs for content, files, screenshots, worlds, and logs. Tidy chaos.',
}, },
instanceContentTabTitle: {
id: 'app.onboarding.instance-content-tab.title',
defaultMessage: 'Content',
},
instanceContentTabDescription: {
id: 'app.onboarding.instance-content-tab.description',
defaultMessage:
'Manage this instance’s mods, resource packs, and shaders here. Search, enable or disable entries, check for updates, and browse for more.',
},
instanceFilesTabTitle: {
id: 'app.onboarding.instance-files-tab.title',
defaultMessage: 'Files',
},
instanceFilesTabDescription: {
id: 'app.onboarding.instance-files-tab.description',
defaultMessage:
'Browse the instance folder and open configs or logs in the built-in editor without leaving the launcher.',
},
instanceWorldsTabTitle: {
id: 'app.onboarding.instance-worlds-tab.title',
defaultMessage: 'Worlds',
},
instanceWorldsTabDescription: {
id: 'app.onboarding.instance-worlds-tab.description',
defaultMessage:
'Manage saved worlds: back them up, rename, edit world settings, and open the world folder.',
},
instanceLogsTabTitle: {
id: 'app.onboarding.instance-logs-tab.title',
defaultMessage: 'Logs',
},
instanceLogsTabDescription: {
id: 'app.onboarding.instance-logs-tab.description',
defaultMessage:
'Read the instance’s live logs to trace crashes and errors without digging through files.',
},
labTitle: { labTitle: {
id: 'app.onboarding.lab.title', id: 'app.onboarding.lab.title',
defaultMessage: 'Useful tools, built in', defaultMessage: 'Useful tools, built in',
@@ -509,15 +545,29 @@ export const onboardingTours: Record<OnboardingMode, OnboardingStep[]> = {
onboardingMessages.instanceActionsTitle, onboardingMessages.instanceActionsTitle,
onboardingMessages.instanceActionsDescription, onboardingMessages.instanceActionsDescription,
), ),
step( inspect(
'instance-tabs', 'instance-content-tab',
'inspect', 'instance-tab-content',
copy( onboardingMessages.instanceContentTabTitle,
onboardingMessages.instanceTabsTitle, onboardingMessages.instanceContentTabDescription,
onboardingMessages.instanceTabsDescription, ),
onboardingMessages.finishArea, inspect(
), 'instance-files-tab',
{ targetId: 'instance-tabs' }, 'instance-tab-files',
onboardingMessages.instanceFilesTabTitle,
onboardingMessages.instanceFilesTabDescription,
),
inspect(
'instance-worlds-tab',
'instance-tab-worlds',
onboardingMessages.instanceWorldsTabTitle,
onboardingMessages.instanceWorldsTabDescription,
),
inspect(
'instance-logs-tab',
'instance-tab-logs',
onboardingMessages.instanceLogsTabTitle,
onboardingMessages.instanceLogsTabDescription,
), ),
], ],
} }
@@ -279,8 +279,11 @@ export function useOnboardingTour(
function handleDocumentClick(event: MouseEvent) { function handleDocumentClick(event: MouseEvent) {
if (!visible.value) return if (!visible.value) return
const clickedElement = event.target instanceof Element ? event.target : null const clickedElement = event.target instanceof Element ? event.target : null
if (clickedElement?.closest('[data-onboarding-overlay-ui]')) return
// 跳过/关闭按钮由其自身处理,不在全局点击里推进
if (clickedElement?.closest('[data-onboarding-skip]')) return
// inspect 步:点击任意位置(含导览气泡本身)都继续下一步
if (step.value.interaction === 'inspect') { if (step.value.interaction === 'inspect') {
event.preventDefault() event.preventDefault()
event.stopImmediatePropagation() event.stopImmediatePropagation()
@@ -288,6 +291,9 @@ export function useOnboardingTour(
return return
} }
// 非 inspect 步:点在导览 UI 自身时不处理
if (clickedElement?.closest('[data-onboarding-overlay-ui]')) return
if (!step.value.targetId || !['navigate', 'activate'].includes(step.value.interaction)) return if (!step.value.targetId || !['navigate', 'activate'].includes(step.value.interaction)) return
if (clickedElement && handleBranchClick(clickedElement)) return if (clickedElement && handleBranchClick(clickedElement)) return
if (!targetElement.value?.contains(event.target as Node)) return if (!targetElement.value?.contains(event.target as Node)) return
@@ -21,7 +21,6 @@ import {
import { import {
Avatar, Avatar,
Button, Button,
type ButtonMenuOption,
type ComboboxOption, type ComboboxOption,
commonMessages, commonMessages,
ConfirmModal, ConfirmModal,
@@ -1038,7 +1037,6 @@ function activateScreenshot(screenshot: InstanceScreenshot, event: MouseEvent |
(candidate) => getSelectionKey(candidate) === getSelectionKey(screenshot), (candidate) => getSelectionKey(candidate) === getSelectionKey(screenshot),
) )
if (index >= 0) { if (index >= 0) {
screenshotOptionsMenu.value?.close()
imageViewer.value?.show(index) imageViewer.value?.show(index)
} }
} }
@@ -1055,44 +1053,34 @@ function requestDelete(screenshot: InstanceScreenshot, fromPreview = false) {
function showScreenshotOptions(screenshot: InstanceScreenshot, event: MouseEvent) { function showScreenshotOptions(screenshot: InstanceScreenshot, event: MouseEvent) {
screenshotOptionsTarget.value = screenshot screenshotOptionsTarget.value = screenshot
const options: ButtonMenuOption[] = [ const options = [
...(event.type === 'contextmenu' ...(event.type === 'contextmenu' ? [{ name: 'edit' }, { name: 'copy' }] : []),
? [ { name: 'open' },
{ { name: 'go-to-instance' },
id: 'edit',
label: formatMessage(messages.edit),
icon: EditIcon,
action: () => editScreenshot(screenshot),
},
{
id: 'copy',
label: formatMessage(messages.copy),
icon: ClipboardCopyIcon,
action: () => void copyScreenshot(screenshot),
},
]
: []),
{
id: 'open',
label: formatMessage(messages.showInFolder),
icon: FolderOpenIcon,
action: () => void openScreenshot(screenshot),
},
{
id: 'go-to-instance',
label: formatMessage(messages.goToInstance),
action: () => void goToInstance(screenshot),
},
{ type: 'divider' }, { type: 'divider' },
{ { name: 'delete', color: 'danger' },
id: 'delete',
label: formatMessage(commonMessages.deleteLabel),
icon: TrashIcon,
tone: 'red',
action: () => requestDelete(screenshot),
},
] ]
screenshotOptionsMenu.value?.open(event, options) screenshotOptionsMenu.value?.showMenu(event, screenshot, options)
}
function handleScreenshotOptionClicked({ item, option }: { item: InstanceScreenshot; option: string }) {
switch (option) {
case 'edit':
editScreenshot(item)
break
case 'copy':
void copyScreenshot(item)
break
case 'open':
void openScreenshot(item)
break
case 'go-to-instance':
void goToInstance(item)
break
case 'delete':
requestDelete(item)
break
}
} }
function goToInstance(screenshot: InstanceScreenshot) { function goToInstance(screenshot: InstanceScreenshot) {
@@ -1128,7 +1116,6 @@ function editScreenshot(screenshot: InstanceScreenshot) {
(candidate) => getSelectionKey(candidate) === getSelectionKey(screenshot), (candidate) => getSelectionKey(candidate) === getSelectionKey(screenshot),
) )
if (index >= 0) { if (index >= 0) {
screenshotOptionsMenu.value?.close()
void imageViewer.value?.edit(index) void imageViewer.value?.edit(index)
} }
} }
@@ -1426,7 +1413,23 @@ onBeforeUnmount(() => {
:markdown="false" :markdown="false"
@proceed="deleteCustomGroup" @proceed="deleteCustomGroup"
/> />
<ContextMenu ref="screenshotOptionsMenu" :label="formatMessage(commonMessages.actionsLabel)"> <ContextMenu
ref="screenshotOptionsMenu"
:label="formatMessage(commonMessages.actionsLabel)"
@option-clicked="handleScreenshotOptionClicked"
>
<template #edit>
<EditIcon />
{{ formatMessage(messages.edit) }}
</template>
<template #copy>
<ClipboardCopyIcon />
{{ formatMessage(messages.copy) }}
</template>
<template #open>
<FolderOpenIcon />
{{ formatMessage(messages.showInFolder) }}
</template>
<template #go-to-instance> <template #go-to-instance>
<Avatar <Avatar
:src="getInstanceIconUrl(screenshotOptionsInstance?.icon_path)" :src="getInstanceIconUrl(screenshotOptionsInstance?.icon_path)"
@@ -1437,6 +1440,10 @@ onBeforeUnmount(() => {
/> />
{{ formatMessage(messages.goToInstance) }} {{ formatMessage(messages.goToInstance) }}
</template> </template>
<template #delete>
<TrashIcon />
{{ formatMessage(commonMessages.deleteLabel) }}
</template>
</ContextMenu> </ContextMenu>
<ImageViewerEditor <ImageViewerEditor
ref="imageViewer" ref="imageViewer"
@@ -6008,6 +6008,30 @@
"app.onboarding.instance-actions.title": { "app.onboarding.instance-actions.title": {
"message": "The main controls" "message": "The main controls"
}, },
"app.onboarding.instance-content-tab.title": {
"message": "Content"
},
"app.onboarding.instance-content-tab.description": {
"message": "Manage this instance’s mods, resource packs, and shaders here. Search, enable or disable entries, check for updates, and browse for more."
},
"app.onboarding.instance-files-tab.title": {
"message": "Files"
},
"app.onboarding.instance-files-tab.description": {
"message": "Browse the instance folder and open configs or logs in the built-in editor without leaving the launcher."
},
"app.onboarding.instance-worlds-tab.title": {
"message": "Worlds"
},
"app.onboarding.instance-worlds-tab.description": {
"message": "Manage saved worlds: back them up, rename, edit world settings, and open the world folder."
},
"app.onboarding.instance-logs-tab.title": {
"message": "Logs"
},
"app.onboarding.instance-logs-tab.description": {
"message": "Read the instance’s live logs to trace crashes and errors without digging through files."
},
"app.onboarding.instance-mode.description": { "app.onboarding.instance-mode.description": {
"message": "StarLight automatically installs the administrator-selected modpack and versions, then checks and completes updates before every launch. A StarLight login is required. Choose Local to select your own versions and modpacks for other servers or single-player." "message": "StarLight automatically installs the administrator-selected modpack and versions, then checks and completes updates before every launch. A StarLight login is required. Choose Local to select your own versions and modpacks for other servers or single-player."
}, },
@@ -9922,5 +9946,8 @@
}, },
"unknown-pack-warning-modal.warning.title": { "unknown-pack-warning-modal.warning.title": {
"message": "Unknown file warning" "message": "Unknown file warning"
},
"app.navigation.screenshots": {
"message": "Screenshots"
} }
} }
@@ -5995,6 +5995,30 @@
"app.onboarding.instance-actions.title": { "app.onboarding.instance-actions.title": {
"message": "主操作台" "message": "主操作台"
}, },
"app.onboarding.instance-content-tab.title": {
"message": "内容"
},
"app.onboarding.instance-content-tab.description": {
"message": "在这里管理实例的 Mod、资源包与光影。可搜索、启用或禁用条目、检查更新,也能继续浏览安装新内容。"
},
"app.onboarding.instance-files-tab.title": {
"message": "文件"
},
"app.onboarding.instance-files-tab.description": {
"message": "浏览实例目录,用内置编辑器直接打开配置文件或日志,无需离开启动器。"
},
"app.onboarding.instance-worlds-tab.title": {
"message": "世界"
},
"app.onboarding.instance-worlds-tab.description": {
"message": "管理存档世界:备份、重命名、编辑世界设置,或打开世界所在文件夹。"
},
"app.onboarding.instance-logs-tab.title": {
"message": "日志"
},
"app.onboarding.instance-logs-tab.description": {
"message": "查看实例的实时日志,排查崩溃与报错,不必再翻找文件。"
},
"app.onboarding.instance-tabs.description": { "app.onboarding.instance-tabs.description": {
"message": "内容、文件、截图、世界和日志都在这些标签里。乱中有序。" "message": "内容、文件、截图、世界和日志都在这些标签里。乱中有序。"
}, },
@@ -10680,5 +10704,8 @@
}, },
"app.starlight-skin.frame-title": { "app.starlight-skin.frame-title": {
"message": "StarLight 皮肤站" "message": "StarLight 皮肤站"
},
"app.navigation.screenshots": {
"message": "截图"
} }
} }
@@ -688,11 +688,13 @@ const tabs = computed(() => [
label: formatMessage(messages.contentTab), label: formatMessage(messages.contentTab),
href: `${basePath.value}`, href: `${basePath.value}`,
icon: BoxesIcon, icon: BoxesIcon,
onboardingId: 'instance-tab-content',
}, },
{ {
label: formatMessage(messages.filesTab), label: formatMessage(messages.filesTab),
href: `${basePath.value}/files`, href: `${basePath.value}/files`,
icon: FolderOpenIcon, icon: FolderOpenIcon,
onboardingId: 'instance-tab-files',
}, },
{ {
label: formatMessage(messages.screenshotsTab), label: formatMessage(messages.screenshotsTab),
@@ -703,11 +705,13 @@ const tabs = computed(() => [
label: formatMessage(messages.worldsTab), label: formatMessage(messages.worldsTab),
href: `${basePath.value}/worlds`, href: `${basePath.value}/worlds`,
icon: GlobeIcon, icon: GlobeIcon,
onboardingId: 'instance-tab-worlds',
}, },
{ {
label: formatMessage(messages.logsTab), label: formatMessage(messages.logsTab),
href: `${basePath.value}/logs`, href: `${basePath.value}/logs`,
icon: TerminalSquareIcon, icon: TerminalSquareIcon,
onboardingId: 'instance-tab-logs',
}, },
]) ])
+2
View File
@@ -3,6 +3,7 @@ import type { AbstractPopupNotificationManager, AbstractWebNotificationManager }
import { setupCreationModal } from './setup/creation-modal' import { setupCreationModal } from './setup/creation-modal'
import { setupFileDropProvider } from './setup/file-drop' import { setupFileDropProvider } from './setup/file-drop'
import { setupFilePickerProvider } from './setup/file-picker' import { setupFilePickerProvider } from './setup/file-picker'
import { setupImageViewerEditorProvider } from './setup/image-viewer-editor'
import { setupInstanceImportProvider } from './setup/instance-import' import { setupInstanceImportProvider } from './setup/instance-import'
import { setupTagsProvider } from './setup/tags' import { setupTagsProvider } from './setup/tags'
@@ -14,6 +15,7 @@ export function setupProviders(
setupTagsProvider(notificationManager, stateInitialization) setupTagsProvider(notificationManager, stateInitialization)
const fileDrop = setupFileDropProvider() const fileDrop = setupFileDropProvider()
const filePicker = setupFilePickerProvider() const filePicker = setupFilePickerProvider()
setupImageViewerEditorProvider()
setupInstanceImportProvider(notificationManager) setupInstanceImportProvider(notificationManager)
return { return {
@@ -0,0 +1,16 @@
import {
type ImageViewerEditorData,
type ImageViewerEditorSource,
provideImageViewerEditor,
} from '@modrinth/ui'
import { readFile } from '@tauri-apps/plugin-fs'
export function setupImageViewerEditorProvider() {
provideImageViewerEditor({
async loadEditorData(source: ImageViewerEditorSource): Promise<ImageViewerEditorData> {
return {
source: new Blob([await readFile(source.path)], { type: 'image/png' }),
}
},
})
}
+4
View File
@@ -119,6 +119,10 @@ export default new createRouter({
pageTransitionGroup: 'multiplayer', pageTransitionGroup: 'multiplayer',
}, },
children: [ children: [
{
path: '',
redirect: { name: 'MultiplayerRooms' },
},
{ {
path: 'rooms', path: 'rooms',
name: 'MultiplayerRooms', name: 'MultiplayerRooms',
+17
View File
@@ -365,6 +365,7 @@ fn main() {
"install_existing_instance", "install_existing_instance",
"hosted_default", "hosted_default",
"hosted_set_session", "hosted_set_session",
"hosted_has_game_account",
"hosted_create", "hosted_create",
"hosted_binding", "hosted_binding",
"hosted_sync", "hosted_sync",
@@ -508,6 +509,20 @@ fn main() {
"instance_edit_icon", "instance_edit_icon",
"instance_export_mrpack", "instance_export_mrpack",
"instance_get_pack_export_candidates", "instance_get_pack_export_candidates",
"instance_list_screenshots",
"instance_list_all_screenshots",
"instance_list_synced_screenshots",
"instance_save_edited_screenshot",
"instance_list_screenshot_groups",
"instance_create_screenshot_group",
"instance_rename_screenshot_group",
"instance_delete_screenshot_group",
"instance_set_screenshot_group_memberships",
"instance_import_screenshot_groups",
"instance_delete_screenshots",
"instance_export_screenshots",
"instance_move_screenshots",
"instance_open_screenshot",
]) ])
.default_permission( .default_permission(
DefaultPermissionRule::AllowAllCommands, DefaultPermissionRule::AllowAllCommands,
@@ -524,6 +539,7 @@ fn main() {
"proxy_get", "proxy_get",
"proxy_set", "proxy_set",
"proxy_test", "proxy_test",
"set_ui_scale",
]) ])
.default_permission( .default_permission(
DefaultPermissionRule::AllowAllCommands, DefaultPermissionRule::AllowAllCommands,
@@ -669,6 +685,7 @@ fn main() {
"file_save_as", "file_save_as",
"file_read_dragged_file", "file_read_dragged_file",
"screenshot_thumbnail", "screenshot_thumbnail",
"instance_icon_thumbnail",
"studio_read_text", "studio_read_text",
"studio_read_binary", "studio_read_binary",
"studio_write_binary", "studio_write_binary",
+9
View File
@@ -650,6 +650,15 @@ Function PageLeaveOptions
Abort Abort
${EndIf} ${EndIf}
; 若安装位置被选在盘符根目录(如 E:\),自动在其下创建 Starlight 子目录,
; 避免启动器文件直接散落在根目录。用户选的具体子目录不受影响。
${GetRoot} "$INSTDIR" $0
StrCpy $1 "$0" -1
${If} "$INSTDIR" == "$1"
StrCpy $INSTDIR "$INSTDIR\Starlight"
${NSD_SetText} $InstallDirInput $INSTDIR
${EndIf}
${NSD_GetState} $DesktopShortcutCheckbox $DesktopShortcutState ${NSD_GetState} $DesktopShortcutCheckbox $DesktopShortcutState
${If} $FreshInstall <> 1 ${If} $FreshInstall <> 1
+45 -21
View File
@@ -478,27 +478,51 @@ fn edit_to_core(edit_instance: EditInstance) -> Result<CoreEditInstance> {
None => Ok(CoreInstanceLink::Unmanaged), None => Ok(CoreInstanceLink::Unmanaged),
}) })
.transpose()?, .transpose()?,
launch_overrides: Some(InstanceLaunchOverridesPatch { launch_overrides: {
player: None, let has_launch_change = edit_instance.java_path.is_some()
instance_mode: None, || edit_instance.extra_launch_args.is_some()
java_path: edit_instance.java_path, || edit_instance.custom_env_vars.is_some()
extra_launch_args: edit_instance.extra_launch_args, || edit_instance.memory.is_some()
custom_env_vars: edit_instance.custom_env_vars, || edit_instance.force_fullscreen.is_some()
memory: edit_instance.memory, || edit_instance.maximize_window.is_some()
force_fullscreen: edit_instance.force_fullscreen, || edit_instance.game_resolution.is_some()
maximize_window: edit_instance.maximize_window, || edit_instance.launch_preparation_timeout.is_some()
game_resolution: edit_instance.game_resolution, || edit_instance.hooks.is_some();
launch_preparation_timeout: edit_instance if has_launch_change {
.launch_preparation_timeout, Some(InstanceLaunchOverridesPatch {
hooks: edit_instance.hooks, player: None,
}), instance_mode: None,
content_set_patch: Some(AppliedContentSetPatch { java_path: edit_instance.java_path,
source_kind: None, extra_launch_args: edit_instance.extra_launch_args,
game_version: edit_instance.game_version, custom_env_vars: edit_instance.custom_env_vars,
protocol_version: Some(None), memory: edit_instance.memory,
loader: edit_instance.loader, force_fullscreen: edit_instance.force_fullscreen,
loader_version: edit_instance.loader_version, maximize_window: edit_instance.maximize_window,
}), game_resolution: edit_instance.game_resolution,
launch_preparation_timeout: edit_instance
.launch_preparation_timeout,
hooks: edit_instance.hooks,
})
} else {
None
}
},
content_set_patch: {
let has_content_change = edit_instance.game_version.is_some()
|| edit_instance.loader.is_some()
|| edit_instance.loader_version.is_some();
if has_content_change {
Some(AppliedContentSetPatch {
source_kind: None,
game_version: edit_instance.game_version,
protocol_version: Some(None),
loader: edit_instance.loader,
loader_version: edit_instance.loader_version,
})
} else {
None
}
},
last_played: None, last_played: None,
submitted_time_played: None, submitted_time_played: None,
recent_time_played: None, recent_time_played: None,
+41 -2
View File
@@ -181,6 +181,7 @@ pub struct Settings {
pub migrated: bool, pub migrated: bool,
pub developer_mode: bool, pub developer_mode: bool,
#[serde(deserialize_with = "deserialize_feature_flags")]
pub feature_flags: HashMap<FeatureFlag, bool>, pub feature_flags: HashMap<FeatureFlag, bool>,
pub skipped_update: Option<String>, pub skipped_update: Option<String>,
@@ -212,6 +213,7 @@ pub enum FeatureFlag {
ServersInApp, ServersInApp,
ServerProjectQa, ServerProjectQa,
I18nDebug, I18nDebug,
MultiplayerInApp,
ShowInstancePlayTime, ShowInstancePlayTime,
SkipNonEssentialWarnings, SkipNonEssentialWarnings,
AdvancedFiltersCollapsed, AdvancedFiltersCollapsed,
@@ -221,6 +223,43 @@ pub enum FeatureFlag {
AutoInstallDependencies, AutoInstallDependencies,
} }
/// 反序列化 feature flags,遇到未知的 flag 名称时直接忽略,而不是报错。
///
/// 这样即使前端(或更新的版本)写入了当前后端不认识的 flag,
/// 旧版本也能正常读取设置,而不是整包失败导致启动器初始化崩溃。
fn deserialize_feature_flags<'de, D>(
deserializer: D,
) -> Result<HashMap<FeatureFlag, bool>, D::Error>
where
D: serde::Deserializer<'de>,
{
let raw = HashMap::<String, bool>::deserialize(deserializer)?;
Ok(filter_known_feature_flags(raw))
}
/// 从 JSON 字符串解析 feature flags,忽略未知名称。
fn parse_feature_flags_json(value: &str) -> HashMap<FeatureFlag, bool> {
match serde_json::from_str::<HashMap<String, bool>>(value) {
Ok(raw) => filter_known_feature_flags(raw),
Err(_) => HashMap::new(),
}
}
/// 只保留能解析为 [`FeatureFlag`] 的条目,未知名称静默丢弃。
fn filter_known_feature_flags(
raw: HashMap<String, bool>,
) -> HashMap<FeatureFlag, bool> {
let mut flags = HashMap::with_capacity(raw.len());
for (key, value) in raw {
if let Ok(flag) = serde_json::from_value::<FeatureFlag>(
serde_json::Value::String(key),
) {
flags.insert(flag, value);
}
}
flags
}
impl Settings { impl Settings {
const CURRENT_VERSION: usize = 3; const CURRENT_VERSION: usize = 3;
@@ -383,8 +422,8 @@ impl Settings {
migrated: res.migrated == 1, migrated: res.migrated == 1,
feature_flags: res feature_flags: res
.feature_flags .feature_flags
.as_ref() .as_deref()
.and_then(|x| serde_json::from_str(x).ok()) .map(parse_feature_flags_json)
.unwrap_or_default(), .unwrap_or_default(),
skipped_update: res.skipped_update, skipped_update: res.skipped_update,
pending_update_toast_for_version: res pending_update_toast_for_version: res