feat:移除了弹窗,服务器添加sls

This commit is contained in:
2026-09-08 22:39:45 +08:00
commit 6a295f9a7a
4082 changed files with 1322534 additions and 0 deletions

View File

@ -0,0 +1,82 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import type { StorageNode } from './storageData'
import { sortStorageChildren } from './storageData'
import StorageTreeRow from './StorageTreeRow.vue'
defineOptions({ name: 'StorageTreeNode' })
const props = defineProps<{
node: StorageNode
depth: number
parentTotal: number
}>()
const emit = defineEmits<{
action: [node: StorageNode]
}>()
const hasChildren = computed(() => (props.node.children?.length ?? 0) > 0)
const expanded = ref(false)
const totalSize = computed(() => props.node.size.actual + props.node.size.symlink)
const visibleChildren = computed(() => sortStorageChildren(props.node.children))
function onToggle(event: Event) {
expanded.value = (event.target as HTMLDetailsElement).open
}
</script>
<template>
<!-- 有子节点时使用原生 <details>/<summary> 管理展开收起 -->
<details v-if="hasChildren" class="flex flex-col" @toggle="onToggle">
<summary class="tree-row-reveal">
<StorageTreeRow
:node="node"
:depth="depth"
:parent-total="parentTotal"
:expanded="expanded"
@action="emit('action', $event)"
/>
</summary>
<div class="tree-children">
<StorageTreeNode
v-for="child in visibleChildren"
:key="child.id"
:node="child"
:depth="depth + 1"
:parent-total="totalSize"
@action="emit('action', $event)"
/>
</div>
</details>
<div v-else class="flex flex-col">
<!-- 叶子节点不需要展开直接渲染行 -->
<StorageTreeRow
:node="node"
:depth="depth"
:parent-total="parentTotal"
:expanded="false"
@action="emit('action', $event)"
/>
</div>
</template>
<style scoped>
/* 原生的 <summary> 需要去掉默认的展开三角形与缩进 */
.tree-row-reveal {
display: block;
list-style: none;
user-select: none;
cursor: pointer;
}
.tree-row-reveal::-webkit-details-marker {
display: none;
}
.tree-row-reveal::marker {
content: none;
}
</style>

View File

@ -0,0 +1,304 @@
<script setup lang="ts">
import { ChevronRightIcon, FileIcon, FolderIcon, FolderOpenIcon } from '@modrinth/assets'
import { useFormatBytes, useVIntl } from '@modrinth/ui'
import { computed } from 'vue'
import type { StorageNode, StorageNodeType } from './storageData'
import { storageMessages } from './storageMessages'
type MessageDescriptor = (typeof storageMessages)['total']
defineOptions({ name: 'StorageTreeRow' })
const props = defineProps<{
node: StorageNode
depth: number
parentTotal: number
expanded: boolean
}>()
const emit = defineEmits<{
action: [node: StorageNode]
}>()
const { formatMessage } = useVIntl()
const formatBytes = useFormatBytes()
const typeLabels: Record<StorageNodeType, MessageDescriptor> = {
instances: storageMessages.instanceData,
cache: storageMessages.cacheData,
meta: storageMessages.metaData,
database: storageMessages.database,
other: storageMessages.other,
instance: storageMessages.instance,
mods: storageMessages.mods,
replay: storageMessages.replay,
resourcepacks: storageMessages.resourcepacks,
saves: storageMessages.saves,
world: storageMessages.world,
schematics: storageMessages.schematics,
screenshots: storageMessages.screenshots,
shaderpacks: storageMessages.shaderpacks,
minimap: storageMessages.minimap,
'distant-horizons': storageMessages.distantHorizons,
'db-file': storageMessages.dbFile,
'db-backup': storageMessages.dbBackup,
}
const hasChildren = computed(() => (props.node.children?.length ?? 0) > 0)
const isDirectory = computed(() => (props.node.paths[0]?.kind ?? 'directory') !== 'file')
const actualShare = computed(() =>
props.parentTotal > 0 ? props.node.size.actual / props.parentTotal : 0,
)
const symShare = computed(() =>
props.parentTotal > 0 ? props.node.size.symlink / props.parentTotal : 0,
)
const totalShare = computed(() => Math.min(1, actualShare.value + symShare.value))
const percent = computed(() => Math.round(totalShare.value * 100))
const displayLabel = computed(() => props.node.name ?? formatMessage(typeLabels[props.node.type]))
const tooltipText = computed(() => props.node.paths.map((path) => path.path).join('\n'))
const nameTooltip = computed(() => ({
content: tooltipText.value,
popperClass: 'storage-tooltip',
}))
const actualSizeTooltip = computed(() =>
formatMessage(storageMessages.actualSizeTooltip, {
size: formatBytes(props.node.size.actual),
}),
)
const symlinkSizeTooltip = computed(() =>
formatMessage(storageMessages.symlinkSizeTooltip, {
size: formatBytes(props.node.size.symlink),
}),
)
const progressTitle = computed(() =>
props.node.size.symlink > 0
? `${actualSizeTooltip.value}\n${symlinkSizeTooltip.value}`
: actualSizeTooltip.value,
)
const progressTooltip = computed(() => ({
content: progressTitle.value,
popperClass: 'storage-tooltip',
}))
const progressLabel = computed(() =>
props.node.size.symlink > 0
? `${actualSizeTooltip.value} ${symlinkSizeTooltip.value}`
: actualSizeTooltip.value,
)
const actualSizeText = computed(() => formatBytes(props.node.size.actual))
const symlinkSizeText = computed(() => formatBytes(props.node.size.symlink))
const openActionLabel = computed(() => formatMessage(storageMessages.openAction))
</script>
<template>
<div class="tree-row hover:bg-surface-2" :class="{ clickable: hasChildren, 'is-expanded': expanded }">
<!-- 左侧树层级与名称部分 -->
<div class="flex h-full min-w-0 flex-1 items-center">
<!-- 根据 depth 生成层级缩进和导轨线 -->
<div class="indent-guides" aria-hidden="true">
<span v-for="i in depth" :key="i" class="guide-line" />
</div>
<!-- 展开/折叠 箭头装饰性由原生的 <summary> 负责展开 -->
<span
v-if="hasChildren"
class="chevron-icon inline-flex h-5 w-5 shrink-0 items-center justify-center p-0 text-secondary"
aria-hidden="true"
>
<ChevronRightIcon class="size-3.5" />
</span>
<span v-else class="chevron-placeholder" aria-hidden="true" />
<!-- 文件/文件夹按钮打开位置不展开树 -->
<button
v-tooltip="openActionLabel"
type="button"
class="node-type-btn mr-1.5 inline-flex cursor-pointer items-center justify-center rounded border-0 bg-transparent p-0 text-secondary hover:bg-surface-3 hover:text-contrast"
:aria-label="`${displayLabel}: ${openActionLabel}`"
@click.stop="emit('action', node)"
>
<FolderOpenIcon v-if="hasChildren && expanded" class="node-type-icon text-brand" />
<FolderIcon v-else-if="isDirectory" class="node-type-icon" />
<FileIcon v-else class="node-type-icon" />
</button>
<!-- 节点名称 -->
<span v-tooltip="nameTooltip" class="node-name">
{{ displayLabel }}
</span>
<span v-if="node.count !== undefined" class="count-badge">
{{ node.count }}
</span>
</div>
<!-- 右侧数据与进度列 -->
<div class="ml-4 flex shrink-0 items-center gap-4">
<div class="storage-size">
{{ actualSizeText }}
<span v-if="node.size.symlink > 0" class="text-secondary"> + {{ symlinkSizeText }} </span>
</div>
<div class="w-9 max-sm:hidden text-right text-xs tabular-nums text-secondary">{{ percent }}%</div>
<progress
v-tooltip="progressTooltip"
class="storage-progress h-1 w-24 shrink-0 appearance-none overflow-hidden rounded-full border-0 bg-surface-3"
:value="totalShare"
:max="1"
:aria-label="progressLabel"
/>
</div>
</div>
</template>
<style scoped>
/* 整体行布局:去卡片化、去分割线 */
.tree-row {
display: flex;
align-items: center;
justify-content: space-between;
height: 2rem;
padding: 0 0.5rem;
border: none;
background: transparent;
user-select: none;
transition: background-color 0.1s ease;
}
.tree-row.clickable {
cursor: pointer;
}
/* 竖向缩进线容器 */
.indent-guides {
display: flex;
height: 100%;
flex-shrink: 0;
}
/* 垂直导轨线:跟随主题 surface 描边色,浅色/深色模式都清晰可见 */
.guide-line {
display: block;
width: 1.25rem;
height: 100%;
position: relative;
}
.guide-line::before {
content: '';
position: absolute;
left: 0.5rem;
top: 0;
bottom: 0;
width: 1px;
background-color: var(--surface-5);
opacity: 1;
}
/* 展开状态下高亮当前父级的引导线,使用主题品牌色 */
.tree-row.is-expanded .indent-guides .guide-line:last-child::before {
background-color: var(--color-brand);
opacity: 1;
}
/* 折叠/展开 箭头图标 */
.chevron-icon {
transition: transform 0.15s ease;
}
.tree-row.is-expanded .chevron-icon {
transform: rotate(90deg);
}
.chevron-placeholder {
width: 1.25rem;
flex-shrink: 0;
}
/* 文件/文件夹打开按钮 */
.node-type-icon {
width: 1.125rem;
height: 1.125rem;
flex-shrink: 0;
}
.node-type-btn:focus-visible {
outline: 2px solid var(--color-brand);
outline-offset: -1px;
}
.node-name {
min-width: 0;
overflow: hidden;
font-size: 0.8125rem;
font-weight: 400;
color: var(--color-contrast);
text-overflow: ellipsis;
white-space: nowrap;
}
.count-badge {
margin-left: 0.375rem;
padding: 0 0.35rem;
height: 1rem;
border-radius: 0.25rem;
background: var(--surface-3);
color: var(--color-secondary);
font-size: 0.6875rem;
line-height: 1rem;
font-variant-numeric: tabular-nums;
flex-shrink: 0;
}
.storage-size {
font-size: 0.8125rem;
font-variant-numeric: tabular-nums;
color: var(--color-primary);
white-space: nowrap;
text-align: right;
min-width: 5rem;
}
/* 原生 <progress> 作为共享占用进度条 */
.storage-progress::-webkit-progress-bar {
background: var(--surface-3);
border-radius: 9999px;
}
.storage-progress::-webkit-progress-value {
background: var(--color-brand);
border-radius: 9999px;
}
.storage-progress::-moz-progress-bar {
background: var(--color-brand);
border-radius: 9999px;
}
@media (max-width: 900px) {
.storage-progress {
display: none;
}
}
/* 存储页多行 tooltip内容换行并限制宽度 */
:global(.v-popper__popper.storage-tooltip .v-popper__inner) {
white-space: pre-line;
max-width: 22rem;
}
</style>

View File

@ -0,0 +1,522 @@
export type StorageNodeType =
| 'instances'
| 'cache'
| 'meta'
| 'database'
| 'other'
| 'instance'
| 'mods'
| 'replay'
| 'resourcepacks'
| 'saves'
| 'world'
| 'schematics'
| 'screenshots'
| 'shaderpacks'
| 'minimap'
| 'distant-horizons'
| 'db-file'
| 'db-backup'
export interface StoragePath {
path: string
kind: 'file' | 'directory'
}
export interface StorageSize {
actual: number
symlink: number
}
export interface StorageNode {
id: string
type: StorageNodeType
name?: string
instance_id?: string
size: StorageSize
count?: number
paths: StoragePath[]
children?: StorageNode[]
}
export interface StorageTree {
version?: number
scannedAt?: string
total: StorageSize
categories: StorageNode[]
rootOther: StorageNode | null
}
export function sortStorageChildren(children: StorageNode[] | undefined): StorageNode[] {
if (!children) return []
return [...children]
.filter((child) => child.size.actual + child.size.symlink > 0)
.sort((a, b) => {
const aIsOther = a.type === 'other' ? 1 : 0
const bIsOther = b.type === 'other' ? 1 : 0
if (aIsOther !== bIsOther) return aIsOther - bIsOther
const aTotal = a.size.actual + a.size.symlink
const bTotal = b.size.actual + b.size.symlink
return bTotal - aTotal
})
}
const gb = (value: number) => Math.round(value * 1024 ** 3)
const mb = (value: number) => Math.round(value * 1024 ** 2)
const appData = 'C:/Users/You/AppData/Roaming/red.ghs.axolotl'
const instanceAPath = `${appData}/profiles/红石生电优化【Redstone Survival Optimization】`
const instanceBPath = `${appData}/profiles/Fabric 1.21.11`
const instanceCPath = `${appData}/profiles/Vanilla 26.2`
const instanceDPath = `${appData}/profiles/CurseForge Pack`
const worldNode = (
id: string,
name: string,
actual: number,
symlink = 0,
parentPath: string,
): StorageNode => ({
id,
type: 'world',
name,
size: { actual, symlink },
paths: [{ path: `${parentPath}/saves/${name}`, kind: 'directory' }],
})
const instanceANode: StorageNode = {
id: 'instance-a',
type: 'instance',
name: '红石生电优化【Redstone Survival Optimization】',
size: { actual: gb(20), symlink: gb(1.5) },
paths: [{ path: instanceAPath, kind: 'directory' }],
children: [
{
id: 'instance-a-mods',
type: 'mods',
size: { actual: gb(1.6), symlink: gb(0.2) },
count: 42,
paths: [{ path: `${instanceAPath}/mods`, kind: 'directory' }],
},
{
id: 'instance-a-replay',
type: 'replay',
size: { actual: gb(5.2), symlink: 0 },
paths: [
{ path: `${instanceAPath}/flashback`, kind: 'directory' },
{ path: `${instanceAPath}/replay_recordings`, kind: 'directory' },
],
},
{
id: 'instance-a-resourcepacks',
type: 'resourcepacks',
size: { actual: gb(0.8), symlink: 0 },
count: 4,
paths: [{ path: `${instanceAPath}/resourcepacks`, kind: 'directory' }],
},
{
id: 'instance-a-saves',
type: 'saves',
size: { actual: gb(9.6), symlink: 0 },
count: 2,
paths: [{ path: `${instanceAPath}/saves`, kind: 'directory' }],
children: [
worldNode('instance-a-world1', 'world1', gb(8.4), 0, instanceAPath),
worldNode('instance-a-world2', 'world2', gb(1.2), 0, instanceAPath),
],
},
{
id: 'instance-a-schematics',
type: 'schematics',
size: { actual: gb(0.15), symlink: 0 },
count: 86,
paths: [{ path: `${instanceAPath}/schematics`, kind: 'directory' }],
},
{
id: 'instance-a-screenshots',
type: 'screenshots',
size: { actual: gb(0.6), symlink: 0 },
count: 214,
paths: [{ path: `${instanceAPath}/screenshots`, kind: 'directory' }],
},
{
id: 'instance-a-shaderpacks',
type: 'shaderpacks',
size: { actual: gb(0.9), symlink: gb(0.1) },
count: 3,
paths: [{ path: `${instanceAPath}/shaderpacks`, kind: 'directory' }],
},
{
id: 'instance-a-minimap',
type: 'minimap',
size: { actual: gb(0.05), symlink: gb(0.8) },
paths: [
{ path: `${instanceAPath}/voxelmap`, kind: 'directory' },
{ path: `${instanceAPath}/xaero`, kind: 'directory' },
{ path: `${instanceAPath}/XaeroWaypoints_BACKUP`, kind: 'directory' },
],
},
{
id: 'instance-a-distant-horizons',
type: 'distant-horizons',
size: { actual: gb(0.3), symlink: gb(0.4) },
paths: [
{ path: `${instanceAPath}/.voxy`, kind: 'directory' },
{ path: `${instanceAPath}/Distant_Horizons_server_data`, kind: 'directory' },
],
},
{
id: 'instance-a-other',
type: 'other',
size: { actual: gb(0.8), symlink: 0 },
paths: [{ path: instanceAPath, kind: 'directory' }],
},
],
}
const instanceBNode: StorageNode = {
id: 'instance-b',
type: 'instance',
name: 'Fabric 1.21.11',
size: { actual: gb(9.8), symlink: 0 },
paths: [{ path: instanceBPath, kind: 'directory' }],
children: [
{
id: 'instance-b-mods',
type: 'mods',
size: { actual: gb(2.4), symlink: 0 },
count: 57,
paths: [{ path: `${instanceBPath}/mods`, kind: 'directory' }],
},
{
id: 'instance-b-replay',
type: 'replay',
size: { actual: gb(0.1), symlink: 0 },
paths: [
{ path: `${instanceBPath}/flashback`, kind: 'directory' },
{ path: `${instanceBPath}/replay_recordings`, kind: 'directory' },
],
},
{
id: 'instance-b-resourcepacks',
type: 'resourcepacks',
size: { actual: gb(0.2), symlink: 0 },
count: 3,
paths: [{ path: `${instanceBPath}/resourcepacks`, kind: 'directory' }],
},
{
id: 'instance-b-saves',
type: 'saves',
size: { actual: gb(5.6), symlink: 0 },
count: 2,
paths: [{ path: `${instanceBPath}/saves`, kind: 'directory' }],
children: [
worldNode('instance-b-world1', 'world1', gb(3.2), 0, instanceBPath),
worldNode('instance-b-world2', 'world2', gb(2.4), 0, instanceBPath),
],
},
{
id: 'instance-b-schematics',
type: 'schematics',
size: { actual: gb(0.05), symlink: 0 },
count: 12,
paths: [{ path: `${instanceBPath}/schematics`, kind: 'directory' }],
},
{
id: 'instance-b-screenshots',
type: 'screenshots',
size: { actual: gb(0.3), symlink: 0 },
count: 76,
paths: [{ path: `${instanceBPath}/screenshots`, kind: 'directory' }],
},
{
id: 'instance-b-shaderpacks',
type: 'shaderpacks',
size: { actual: gb(0.4), symlink: 0 },
count: 2,
paths: [{ path: `${instanceBPath}/shaderpacks`, kind: 'directory' }],
},
{
id: 'instance-b-minimap',
type: 'minimap',
size: { actual: gb(0.02), symlink: 0 },
paths: [
{ path: `${instanceBPath}/voxelmap`, kind: 'directory' },
{ path: `${instanceBPath}/xaero`, kind: 'directory' },
{ path: `${instanceBPath}/XaeroWaypoints_BACKUP`, kind: 'directory' },
],
},
{
id: 'instance-b-distant-horizons',
type: 'distant-horizons',
size: { actual: gb(0.1), symlink: 0 },
paths: [
{ path: `${instanceBPath}/.voxy`, kind: 'directory' },
{ path: `${instanceBPath}/Distant_Horizons_server_data`, kind: 'directory' },
],
},
{
id: 'instance-b-other',
type: 'other',
size: { actual: gb(0.63), symlink: 0 },
paths: [{ path: instanceBPath, kind: 'directory' }],
},
],
}
const instanceCNode: StorageNode = {
id: 'instance-c',
type: 'instance',
name: 'Vanilla 26.2',
size: { actual: gb(0.5), symlink: gb(12) },
paths: [
{ path: `${appData}/profiles/Vanilla 26.2`, kind: 'directory' },
{ path: `${appData}/.minecraft/versions/Vanilla 26.2`, kind: 'directory' },
],
children: [
{
id: 'instance-c-mods',
type: 'mods',
size: { actual: gb(0.05), symlink: gb(0.5) },
count: 1,
paths: [{ path: `${instanceCPath}/mods`, kind: 'directory' }],
},
{
id: 'instance-c-replay',
type: 'replay',
size: { actual: 0, symlink: 0 },
paths: [
{ path: `${instanceCPath}/flashback`, kind: 'directory' },
{ path: `${instanceCPath}/replay_recordings`, kind: 'directory' },
],
},
{
id: 'instance-c-resourcepacks',
type: 'resourcepacks',
size: { actual: gb(0.02), symlink: gb(0.3) },
count: 1,
paths: [{ path: `${instanceCPath}/resourcepacks`, kind: 'directory' }],
},
{
id: 'instance-c-saves',
type: 'saves',
size: { actual: gb(0.4), symlink: gb(9) },
count: 1,
paths: [{ path: `${instanceCPath}/saves`, kind: 'directory' }],
children: [worldNode('instance-c-world1', 'world1', gb(0.4), gb(9), instanceCPath)],
},
{
id: 'instance-c-schematics',
type: 'schematics',
size: { actual: 0, symlink: 0 },
count: 0,
paths: [{ path: `${instanceCPath}/schematics`, kind: 'directory' }],
},
{
id: 'instance-c-screenshots',
type: 'screenshots',
size: { actual: 0, symlink: 0 },
count: 0,
paths: [{ path: `${instanceCPath}/screenshots`, kind: 'directory' }],
},
{
id: 'instance-c-shaderpacks',
type: 'shaderpacks',
size: { actual: gb(0.01), symlink: gb(2) },
count: 1,
paths: [{ path: `${instanceCPath}/shaderpacks`, kind: 'directory' }],
},
{
id: 'instance-c-minimap',
type: 'minimap',
size: { actual: gb(0.01), symlink: gb(0.1) },
paths: [
{ path: `${instanceCPath}/voxelmap`, kind: 'directory' },
{ path: `${instanceCPath}/xaero`, kind: 'directory' },
{ path: `${instanceCPath}/XaeroWaypoints_BACKUP`, kind: 'directory' },
],
},
{
id: 'instance-c-distant-horizons',
type: 'distant-horizons',
size: { actual: gb(0.01), symlink: gb(0.1) },
paths: [
{ path: `${instanceCPath}/.voxy`, kind: 'directory' },
{ path: `${instanceCPath}/Distant_Horizons_server_data`, kind: 'directory' },
],
},
{
id: 'instance-c-other',
type: 'other',
size: { actual: 0, symlink: 0 },
paths: [{ path: instanceCPath, kind: 'directory' }],
},
],
}
const instanceDNode: StorageNode = {
id: 'instance-d',
type: 'instance',
name: 'CurseForge Pack',
size: { actual: gb(4), symlink: gb(0.2) },
paths: [{ path: instanceDPath, kind: 'directory' }],
children: [
{
id: 'instance-d-mods',
type: 'mods',
size: { actual: gb(2), symlink: gb(0.1) },
count: 35,
paths: [{ path: `${instanceDPath}/mods`, kind: 'directory' }],
},
{
id: 'instance-d-replay',
type: 'replay',
size: { actual: gb(0.05), symlink: 0 },
paths: [
{ path: `${instanceDPath}/flashback`, kind: 'directory' },
{ path: `${instanceDPath}/replay_recordings`, kind: 'directory' },
],
},
{
id: 'instance-d-resourcepacks',
type: 'resourcepacks',
size: { actual: gb(0.3), symlink: 0 },
count: 5,
paths: [{ path: `${instanceDPath}/resourcepacks`, kind: 'directory' }],
},
{
id: 'instance-d-saves',
type: 'saves',
size: { actual: gb(1), symlink: 0 },
count: 2,
paths: [{ path: `${instanceDPath}/saves`, kind: 'directory' }],
children: [
worldNode('instance-d-world1', 'world1', gb(0.6), 0, instanceDPath),
worldNode('instance-d-world2', 'world2', gb(0.4), 0, instanceDPath),
],
},
{
id: 'instance-d-schematics',
type: 'schematics',
size: { actual: gb(0.1), symlink: 0 },
count: 24,
paths: [{ path: `${instanceDPath}/schematics`, kind: 'directory' }],
},
{
id: 'instance-d-screenshots',
type: 'screenshots',
size: { actual: gb(0.2), symlink: 0 },
count: 88,
paths: [{ path: `${instanceDPath}/screenshots`, kind: 'directory' }],
},
{
id: 'instance-d-shaderpacks',
type: 'shaderpacks',
size: { actual: gb(0.2), symlink: 0 },
count: 4,
paths: [{ path: `${instanceDPath}/shaderpacks`, kind: 'directory' }],
},
{
id: 'instance-d-minimap',
type: 'minimap',
size: { actual: gb(0.03), symlink: 0 },
paths: [
{ path: `${instanceDPath}/voxelmap`, kind: 'directory' },
{ path: `${instanceDPath}/xaero`, kind: 'directory' },
{ path: `${instanceDPath}/XaeroWaypoints_BACKUP`, kind: 'directory' },
],
},
{
id: 'instance-d-distant-horizons',
type: 'distant-horizons',
size: { actual: gb(0.02), symlink: 0 },
paths: [
{ path: `${instanceDPath}/.voxy`, kind: 'directory' },
{ path: `${instanceDPath}/Distant_Horizons_server_data`, kind: 'directory' },
],
},
{
id: 'instance-d-other',
type: 'other',
size: { actual: gb(0.1), symlink: gb(0.1) },
paths: [{ path: instanceDPath, kind: 'directory' }],
},
],
}
const instancesCategory: StorageNode = {
id: 'category-instances',
type: 'instances',
size: { actual: gb(34.7), symlink: gb(13.7) },
count: 4,
paths: [{ path: `${appData}/profiles`, kind: 'directory' }],
children: [
{
id: 'profiles-root-other',
type: 'other',
size: { actual: gb(0.4), symlink: 0 },
paths: [{ path: `${appData}/profiles`, kind: 'directory' }],
},
instanceANode,
instanceBNode,
instanceCNode,
instanceDNode,
],
}
const cacheCategory: StorageNode = {
id: 'category-cache',
type: 'cache',
size: { actual: gb(2.1), symlink: 0 },
count: 128,
paths: [{ path: `${appData}/caches`, kind: 'directory' }],
}
const metaCategory: StorageNode = {
id: 'category-meta',
type: 'meta',
size: { actual: gb(6.3), symlink: 0 },
count: 3421,
paths: [{ path: `${appData}/meta`, kind: 'directory' }],
}
const databaseCategory: StorageNode = {
id: 'category-database',
type: 'database',
size: { actual: gb(0.5), symlink: 0 },
count: 2,
paths: [{ path: `${appData}`, kind: 'directory' }],
children: [
{
id: 'database-app-db',
type: 'db-file',
size: { actual: mb(20), symlink: 0 },
paths: [{ path: `${appData}/app.db`, kind: 'file' }],
},
{
id: 'database-backups',
type: 'db-backup',
size: { actual: mb(480), symlink: 0 },
paths: [{ path: `${appData}/Backups/app-db`, kind: 'directory' }],
},
],
}
const rootOther: StorageNode = {
id: 'root-other',
type: 'other',
size: { actual: gb(0.3), symlink: 0 },
paths: [
{ path: `${appData}/launcher_logs`, kind: 'directory' },
{ path: `${appData}/app-window-state.json`, kind: 'file' },
{ path: `${appData}/download.log`, kind: 'file' },
{ path: `${appData}/download-reputation.json`, kind: 'file' },
],
}
export const storageTree: StorageTree = {
total: { actual: gb(43.9), symlink: gb(13.7) },
categories: [instancesCategory, cacheCategory, metaCategory, databaseCategory, rootOther],
rootOther,
}

View File

@ -0,0 +1,137 @@
import { defineMessages } from '@modrinth/ui'
export const storageMessages = defineMessages({
total: {
id: 'app.settings.storage.total',
defaultMessage: 'Total size',
},
totalDescription: {
id: 'app.settings.storage.total-description',
defaultMessage: 'Total size including symbolic links and junctions',
},
instanceData: {
id: 'app.settings.storage.instance-data',
defaultMessage: 'Instance data',
},
cacheData: {
id: 'app.settings.storage.cache-data',
defaultMessage: 'Cache data',
},
metaData: {
id: 'app.settings.storage.meta-data',
defaultMessage: 'Meta data',
},
database: {
id: 'app.settings.storage.database',
defaultMessage: 'Database',
},
other: {
id: 'app.settings.storage.other',
defaultMessage: 'Other',
},
instance: {
id: 'app.settings.storage.instance',
defaultMessage: 'Instance',
},
mods: {
id: 'app.settings.storage.mods',
defaultMessage: 'Mods',
},
replay: {
id: 'app.settings.storage.replay',
defaultMessage: 'Replay recordings',
},
resourcepacks: {
id: 'app.settings.storage.resourcepacks',
defaultMessage: 'Resource packs',
},
saves: {
id: 'app.settings.storage.saves',
defaultMessage: 'Saves',
},
world: {
id: 'app.settings.storage.world',
defaultMessage: 'World',
},
schematics: {
id: 'app.settings.storage.schematics',
defaultMessage: 'Schematics',
},
screenshots: {
id: 'app.settings.storage.screenshots',
defaultMessage: 'Screenshots',
},
shaderpacks: {
id: 'app.settings.storage.shaderpacks',
defaultMessage: 'Shader packs',
},
minimap: {
id: 'app.settings.storage.minimap',
defaultMessage: 'Minimap data',
},
distantHorizons: {
id: 'app.settings.storage.distant-horizons',
defaultMessage: 'Distant Horizons cache',
},
dbFile: {
id: 'app.settings.storage.db-file',
defaultMessage: 'App database',
},
dbBackup: {
id: 'app.settings.storage.db-backup',
defaultMessage: 'Database backups',
},
itemCount: {
id: 'app.settings.storage.item-count',
defaultMessage: '{count} items',
},
instanceCount: {
id: 'app.settings.storage.instance-count',
defaultMessage: '{count} instances',
},
actualSizeTooltip: {
id: 'app.settings.storage.actual-size-tooltip',
defaultMessage: 'Actual size: {size}',
},
symlinkSizeTooltip: {
id: 'app.settings.storage.symlink-size-tooltip',
defaultMessage: 'Symbolic link or junction referenced size: {size}',
},
openAction: {
id: 'app.settings.storage.open-action',
defaultMessage: 'Open in launcher or open location',
},
symlinkLabel: {
id: 'app.settings.storage.symlink-label',
defaultMessage: 'symlink',
},
symlinkHelp: {
id: 'app.settings.storage.symlink-help',
defaultMessage: 'What is a symlink?',
},
symlinkHelpTooltip: {
id: 'app.settings.storage.symlink-help-tooltip',
defaultMessage:
'Symbolic links reference Minecraft resources from other locations — these files may actually live in another launcher\u2019s directory.\nFor example, \u201c20MB + 1.2GB\u201d means the launcher folder contains 20MB of files and references an external 1.2GB of files.',
},
update: {
id: 'app.settings.storage.update',
defaultMessage: 'Update',
},
updating: {
id: 'app.settings.storage.updating',
defaultMessage: 'Updating…',
},
lastUpdatedLabel: {
id: 'app.settings.storage.last-updated-label',
defaultMessage: 'Last updated:',
},
scanning: {
id: 'app.settings.storage.scanning',
defaultMessage: 'Scanning storage…',
},
storageTab: {
id: 'app.settings.tabs.storage',
defaultMessage: 'Storage',
},
})