@huyooo/file-explorer-frontend-vue 0.4.10 → 0.4.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/CompressDialog.vue.d.ts.map +1 -1
- package/dist/components/FileInfoDialog.vue.d.ts.map +1 -1
- package/dist/components/FileListView.vue.d.ts.map +1 -1
- package/dist/components/ProgressDialog.vue.d.ts.map +1 -1
- package/dist/components/Window.vue.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +1096 -2224
- package/dist/index.js.map +1 -1
- package/package.json +2 -3
- package/src/components/CompressDialog.vue +4 -4
- package/src/components/FileInfoDialog.vue +6 -19
- package/src/components/FileListView.vue +2 -2
- package/src/components/ProgressDialog.vue +9 -9
- package/src/components/Window.vue +4 -4
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/types/index.ts","../../../node_modules/@iconify/vue/dist/iconify.mjs","../src/utils/fileTypeIcon.ts","../src/utils/folderTypeIcon.ts","../src/components/FileIcon.vue","../src/components/FileGrid.vue","../src/components/SortIndicator.vue","../src/components/FileList.vue","../src/components/FileListView.vue","../src/components/FileSidebar.vue","../src/components/Breadcrumb.vue","../src/components/Toolbar.vue","../src/components/StatusBar.vue","../src/components/ContextMenu.vue","../src/composables/useWindowDrag.ts","../src/composables/useWindowResize.ts","../src/components/Window.vue","../src/components/CompressDialog.vue","../src/components/ProgressDialog.vue","../src/components/FileInfoDialog.vue","../src/composables/useSelection.ts","../src/composables/useDragAndDrop.ts","../src/composables/useMediaPlayer.ts","../src/composables/useApplicationIcon.ts"],"sourcesContent":["/**\n * 文件类型(使用 const object 而非 enum,更好的 tree-shaking)\n */\nexport const FileType = {\n FOLDER: 'folder',\n FILE: 'file',\n IMAGE: 'image',\n VIDEO: 'video',\n MUSIC: 'music',\n DOCUMENT: 'document',\n CODE: 'code',\n TEXT: 'text',\n PDF: 'pdf',\n ARCHIVE: 'archive',\n APPLICATION: 'application',\n UNKNOWN: 'unknown'\n} as const;\n\nexport type FileType = typeof FileType[keyof typeof FileType];\n\n/**\n * 文件系统项\n */\nexport interface FileItem {\n /** 唯一标识(通常是完整路径) */\n id: string;\n name: string;\n type: FileType;\n size?: string;\n dateModified?: string;\n url?: string;\n thumbnailUrl?: string;\n children?: FileItem[];\n}\n\n/**\n * 视图模式\n */\nexport type ViewMode = 'grid' | 'list' | 'columns';\n\n/**\n * 排序配置\n */\nexport interface SortConfig {\n field: 'name' | 'dateModified' | 'size' | 'type';\n direction: 'asc' | 'desc';\n}\n\n/**\n * 侧边栏项目\n */\nexport interface SidebarItem {\n id: string;\n label: string;\n icon?: string;\n path?: string;\n children?: SidebarItem[];\n}\n\n/**\n * 面包屑项\n */\nexport interface BreadcrumbItem {\n id: string;\n name: string;\n}\n\n/**\n * 操作结果\n */\nexport interface OperationResult<T = void> {\n success: boolean;\n data?: T;\n error?: string;\n}\n\n/** 压缩格式 */\nexport type CompressFormat = 'zip' | 'tar' | 'tgz' | 'tarbz2';\n\n/** 压缩级别 */\nexport type CompressLevel = 'fast' | 'normal' | 'best';\n\n/** 压缩选项 */\nexport interface CompressOptions {\n format: CompressFormat;\n level?: CompressLevel;\n outputName: string;\n outputDir: string;\n deleteSource?: boolean;\n}\n\n/** 解压选项 */\nexport interface ExtractOptions {\n targetDir: string;\n deleteArchive?: boolean;\n}\n\n/** 压缩进度 */\nexport interface CompressProgress {\n currentFile: string;\n processedCount: number;\n totalCount: number;\n percent: number;\n}\n\n/** 压缩结果 */\nexport interface CompressResult {\n success: boolean;\n outputPath?: string;\n error?: string;\n}\n\n/** 进度状态 */\nexport type ProgressStatus = 'pending' | 'processing' | 'success' | 'error';\n\n/** 进度信息(UI 使用) */\nexport interface ProgressInfo {\n type: 'compress' | 'extract';\n status: ProgressStatus;\n percent: number;\n currentFile?: string;\n processedCount?: number;\n totalCount?: number;\n error?: string;\n outputPath?: string;\n}\n\n/**\n * 文件操作适配器接口\n */\nexport interface FileExplorerAdapter {\n /** 读取目录 */\n readDirectory(dirPath: string): Promise<FileItem[]>;\n /** 读取系统路径目录 */\n readSystemPath(pathId: string): Promise<FileItem[]>;\n /** 获取系统路径 */\n getSystemPath(pathId: string): Promise<string | null>;\n /** 读取文件内容 */\n readFileContent(filePath: string): Promise<string>;\n /** 写入文件内容 */\n writeFileContent(filePath: string, content: string): Promise<OperationResult>;\n /** 创建文件夹 */\n createFolder(parentDir: string, folderName: string): Promise<OperationResult<{ finalPath: string }>>;\n /** 创建文件 */\n createFile(parentDir: string, fileName: string, content?: string): Promise<OperationResult<{ finalPath: string }>>;\n /** 删除文件 */\n deleteFiles(paths: string[]): Promise<OperationResult>;\n /** 重命名文件 */\n renameFile(oldPath: string, newPath: string): Promise<OperationResult>;\n /** 复制文件 */\n copyFiles(sourcePaths: string[], targetDir: string): Promise<OperationResult<{ copiedPaths: string[] }>>;\n /** 移动文件 */\n moveFiles(sourcePaths: string[], targetDir: string): Promise<OperationResult<{ movedPaths: string[] }>>;\n /** 使用系统默认应用打开 */\n openPath(filePath: string): Promise<OperationResult>;\n /** 复制文件到剪贴板 */\n copyFilesToClipboard(filePaths: string[]): Promise<OperationResult>;\n /** 获取剪贴板文件 */\n getClipboardFiles(): Promise<OperationResult<{ files: string[] }>>;\n /** 粘贴文件 */\n pasteFiles(targetDir: string, sourcePaths: string[]): Promise<OperationResult<{ pastedPaths: string[] }>>;\n /** 流式搜索文件 */\n searchFilesStream(searchPath: string, pattern: string, searchId: string): Promise<OperationResult>;\n /** 监听搜索结果 */\n onSearchResults(callback: (data: { searchId: string; items: FileItem[]; done: boolean }) => void): () => void;\n /** 压缩文件 */\n compressFiles(sources: string[], options: CompressOptions): Promise<CompressResult>;\n /** 解压文件 */\n extractArchive(archivePath: string, options: ExtractOptions): Promise<CompressResult>;\n /** 判断是否为压缩文件 */\n isArchiveFile(filePath: string): Promise<boolean>;\n /** 监听压缩进度 */\n onCompressProgress(callback: (data: CompressProgress) => void): () => void;\n /** 监听解压进度 */\n onExtractProgress(callback: (data: CompressProgress) => void): () => void;\n /** 监听目录变化 */\n watchDirectory(dirPath: string, watchId: string): Promise<OperationResult>;\n /** 停止监听目录 */\n unwatchDirectory(watchId: string): Promise<OperationResult>;\n /** 监听文件变化事件 */\n onWatchEvent(callback: (data: { watchId: string; event: WatchEvent }) => void): () => void;\n /** 显示文件/文件夹的系统属性窗口 */\n showFileInfo(filePath: string): Promise<OperationResult>;\n /** 在终端中打开目录 */\n openInTerminal(dirPath: string): Promise<OperationResult>;\n /** 通过 Cursor 打开 */\n openInEditor(targetPath: string): Promise<OperationResult>;\n /** 在新窗口中打开文件夹(使用系统文件管理器) */\n openInNewWindow(folderPath: string): Promise<OperationResult>;\n /** 请求窗口聚焦(用于右键打开菜单前激活窗口) */\n requestWindowFocus(): void;\n \n // ===== 媒体服务 =====\n \n /** 检测媒体文件是否需要转码 */\n mediaNeedsTranscode?(filePath: string): Promise<OperationResult<TranscodeInfo>>;\n /** 获取可播放的媒体 URL(自动转码) */\n mediaGetPlayableUrl?(filePath: string): Promise<{ success: boolean; url?: string; error?: string }>;\n /** 获取媒体元数据 */\n mediaGetMetadata?(filePath: string): Promise<OperationResult<MediaMetadata>>;\n /** 监听转码进度 */\n onMediaTranscodeProgress?(callback: (data: { filePath: string; progress: MediaTranscodeProgress }) => void): () => void;\n /** 清理指定文件的转码缓存 */\n mediaCleanupFile?(filePath: string): Promise<OperationResult>;\n \n // ===== 媒体预览窗口 =====\n \n /** 打开媒体预览窗口(原生窗口) */\n openMediaPreviewWindow?(filePath: string, mediaType: 'image' | 'video' | 'audio'): Promise<OperationResult>;\n /** 关闭媒体预览窗口 */\n closeMediaPreviewWindow?(filePath: string): Promise<OperationResult>;\n}\n\n/** 文件变化事件类型 */\nexport type WatchEventType = 'add' | 'change' | 'remove' | 'rename';\n\n/** 文件变化事件 */\nexport interface WatchEvent {\n type: WatchEventType;\n path: string;\n filename: string;\n}\n\n// ===== 媒体服务类型 =====\n\n/** 媒体转码方式 */\nexport type TranscodeMethod = 'direct' | 'remux' | 'transcode';\n\n/** 媒体转码状态 */\nexport type TranscodeStatus = 'idle' | 'checking' | 'transcoding' | 'ready' | 'error';\n\n/** 媒体转码信息 */\nexport interface TranscodeInfo {\n type: 'video' | 'audio';\n needsTranscode: boolean;\n method: TranscodeMethod;\n estimatedTime?: number;\n targetFormat?: string;\n}\n\n/** 媒体转码进度 */\nexport interface MediaTranscodeProgress {\n percent: number;\n time?: number;\n duration?: number;\n speed?: string;\n}\n\n/** 媒体元数据 */\nexport interface MediaMetadata {\n filePath: string;\n type: 'video' | 'audio';\n duration: number;\n title?: string;\n artist?: string;\n album?: string;\n}\n\n/**\n * 右键菜单项\n */\nexport interface ContextMenuItem {\n id: string;\n label: string;\n icon?: string;\n shortcut?: string;\n disabled?: boolean;\n separator?: boolean;\n danger?: boolean; // 危险操作标记(如删除)\n checked?: boolean; // 勾选状态(显示在右侧)\n action?: () => void;\n children?: ContextMenuItem[];\n}\n","import { h, defineComponent, ref, shallowRef, onMounted, watch, onUnmounted, nextTick } from 'vue';\n\nconst matchIconName = /^[a-z0-9]+(-[a-z0-9]+)*$/;\nconst stringToIcon = (value, validate, allowSimpleName, provider = \"\") => {\n const colonSeparated = value.split(\":\");\n if (value.slice(0, 1) === \"@\") {\n if (colonSeparated.length < 2 || colonSeparated.length > 3) {\n return null;\n }\n provider = colonSeparated.shift().slice(1);\n }\n if (colonSeparated.length > 3 || !colonSeparated.length) {\n return null;\n }\n if (colonSeparated.length > 1) {\n const name2 = colonSeparated.pop();\n const prefix = colonSeparated.pop();\n const result = {\n // Allow provider without '@': \"provider:prefix:name\"\n provider: colonSeparated.length > 0 ? colonSeparated[0] : provider,\n prefix,\n name: name2\n };\n return validate && !validateIconName(result) ? null : result;\n }\n const name = colonSeparated[0];\n const dashSeparated = name.split(\"-\");\n if (dashSeparated.length > 1) {\n const result = {\n provider,\n prefix: dashSeparated.shift(),\n name: dashSeparated.join(\"-\")\n };\n return validate && !validateIconName(result) ? null : result;\n }\n if (allowSimpleName && provider === \"\") {\n const result = {\n provider,\n prefix: \"\",\n name\n };\n return validate && !validateIconName(result, allowSimpleName) ? null : result;\n }\n return null;\n};\nconst validateIconName = (icon, allowSimpleName) => {\n if (!icon) {\n return false;\n }\n return !!// Check prefix: cannot be empty, unless allowSimpleName is enabled\n // Check name: cannot be empty\n ((allowSimpleName && icon.prefix === \"\" || !!icon.prefix) && !!icon.name);\n};\n\nconst defaultIconDimensions = Object.freeze(\n {\n left: 0,\n top: 0,\n width: 16,\n height: 16\n }\n);\nconst defaultIconTransformations = Object.freeze({\n rotate: 0,\n vFlip: false,\n hFlip: false\n});\nconst defaultIconProps = Object.freeze({\n ...defaultIconDimensions,\n ...defaultIconTransformations\n});\nconst defaultExtendedIconProps = Object.freeze({\n ...defaultIconProps,\n body: \"\",\n hidden: false\n});\n\nfunction mergeIconTransformations(obj1, obj2) {\n const result = {};\n if (!obj1.hFlip !== !obj2.hFlip) {\n result.hFlip = true;\n }\n if (!obj1.vFlip !== !obj2.vFlip) {\n result.vFlip = true;\n }\n const rotate = ((obj1.rotate || 0) + (obj2.rotate || 0)) % 4;\n if (rotate) {\n result.rotate = rotate;\n }\n return result;\n}\n\nfunction mergeIconData(parent, child) {\n const result = mergeIconTransformations(parent, child);\n for (const key in defaultExtendedIconProps) {\n if (key in defaultIconTransformations) {\n if (key in parent && !(key in result)) {\n result[key] = defaultIconTransformations[key];\n }\n } else if (key in child) {\n result[key] = child[key];\n } else if (key in parent) {\n result[key] = parent[key];\n }\n }\n return result;\n}\n\nfunction getIconsTree(data, names) {\n const icons = data.icons;\n const aliases = data.aliases || /* @__PURE__ */ Object.create(null);\n const resolved = /* @__PURE__ */ Object.create(null);\n function resolve(name) {\n if (icons[name]) {\n return resolved[name] = [];\n }\n if (!(name in resolved)) {\n resolved[name] = null;\n const parent = aliases[name] && aliases[name].parent;\n const value = parent && resolve(parent);\n if (value) {\n resolved[name] = [parent].concat(value);\n }\n }\n return resolved[name];\n }\n (Object.keys(icons).concat(Object.keys(aliases))).forEach(resolve);\n return resolved;\n}\n\nfunction internalGetIconData(data, name, tree) {\n const icons = data.icons;\n const aliases = data.aliases || /* @__PURE__ */ Object.create(null);\n let currentProps = {};\n function parse(name2) {\n currentProps = mergeIconData(\n icons[name2] || aliases[name2],\n currentProps\n );\n }\n parse(name);\n tree.forEach(parse);\n return mergeIconData(data, currentProps);\n}\n\nfunction parseIconSet(data, callback) {\n const names = [];\n if (typeof data !== \"object\" || typeof data.icons !== \"object\") {\n return names;\n }\n if (data.not_found instanceof Array) {\n data.not_found.forEach((name) => {\n callback(name, null);\n names.push(name);\n });\n }\n const tree = getIconsTree(data);\n for (const name in tree) {\n const item = tree[name];\n if (item) {\n callback(name, internalGetIconData(data, name, item));\n names.push(name);\n }\n }\n return names;\n}\n\nconst optionalPropertyDefaults = {\n provider: \"\",\n aliases: {},\n not_found: {},\n ...defaultIconDimensions\n};\nfunction checkOptionalProps(item, defaults) {\n for (const prop in defaults) {\n if (prop in item && typeof item[prop] !== typeof defaults[prop]) {\n return false;\n }\n }\n return true;\n}\nfunction quicklyValidateIconSet(obj) {\n if (typeof obj !== \"object\" || obj === null) {\n return null;\n }\n const data = obj;\n if (typeof data.prefix !== \"string\" || !obj.icons || typeof obj.icons !== \"object\") {\n return null;\n }\n if (!checkOptionalProps(obj, optionalPropertyDefaults)) {\n return null;\n }\n const icons = data.icons;\n for (const name in icons) {\n const icon = icons[name];\n if (\n // Name cannot be empty\n !name || // Must have body\n typeof icon.body !== \"string\" || // Check other props\n !checkOptionalProps(\n icon,\n defaultExtendedIconProps\n )\n ) {\n return null;\n }\n }\n const aliases = data.aliases || /* @__PURE__ */ Object.create(null);\n for (const name in aliases) {\n const icon = aliases[name];\n const parent = icon.parent;\n if (\n // Name cannot be empty\n !name || // Parent must be set and point to existing icon\n typeof parent !== \"string\" || !icons[parent] && !aliases[parent] || // Check other props\n !checkOptionalProps(\n icon,\n defaultExtendedIconProps\n )\n ) {\n return null;\n }\n }\n return data;\n}\n\nconst dataStorage = /* @__PURE__ */ Object.create(null);\nfunction newStorage(provider, prefix) {\n return {\n provider,\n prefix,\n icons: /* @__PURE__ */ Object.create(null),\n missing: /* @__PURE__ */ new Set()\n };\n}\nfunction getStorage(provider, prefix) {\n const providerStorage = dataStorage[provider] || (dataStorage[provider] = /* @__PURE__ */ Object.create(null));\n return providerStorage[prefix] || (providerStorage[prefix] = newStorage(provider, prefix));\n}\nfunction addIconSet(storage, data) {\n if (!quicklyValidateIconSet(data)) {\n return [];\n }\n return parseIconSet(data, (name, icon) => {\n if (icon) {\n storage.icons[name] = icon;\n } else {\n storage.missing.add(name);\n }\n });\n}\nfunction addIconToStorage(storage, name, icon) {\n try {\n if (typeof icon.body === \"string\") {\n storage.icons[name] = { ...icon };\n return true;\n }\n } catch (err) {\n }\n return false;\n}\nfunction listIcons(provider, prefix) {\n let allIcons = [];\n const providers = typeof provider === \"string\" ? [provider] : Object.keys(dataStorage);\n providers.forEach((provider2) => {\n const prefixes = typeof provider2 === \"string\" && typeof prefix === \"string\" ? [prefix] : Object.keys(dataStorage[provider2] || {});\n prefixes.forEach((prefix2) => {\n const storage = getStorage(provider2, prefix2);\n allIcons = allIcons.concat(\n Object.keys(storage.icons).map(\n (name) => (provider2 !== \"\" ? \"@\" + provider2 + \":\" : \"\") + prefix2 + \":\" + name\n )\n );\n });\n });\n return allIcons;\n}\n\nlet simpleNames = false;\nfunction allowSimpleNames(allow) {\n if (typeof allow === \"boolean\") {\n simpleNames = allow;\n }\n return simpleNames;\n}\nfunction getIconData(name) {\n const icon = typeof name === \"string\" ? stringToIcon(name, true, simpleNames) : name;\n if (icon) {\n const storage = getStorage(icon.provider, icon.prefix);\n const iconName = icon.name;\n return storage.icons[iconName] || (storage.missing.has(iconName) ? null : void 0);\n }\n}\nfunction addIcon(name, data) {\n const icon = stringToIcon(name, true, simpleNames);\n if (!icon) {\n return false;\n }\n const storage = getStorage(icon.provider, icon.prefix);\n if (data) {\n return addIconToStorage(storage, icon.name, data);\n } else {\n storage.missing.add(icon.name);\n return true;\n }\n}\nfunction addCollection(data, provider) {\n if (typeof data !== \"object\") {\n return false;\n }\n if (typeof provider !== \"string\") {\n provider = data.provider || \"\";\n }\n if (simpleNames && !provider && !data.prefix) {\n let added = false;\n if (quicklyValidateIconSet(data)) {\n data.prefix = \"\";\n parseIconSet(data, (name, icon) => {\n if (addIcon(name, icon)) {\n added = true;\n }\n });\n }\n return added;\n }\n const prefix = data.prefix;\n if (!validateIconName({\n prefix,\n name: \"a\"\n })) {\n return false;\n }\n const storage = getStorage(provider, prefix);\n return !!addIconSet(storage, data);\n}\nfunction iconLoaded(name) {\n return !!getIconData(name);\n}\nfunction getIcon(name) {\n const result = getIconData(name);\n return result ? {\n ...defaultIconProps,\n ...result\n } : result;\n}\n\nconst defaultIconSizeCustomisations = Object.freeze({\n width: null,\n height: null\n});\nconst defaultIconCustomisations = Object.freeze({\n // Dimensions\n ...defaultIconSizeCustomisations,\n // Transformations\n ...defaultIconTransformations\n});\n\nconst unitsSplit = /(-?[0-9.]*[0-9]+[0-9.]*)/g;\nconst unitsTest = /^-?[0-9.]*[0-9]+[0-9.]*$/g;\nfunction calculateSize(size, ratio, precision) {\n if (ratio === 1) {\n return size;\n }\n precision = precision || 100;\n if (typeof size === \"number\") {\n return Math.ceil(size * ratio * precision) / precision;\n }\n if (typeof size !== \"string\") {\n return size;\n }\n const oldParts = size.split(unitsSplit);\n if (oldParts === null || !oldParts.length) {\n return size;\n }\n const newParts = [];\n let code = oldParts.shift();\n let isNumber = unitsTest.test(code);\n while (true) {\n if (isNumber) {\n const num = parseFloat(code);\n if (isNaN(num)) {\n newParts.push(code);\n } else {\n newParts.push(Math.ceil(num * ratio * precision) / precision);\n }\n } else {\n newParts.push(code);\n }\n code = oldParts.shift();\n if (code === void 0) {\n return newParts.join(\"\");\n }\n isNumber = !isNumber;\n }\n}\n\nfunction splitSVGDefs(content, tag = \"defs\") {\n let defs = \"\";\n const index = content.indexOf(\"<\" + tag);\n while (index >= 0) {\n const start = content.indexOf(\">\", index);\n const end = content.indexOf(\"</\" + tag);\n if (start === -1 || end === -1) {\n break;\n }\n const endEnd = content.indexOf(\">\", end);\n if (endEnd === -1) {\n break;\n }\n defs += content.slice(start + 1, end).trim();\n content = content.slice(0, index).trim() + content.slice(endEnd + 1);\n }\n return {\n defs,\n content\n };\n}\nfunction mergeDefsAndContent(defs, content) {\n return defs ? \"<defs>\" + defs + \"</defs>\" + content : content;\n}\nfunction wrapSVGContent(body, start, end) {\n const split = splitSVGDefs(body);\n return mergeDefsAndContent(split.defs, start + split.content + end);\n}\n\nconst isUnsetKeyword = (value) => value === \"unset\" || value === \"undefined\" || value === \"none\";\nfunction iconToSVG(icon, customisations) {\n const fullIcon = {\n ...defaultIconProps,\n ...icon\n };\n const fullCustomisations = {\n ...defaultIconCustomisations,\n ...customisations\n };\n const box = {\n left: fullIcon.left,\n top: fullIcon.top,\n width: fullIcon.width,\n height: fullIcon.height\n };\n let body = fullIcon.body;\n [fullIcon, fullCustomisations].forEach((props) => {\n const transformations = [];\n const hFlip = props.hFlip;\n const vFlip = props.vFlip;\n let rotation = props.rotate;\n if (hFlip) {\n if (vFlip) {\n rotation += 2;\n } else {\n transformations.push(\n \"translate(\" + (box.width + box.left).toString() + \" \" + (0 - box.top).toString() + \")\"\n );\n transformations.push(\"scale(-1 1)\");\n box.top = box.left = 0;\n }\n } else if (vFlip) {\n transformations.push(\n \"translate(\" + (0 - box.left).toString() + \" \" + (box.height + box.top).toString() + \")\"\n );\n transformations.push(\"scale(1 -1)\");\n box.top = box.left = 0;\n }\n let tempValue;\n if (rotation < 0) {\n rotation -= Math.floor(rotation / 4) * 4;\n }\n rotation = rotation % 4;\n switch (rotation) {\n case 1:\n tempValue = box.height / 2 + box.top;\n transformations.unshift(\n \"rotate(90 \" + tempValue.toString() + \" \" + tempValue.toString() + \")\"\n );\n break;\n case 2:\n transformations.unshift(\n \"rotate(180 \" + (box.width / 2 + box.left).toString() + \" \" + (box.height / 2 + box.top).toString() + \")\"\n );\n break;\n case 3:\n tempValue = box.width / 2 + box.left;\n transformations.unshift(\n \"rotate(-90 \" + tempValue.toString() + \" \" + tempValue.toString() + \")\"\n );\n break;\n }\n if (rotation % 2 === 1) {\n if (box.left !== box.top) {\n tempValue = box.left;\n box.left = box.top;\n box.top = tempValue;\n }\n if (box.width !== box.height) {\n tempValue = box.width;\n box.width = box.height;\n box.height = tempValue;\n }\n }\n if (transformations.length) {\n body = wrapSVGContent(\n body,\n '<g transform=\"' + transformations.join(\" \") + '\">',\n \"</g>\"\n );\n }\n });\n const customisationsWidth = fullCustomisations.width;\n const customisationsHeight = fullCustomisations.height;\n const boxWidth = box.width;\n const boxHeight = box.height;\n let width;\n let height;\n if (customisationsWidth === null) {\n height = customisationsHeight === null ? \"1em\" : customisationsHeight === \"auto\" ? boxHeight : customisationsHeight;\n width = calculateSize(height, boxWidth / boxHeight);\n } else {\n width = customisationsWidth === \"auto\" ? boxWidth : customisationsWidth;\n height = customisationsHeight === null ? calculateSize(width, boxHeight / boxWidth) : customisationsHeight === \"auto\" ? boxHeight : customisationsHeight;\n }\n const attributes = {};\n const setAttr = (prop, value) => {\n if (!isUnsetKeyword(value)) {\n attributes[prop] = value.toString();\n }\n };\n setAttr(\"width\", width);\n setAttr(\"height\", height);\n const viewBox = [box.left, box.top, boxWidth, boxHeight];\n attributes.viewBox = viewBox.join(\" \");\n return {\n attributes,\n viewBox,\n body\n };\n}\n\nconst regex = /\\sid=\"(\\S+)\"/g;\nconst randomPrefix = \"IconifyId\" + Date.now().toString(16) + (Math.random() * 16777216 | 0).toString(16);\nlet counter = 0;\nfunction replaceIDs(body, prefix = randomPrefix) {\n const ids = [];\n let match;\n while (match = regex.exec(body)) {\n ids.push(match[1]);\n }\n if (!ids.length) {\n return body;\n }\n const suffix = \"suffix\" + (Math.random() * 16777216 | Date.now()).toString(16);\n ids.forEach((id) => {\n const newID = typeof prefix === \"function\" ? prefix(id) : prefix + (counter++).toString();\n const escapedID = id.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n body = body.replace(\n // Allowed characters before id: [#;\"]\n // Allowed characters after id: [)\"], .[a-z]\n new RegExp('([#;\"])(' + escapedID + ')([\")]|\\\\.[a-z])', \"g\"),\n \"$1\" + newID + suffix + \"$3\"\n );\n });\n body = body.replace(new RegExp(suffix, \"g\"), \"\");\n return body;\n}\n\nconst storage = /* @__PURE__ */ Object.create(null);\nfunction setAPIModule(provider, item) {\n storage[provider] = item;\n}\nfunction getAPIModule(provider) {\n return storage[provider] || storage[\"\"];\n}\n\nfunction createAPIConfig(source) {\n let resources;\n if (typeof source.resources === \"string\") {\n resources = [source.resources];\n } else {\n resources = source.resources;\n if (!(resources instanceof Array) || !resources.length) {\n return null;\n }\n }\n const result = {\n // API hosts\n resources,\n // Root path\n path: source.path || \"/\",\n // URL length limit\n maxURL: source.maxURL || 500,\n // Timeout before next host is used.\n rotate: source.rotate || 750,\n // Timeout before failing query.\n timeout: source.timeout || 5e3,\n // Randomise default API end point.\n random: source.random === true,\n // Start index\n index: source.index || 0,\n // Receive data after time out (used if time out kicks in first, then API module sends data anyway).\n dataAfterTimeout: source.dataAfterTimeout !== false\n };\n return result;\n}\nconst configStorage = /* @__PURE__ */ Object.create(null);\nconst fallBackAPISources = [\n \"https://api.simplesvg.com\",\n \"https://api.unisvg.com\"\n];\nconst fallBackAPI = [];\nwhile (fallBackAPISources.length > 0) {\n if (fallBackAPISources.length === 1) {\n fallBackAPI.push(fallBackAPISources.shift());\n } else {\n if (Math.random() > 0.5) {\n fallBackAPI.push(fallBackAPISources.shift());\n } else {\n fallBackAPI.push(fallBackAPISources.pop());\n }\n }\n}\nconfigStorage[\"\"] = createAPIConfig({\n resources: [\"https://api.iconify.design\"].concat(fallBackAPI)\n});\nfunction addAPIProvider(provider, customConfig) {\n const config = createAPIConfig(customConfig);\n if (config === null) {\n return false;\n }\n configStorage[provider] = config;\n return true;\n}\nfunction getAPIConfig(provider) {\n return configStorage[provider];\n}\nfunction listAPIProviders() {\n return Object.keys(configStorage);\n}\n\nconst detectFetch = () => {\n let callback;\n try {\n callback = fetch;\n if (typeof callback === \"function\") {\n return callback;\n }\n } catch (err) {\n }\n};\nlet fetchModule = detectFetch();\nfunction setFetch(fetch2) {\n fetchModule = fetch2;\n}\nfunction getFetch() {\n return fetchModule;\n}\nfunction calculateMaxLength(provider, prefix) {\n const config = getAPIConfig(provider);\n if (!config) {\n return 0;\n }\n let result;\n if (!config.maxURL) {\n result = 0;\n } else {\n let maxHostLength = 0;\n config.resources.forEach((item) => {\n const host = item;\n maxHostLength = Math.max(maxHostLength, host.length);\n });\n const url = prefix + \".json?icons=\";\n result = config.maxURL - maxHostLength - config.path.length - url.length;\n }\n return result;\n}\nfunction shouldAbort(status) {\n return status === 404;\n}\nconst prepare = (provider, prefix, icons) => {\n const results = [];\n const maxLength = calculateMaxLength(provider, prefix);\n const type = \"icons\";\n let item = {\n type,\n provider,\n prefix,\n icons: []\n };\n let length = 0;\n icons.forEach((name, index) => {\n length += name.length + 1;\n if (length >= maxLength && index > 0) {\n results.push(item);\n item = {\n type,\n provider,\n prefix,\n icons: []\n };\n length = name.length;\n }\n item.icons.push(name);\n });\n results.push(item);\n return results;\n};\nfunction getPath(provider) {\n if (typeof provider === \"string\") {\n const config = getAPIConfig(provider);\n if (config) {\n return config.path;\n }\n }\n return \"/\";\n}\nconst send = (host, params, callback) => {\n if (!fetchModule) {\n callback(\"abort\", 424);\n return;\n }\n let path = getPath(params.provider);\n switch (params.type) {\n case \"icons\": {\n const prefix = params.prefix;\n const icons = params.icons;\n const iconsList = icons.join(\",\");\n const urlParams = new URLSearchParams({\n icons: iconsList\n });\n path += prefix + \".json?\" + urlParams.toString();\n break;\n }\n case \"custom\": {\n const uri = params.uri;\n path += uri.slice(0, 1) === \"/\" ? uri.slice(1) : uri;\n break;\n }\n default:\n callback(\"abort\", 400);\n return;\n }\n let defaultError = 503;\n fetchModule(host + path).then((response) => {\n const status = response.status;\n if (status !== 200) {\n setTimeout(() => {\n callback(shouldAbort(status) ? \"abort\" : \"next\", status);\n });\n return;\n }\n defaultError = 501;\n return response.json();\n }).then((data) => {\n if (typeof data !== \"object\" || data === null) {\n setTimeout(() => {\n if (data === 404) {\n callback(\"abort\", data);\n } else {\n callback(\"next\", defaultError);\n }\n });\n return;\n }\n setTimeout(() => {\n callback(\"success\", data);\n });\n }).catch(() => {\n callback(\"next\", defaultError);\n });\n};\nconst fetchAPIModule = {\n prepare,\n send\n};\n\nfunction sortIcons(icons) {\n const result = {\n loaded: [],\n missing: [],\n pending: []\n };\n const storage = /* @__PURE__ */ Object.create(null);\n icons.sort((a, b) => {\n if (a.provider !== b.provider) {\n return a.provider.localeCompare(b.provider);\n }\n if (a.prefix !== b.prefix) {\n return a.prefix.localeCompare(b.prefix);\n }\n return a.name.localeCompare(b.name);\n });\n let lastIcon = {\n provider: \"\",\n prefix: \"\",\n name: \"\"\n };\n icons.forEach((icon) => {\n if (lastIcon.name === icon.name && lastIcon.prefix === icon.prefix && lastIcon.provider === icon.provider) {\n return;\n }\n lastIcon = icon;\n const provider = icon.provider;\n const prefix = icon.prefix;\n const name = icon.name;\n const providerStorage = storage[provider] || (storage[provider] = /* @__PURE__ */ Object.create(null));\n const localStorage = providerStorage[prefix] || (providerStorage[prefix] = getStorage(provider, prefix));\n let list;\n if (name in localStorage.icons) {\n list = result.loaded;\n } else if (prefix === \"\" || localStorage.missing.has(name)) {\n list = result.missing;\n } else {\n list = result.pending;\n }\n const item = {\n provider,\n prefix,\n name\n };\n list.push(item);\n });\n return result;\n}\n\nfunction removeCallback(storages, id) {\n storages.forEach((storage) => {\n const items = storage.loaderCallbacks;\n if (items) {\n storage.loaderCallbacks = items.filter((row) => row.id !== id);\n }\n });\n}\nfunction updateCallbacks(storage) {\n if (!storage.pendingCallbacksFlag) {\n storage.pendingCallbacksFlag = true;\n setTimeout(() => {\n storage.pendingCallbacksFlag = false;\n const items = storage.loaderCallbacks ? storage.loaderCallbacks.slice(0) : [];\n if (!items.length) {\n return;\n }\n let hasPending = false;\n const provider = storage.provider;\n const prefix = storage.prefix;\n items.forEach((item) => {\n const icons = item.icons;\n const oldLength = icons.pending.length;\n icons.pending = icons.pending.filter((icon) => {\n if (icon.prefix !== prefix) {\n return true;\n }\n const name = icon.name;\n if (storage.icons[name]) {\n icons.loaded.push({\n provider,\n prefix,\n name\n });\n } else if (storage.missing.has(name)) {\n icons.missing.push({\n provider,\n prefix,\n name\n });\n } else {\n hasPending = true;\n return true;\n }\n return false;\n });\n if (icons.pending.length !== oldLength) {\n if (!hasPending) {\n removeCallback([storage], item.id);\n }\n item.callback(\n icons.loaded.slice(0),\n icons.missing.slice(0),\n icons.pending.slice(0),\n item.abort\n );\n }\n });\n });\n }\n}\nlet idCounter = 0;\nfunction storeCallback(callback, icons, pendingSources) {\n const id = idCounter++;\n const abort = removeCallback.bind(null, pendingSources, id);\n if (!icons.pending.length) {\n return abort;\n }\n const item = {\n id,\n icons,\n callback,\n abort\n };\n pendingSources.forEach((storage) => {\n (storage.loaderCallbacks || (storage.loaderCallbacks = [])).push(item);\n });\n return abort;\n}\n\nfunction listToIcons(list, validate = true, simpleNames = false) {\n const result = [];\n list.forEach((item) => {\n const icon = typeof item === \"string\" ? stringToIcon(item, validate, simpleNames) : item;\n if (icon) {\n result.push(icon);\n }\n });\n return result;\n}\n\n// src/config.ts\nvar defaultConfig = {\n resources: [],\n index: 0,\n timeout: 2e3,\n rotate: 750,\n random: false,\n dataAfterTimeout: false\n};\n\n// src/query.ts\nfunction sendQuery(config, payload, query, done) {\n const resourcesCount = config.resources.length;\n const startIndex = config.random ? Math.floor(Math.random() * resourcesCount) : config.index;\n let resources;\n if (config.random) {\n let list = config.resources.slice(0);\n resources = [];\n while (list.length > 1) {\n const nextIndex = Math.floor(Math.random() * list.length);\n resources.push(list[nextIndex]);\n list = list.slice(0, nextIndex).concat(list.slice(nextIndex + 1));\n }\n resources = resources.concat(list);\n } else {\n resources = config.resources.slice(startIndex).concat(config.resources.slice(0, startIndex));\n }\n const startTime = Date.now();\n let status = \"pending\";\n let queriesSent = 0;\n let lastError;\n let timer = null;\n let queue = [];\n let doneCallbacks = [];\n if (typeof done === \"function\") {\n doneCallbacks.push(done);\n }\n function resetTimer() {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n }\n function abort() {\n if (status === \"pending\") {\n status = \"aborted\";\n }\n resetTimer();\n queue.forEach((item) => {\n if (item.status === \"pending\") {\n item.status = \"aborted\";\n }\n });\n queue = [];\n }\n function subscribe(callback, overwrite) {\n if (overwrite) {\n doneCallbacks = [];\n }\n if (typeof callback === \"function\") {\n doneCallbacks.push(callback);\n }\n }\n function getQueryStatus() {\n return {\n startTime,\n payload,\n status,\n queriesSent,\n queriesPending: queue.length,\n subscribe,\n abort\n };\n }\n function failQuery() {\n status = \"failed\";\n doneCallbacks.forEach((callback) => {\n callback(void 0, lastError);\n });\n }\n function clearQueue() {\n queue.forEach((item) => {\n if (item.status === \"pending\") {\n item.status = \"aborted\";\n }\n });\n queue = [];\n }\n function moduleResponse(item, response, data) {\n const isError = response !== \"success\";\n queue = queue.filter((queued) => queued !== item);\n switch (status) {\n case \"pending\":\n break;\n case \"failed\":\n if (isError || !config.dataAfterTimeout) {\n return;\n }\n break;\n default:\n return;\n }\n if (response === \"abort\") {\n lastError = data;\n failQuery();\n return;\n }\n if (isError) {\n lastError = data;\n if (!queue.length) {\n if (!resources.length) {\n failQuery();\n } else {\n execNext();\n }\n }\n return;\n }\n resetTimer();\n clearQueue();\n if (!config.random) {\n const index = config.resources.indexOf(item.resource);\n if (index !== -1 && index !== config.index) {\n config.index = index;\n }\n }\n status = \"completed\";\n doneCallbacks.forEach((callback) => {\n callback(data);\n });\n }\n function execNext() {\n if (status !== \"pending\") {\n return;\n }\n resetTimer();\n const resource = resources.shift();\n if (resource === void 0) {\n if (queue.length) {\n timer = setTimeout(() => {\n resetTimer();\n if (status === \"pending\") {\n clearQueue();\n failQuery();\n }\n }, config.timeout);\n return;\n }\n failQuery();\n return;\n }\n const item = {\n status: \"pending\",\n resource,\n callback: (status2, data) => {\n moduleResponse(item, status2, data);\n }\n };\n queue.push(item);\n queriesSent++;\n timer = setTimeout(execNext, config.rotate);\n query(resource, payload, item.callback);\n }\n setTimeout(execNext);\n return getQueryStatus;\n}\n\n// src/index.ts\nfunction initRedundancy(cfg) {\n const config = {\n ...defaultConfig,\n ...cfg\n };\n let queries = [];\n function cleanup() {\n queries = queries.filter((item) => item().status === \"pending\");\n }\n function query(payload, queryCallback, doneCallback) {\n const query2 = sendQuery(\n config,\n payload,\n queryCallback,\n (data, error) => {\n cleanup();\n if (doneCallback) {\n doneCallback(data, error);\n }\n }\n );\n queries.push(query2);\n return query2;\n }\n function find(callback) {\n return queries.find((value) => {\n return callback(value);\n }) || null;\n }\n const instance = {\n query,\n find,\n setIndex: (index) => {\n config.index = index;\n },\n getIndex: () => config.index,\n cleanup\n };\n return instance;\n}\n\nfunction emptyCallback$1() {\n}\nconst redundancyCache = /* @__PURE__ */ Object.create(null);\nfunction getRedundancyCache(provider) {\n if (!redundancyCache[provider]) {\n const config = getAPIConfig(provider);\n if (!config) {\n return;\n }\n const redundancy = initRedundancy(config);\n const cachedReundancy = {\n config,\n redundancy\n };\n redundancyCache[provider] = cachedReundancy;\n }\n return redundancyCache[provider];\n}\nfunction sendAPIQuery(target, query, callback) {\n let redundancy;\n let send;\n if (typeof target === \"string\") {\n const api = getAPIModule(target);\n if (!api) {\n callback(void 0, 424);\n return emptyCallback$1;\n }\n send = api.send;\n const cached = getRedundancyCache(target);\n if (cached) {\n redundancy = cached.redundancy;\n }\n } else {\n const config = createAPIConfig(target);\n if (config) {\n redundancy = initRedundancy(config);\n const moduleKey = target.resources ? target.resources[0] : \"\";\n const api = getAPIModule(moduleKey);\n if (api) {\n send = api.send;\n }\n }\n }\n if (!redundancy || !send) {\n callback(void 0, 424);\n return emptyCallback$1;\n }\n return redundancy.query(query, send, callback)().abort;\n}\n\nfunction emptyCallback() {\n}\nfunction loadedNewIcons(storage) {\n if (!storage.iconsLoaderFlag) {\n storage.iconsLoaderFlag = true;\n setTimeout(() => {\n storage.iconsLoaderFlag = false;\n updateCallbacks(storage);\n });\n }\n}\nfunction checkIconNamesForAPI(icons) {\n const valid = [];\n const invalid = [];\n icons.forEach((name) => {\n (name.match(matchIconName) ? valid : invalid).push(name);\n });\n return {\n valid,\n invalid\n };\n}\nfunction parseLoaderResponse(storage, icons, data) {\n function checkMissing() {\n const pending = storage.pendingIcons;\n icons.forEach((name) => {\n if (pending) {\n pending.delete(name);\n }\n if (!storage.icons[name]) {\n storage.missing.add(name);\n }\n });\n }\n if (data && typeof data === \"object\") {\n try {\n const parsed = addIconSet(storage, data);\n if (!parsed.length) {\n checkMissing();\n return;\n }\n } catch (err) {\n console.error(err);\n }\n }\n checkMissing();\n loadedNewIcons(storage);\n}\nfunction parsePossiblyAsyncResponse(response, callback) {\n if (response instanceof Promise) {\n response.then((data) => {\n callback(data);\n }).catch(() => {\n callback(null);\n });\n } else {\n callback(response);\n }\n}\nfunction loadNewIcons(storage, icons) {\n if (!storage.iconsToLoad) {\n storage.iconsToLoad = icons;\n } else {\n storage.iconsToLoad = storage.iconsToLoad.concat(icons).sort();\n }\n if (!storage.iconsQueueFlag) {\n storage.iconsQueueFlag = true;\n setTimeout(() => {\n storage.iconsQueueFlag = false;\n const { provider, prefix } = storage;\n const icons2 = storage.iconsToLoad;\n delete storage.iconsToLoad;\n if (!icons2 || !icons2.length) {\n return;\n }\n const customIconLoader = storage.loadIcon;\n if (storage.loadIcons && (icons2.length > 1 || !customIconLoader)) {\n parsePossiblyAsyncResponse(\n storage.loadIcons(icons2, prefix, provider),\n (data) => {\n parseLoaderResponse(storage, icons2, data);\n }\n );\n return;\n }\n if (customIconLoader) {\n icons2.forEach((name) => {\n const response = customIconLoader(name, prefix, provider);\n parsePossiblyAsyncResponse(response, (data) => {\n const iconSet = data ? {\n prefix,\n icons: {\n [name]: data\n }\n } : null;\n parseLoaderResponse(storage, [name], iconSet);\n });\n });\n return;\n }\n const { valid, invalid } = checkIconNamesForAPI(icons2);\n if (invalid.length) {\n parseLoaderResponse(storage, invalid, null);\n }\n if (!valid.length) {\n return;\n }\n const api = prefix.match(matchIconName) ? getAPIModule(provider) : null;\n if (!api) {\n parseLoaderResponse(storage, valid, null);\n return;\n }\n const params = api.prepare(provider, prefix, valid);\n params.forEach((item) => {\n sendAPIQuery(provider, item, (data) => {\n parseLoaderResponse(storage, item.icons, data);\n });\n });\n });\n }\n}\nconst loadIcons = (icons, callback) => {\n const cleanedIcons = listToIcons(icons, true, allowSimpleNames());\n const sortedIcons = sortIcons(cleanedIcons);\n if (!sortedIcons.pending.length) {\n let callCallback = true;\n if (callback) {\n setTimeout(() => {\n if (callCallback) {\n callback(\n sortedIcons.loaded,\n sortedIcons.missing,\n sortedIcons.pending,\n emptyCallback\n );\n }\n });\n }\n return () => {\n callCallback = false;\n };\n }\n const newIcons = /* @__PURE__ */ Object.create(null);\n const sources = [];\n let lastProvider, lastPrefix;\n sortedIcons.pending.forEach((icon) => {\n const { provider, prefix } = icon;\n if (prefix === lastPrefix && provider === lastProvider) {\n return;\n }\n lastProvider = provider;\n lastPrefix = prefix;\n sources.push(getStorage(provider, prefix));\n const providerNewIcons = newIcons[provider] || (newIcons[provider] = /* @__PURE__ */ Object.create(null));\n if (!providerNewIcons[prefix]) {\n providerNewIcons[prefix] = [];\n }\n });\n sortedIcons.pending.forEach((icon) => {\n const { provider, prefix, name } = icon;\n const storage = getStorage(provider, prefix);\n const pendingQueue = storage.pendingIcons || (storage.pendingIcons = /* @__PURE__ */ new Set());\n if (!pendingQueue.has(name)) {\n pendingQueue.add(name);\n newIcons[provider][prefix].push(name);\n }\n });\n sources.forEach((storage) => {\n const list = newIcons[storage.provider][storage.prefix];\n if (list.length) {\n loadNewIcons(storage, list);\n }\n });\n return callback ? storeCallback(callback, sortedIcons, sources) : emptyCallback;\n};\nconst loadIcon = (icon) => {\n return new Promise((fulfill, reject) => {\n const iconObj = typeof icon === \"string\" ? stringToIcon(icon, true) : icon;\n if (!iconObj) {\n reject(icon);\n return;\n }\n loadIcons([iconObj || icon], (loaded) => {\n if (loaded.length && iconObj) {\n const data = getIconData(iconObj);\n if (data) {\n fulfill({\n ...defaultIconProps,\n ...data\n });\n return;\n }\n }\n reject(icon);\n });\n });\n};\n\nfunction setCustomIconsLoader(loader, prefix, provider) {\n getStorage(provider || \"\", prefix).loadIcons = loader;\n}\nfunction setCustomIconLoader(loader, prefix, provider) {\n getStorage(provider || \"\", prefix).loadIcon = loader;\n}\n\nfunction mergeCustomisations(defaults, item) {\n const result = {\n ...defaults\n };\n for (const key in item) {\n const value = item[key];\n const valueType = typeof value;\n if (key in defaultIconSizeCustomisations) {\n if (value === null || value && (valueType === \"string\" || valueType === \"number\")) {\n result[key] = value;\n }\n } else if (valueType === typeof result[key]) {\n result[key] = key === \"rotate\" ? value % 4 : value;\n }\n }\n return result;\n}\n\nconst separator = /[\\s,]+/;\nfunction flipFromString(custom, flip) {\n flip.split(separator).forEach((str) => {\n const value = str.trim();\n switch (value) {\n case \"horizontal\":\n custom.hFlip = true;\n break;\n case \"vertical\":\n custom.vFlip = true;\n break;\n }\n });\n}\n\nfunction rotateFromString(value, defaultValue = 0) {\n const units = value.replace(/^-?[0-9.]*/, \"\");\n function cleanup(value2) {\n while (value2 < 0) {\n value2 += 4;\n }\n return value2 % 4;\n }\n if (units === \"\") {\n const num = parseInt(value);\n return isNaN(num) ? 0 : cleanup(num);\n } else if (units !== value) {\n let split = 0;\n switch (units) {\n case \"%\":\n split = 25;\n break;\n case \"deg\":\n split = 90;\n }\n if (split) {\n let num = parseFloat(value.slice(0, value.length - units.length));\n if (isNaN(num)) {\n return 0;\n }\n num = num / split;\n return num % 1 === 0 ? cleanup(num) : 0;\n }\n }\n return defaultValue;\n}\n\nfunction iconToHTML(body, attributes) {\n let renderAttribsHTML = body.indexOf(\"xlink:\") === -1 ? \"\" : ' xmlns:xlink=\"http://www.w3.org/1999/xlink\"';\n for (const attr in attributes) {\n renderAttribsHTML += \" \" + attr + '=\"' + attributes[attr] + '\"';\n }\n return '<svg xmlns=\"http://www.w3.org/2000/svg\"' + renderAttribsHTML + \">\" + body + \"</svg>\";\n}\n\nfunction encodeSVGforURL(svg) {\n return svg.replace(/\"/g, \"'\").replace(/%/g, \"%25\").replace(/#/g, \"%23\").replace(/</g, \"%3C\").replace(/>/g, \"%3E\").replace(/\\s+/g, \" \");\n}\nfunction svgToData(svg) {\n return \"data:image/svg+xml,\" + encodeSVGforURL(svg);\n}\nfunction svgToURL(svg) {\n return 'url(\"' + svgToData(svg) + '\")';\n}\n\nconst defaultExtendedIconCustomisations = {\n ...defaultIconCustomisations,\n inline: false,\n};\n\n/**\n * Default SVG attributes\n */\nconst svgDefaults = {\n 'xmlns': 'http://www.w3.org/2000/svg',\n 'xmlns:xlink': 'http://www.w3.org/1999/xlink',\n 'aria-hidden': true,\n 'role': 'img',\n};\n/**\n * Style modes\n */\nconst commonProps = {\n display: 'inline-block',\n};\nconst monotoneProps = {\n backgroundColor: 'currentColor',\n};\nconst coloredProps = {\n backgroundColor: 'transparent',\n};\n// Dynamically add common props to variables above\nconst propsToAdd = {\n Image: 'var(--svg)',\n Repeat: 'no-repeat',\n Size: '100% 100%',\n};\nconst propsToAddTo = {\n webkitMask: monotoneProps,\n mask: monotoneProps,\n background: coloredProps,\n};\nfor (const prefix in propsToAddTo) {\n const list = propsToAddTo[prefix];\n for (const prop in propsToAdd) {\n list[prefix + prop] = propsToAdd[prop];\n }\n}\n/**\n * Aliases for customisations.\n * In Vue 'v-' properties are reserved, so v-flip must be renamed\n */\nconst customisationAliases = {};\n['horizontal', 'vertical'].forEach((prefix) => {\n const attr = prefix.slice(0, 1) + 'Flip';\n // vertical-flip\n customisationAliases[prefix + '-flip'] = attr;\n // v-flip\n customisationAliases[prefix.slice(0, 1) + '-flip'] = attr;\n // verticalFlip\n customisationAliases[prefix + 'Flip'] = attr;\n});\n/**\n * Fix size: add 'px' to numbers\n */\nfunction fixSize(value) {\n return value + (value.match(/^[-0-9.]+$/) ? 'px' : '');\n}\n/**\n * Render icon\n */\nconst render = (\n// Icon must be validated before calling this function\nicon, \n// Partial properties\nprops) => {\n // Split properties\n const customisations = mergeCustomisations(defaultExtendedIconCustomisations, props);\n const componentProps = { ...svgDefaults };\n // Check mode\n const mode = props.mode || 'svg';\n // Copy style\n const style = {};\n const propsStyle = props.style;\n const customStyle = typeof propsStyle === 'object' && !(propsStyle instanceof Array)\n ? propsStyle\n : {};\n // Get element properties\n for (let key in props) {\n const value = props[key];\n if (value === void 0) {\n continue;\n }\n switch (key) {\n // Properties to ignore\n case 'icon':\n case 'style':\n case 'onLoad':\n case 'mode':\n case 'ssr':\n break;\n // Boolean attributes\n case 'inline':\n case 'hFlip':\n case 'vFlip':\n customisations[key] =\n value === true || value === 'true' || value === 1;\n break;\n // Flip as string: 'horizontal,vertical'\n case 'flip':\n if (typeof value === 'string') {\n flipFromString(customisations, value);\n }\n break;\n // Color: override style\n case 'color':\n style.color = value;\n break;\n // Rotation as string\n case 'rotate':\n if (typeof value === 'string') {\n customisations[key] = rotateFromString(value);\n }\n else if (typeof value === 'number') {\n customisations[key] = value;\n }\n break;\n // Remove aria-hidden\n case 'ariaHidden':\n case 'aria-hidden':\n // Vue transforms 'aria-hidden' property to 'ariaHidden'\n if (value !== true && value !== 'true') {\n delete componentProps['aria-hidden'];\n }\n break;\n default: {\n const alias = customisationAliases[key];\n if (alias) {\n // Aliases for boolean customisations\n if (value === true || value === 'true' || value === 1) {\n customisations[alias] = true;\n }\n }\n else if (defaultExtendedIconCustomisations[key] === void 0) {\n // Copy missing property if it does not exist in customisations\n componentProps[key] = value;\n }\n }\n }\n }\n // Generate icon\n const item = iconToSVG(icon, customisations);\n const renderAttribs = item.attributes;\n // Inline display\n if (customisations.inline) {\n style.verticalAlign = '-0.125em';\n }\n if (mode === 'svg') {\n // Add style\n componentProps.style = {\n ...style,\n ...customStyle,\n };\n // Add icon stuff\n Object.assign(componentProps, renderAttribs);\n // Counter for ids based on \"id\" property to render icons consistently on server and client\n let localCounter = 0;\n let id = props.id;\n if (typeof id === 'string') {\n // Convert '-' to '_' to avoid errors in animations\n id = id.replace(/-/g, '_');\n }\n // Add innerHTML and style to props\n componentProps['innerHTML'] = replaceIDs(item.body, id ? () => id + 'ID' + localCounter++ : 'iconifyVue');\n // Render icon\n return h('svg', componentProps);\n }\n // Render <span> with style\n const { body, width, height } = icon;\n const useMask = mode === 'mask' ||\n (mode === 'bg' ? false : body.indexOf('currentColor') !== -1);\n // Generate SVG\n const html = iconToHTML(body, {\n ...renderAttribs,\n width: width + '',\n height: height + '',\n });\n // Generate style\n componentProps.style = {\n ...style,\n '--svg': svgToURL(html),\n 'width': fixSize(renderAttribs.width),\n 'height': fixSize(renderAttribs.height),\n ...commonProps,\n ...(useMask ? monotoneProps : coloredProps),\n ...customStyle,\n };\n return h('span', componentProps);\n};\n\n/**\n * Initialise stuff\n */\n// Enable short names\nallowSimpleNames(true);\n// Set API module\nsetAPIModule('', fetchAPIModule);\n/**\n * Browser stuff\n */\nif (typeof document !== 'undefined' && typeof window !== 'undefined') {\n const _window = window;\n // Load icons from global \"IconifyPreload\"\n if (_window.IconifyPreload !== void 0) {\n const preload = _window.IconifyPreload;\n const err = 'Invalid IconifyPreload syntax.';\n if (typeof preload === 'object' && preload !== null) {\n (preload instanceof Array ? preload : [preload]).forEach((item) => {\n try {\n if (\n // Check if item is an object and not null/array\n typeof item !== 'object' ||\n item === null ||\n item instanceof Array ||\n // Check for 'icons' and 'prefix'\n typeof item.icons !== 'object' ||\n typeof item.prefix !== 'string' ||\n // Add icon set\n !addCollection(item)) {\n console.error(err);\n }\n }\n catch (e) {\n console.error(err);\n }\n });\n }\n }\n // Set API from global \"IconifyProviders\"\n if (_window.IconifyProviders !== void 0) {\n const providers = _window.IconifyProviders;\n if (typeof providers === 'object' && providers !== null) {\n for (let key in providers) {\n const err = 'IconifyProviders[' + key + '] is invalid.';\n try {\n const value = providers[key];\n if (typeof value !== 'object' ||\n !value ||\n value.resources === void 0) {\n continue;\n }\n if (!addAPIProvider(key, value)) {\n console.error(err);\n }\n }\n catch (e) {\n console.error(err);\n }\n }\n }\n }\n}\n/**\n * Empty icon data, rendered when icon is not available\n */\nconst emptyIcon = {\n ...defaultIconProps,\n body: '',\n};\n/**\n * Component\n */\nconst Icon = defineComponent((props, { emit }) => {\n const loader = ref(null);\n function abortLoading() {\n if (loader.value) {\n loader.value.abort?.();\n loader.value = null;\n }\n }\n // Render state\n const rendering = ref(!!props.ssr);\n const lastRenderedIconName = ref('');\n const iconData = shallowRef(null);\n // Update icon data\n function getIcon() {\n const icon = props.icon;\n // Icon is an object\n if (typeof icon === 'object' &&\n icon !== null &&\n typeof icon.body === 'string') {\n lastRenderedIconName.value = '';\n return {\n data: icon,\n };\n }\n // Check for valid icon name\n let iconName;\n if (typeof icon !== 'string' ||\n (iconName = stringToIcon(icon, false, true)) === null) {\n return null;\n }\n // Load icon\n let data = getIconData(iconName);\n if (!data) {\n // Icon data is not available\n const oldState = loader.value;\n if (!oldState || oldState.name !== icon) {\n // Icon name does not match old loader state\n if (data === null) {\n // Failed to load\n loader.value = {\n name: icon,\n };\n }\n else {\n loader.value = {\n name: icon,\n abort: loadIcons([iconName], updateIconData),\n };\n }\n }\n return null;\n }\n // Icon data is available\n abortLoading();\n if (lastRenderedIconName.value !== icon) {\n lastRenderedIconName.value = icon;\n // Emit on next tick because render will be called on next tick\n nextTick(() => {\n emit('load', icon);\n });\n }\n // Customise icon\n const customise = props.customise;\n if (customise) {\n // Clone data and customise it\n data = Object.assign({}, data);\n const customised = customise(data.body, iconName.name, iconName.prefix, iconName.provider);\n if (typeof customised === 'string') {\n data.body = customised;\n }\n }\n // Add classes\n const classes = ['iconify'];\n if (iconName.prefix !== '') {\n classes.push('iconify--' + iconName.prefix);\n }\n if (iconName.provider !== '') {\n classes.push('iconify--' + iconName.provider);\n }\n return { data, classes };\n }\n function updateIconData() {\n const icon = getIcon();\n if (!icon) {\n iconData.value = null;\n }\n else if (icon.data !== iconData.value?.data) {\n iconData.value = icon;\n }\n }\n // Set icon data\n if (rendering.value) {\n updateIconData();\n }\n else {\n onMounted(() => {\n rendering.value = true;\n updateIconData();\n });\n }\n watch(() => props.icon, updateIconData);\n // Abort loading on unmount\n onUnmounted(abortLoading);\n // Render function\n return () => {\n // Get icon data\n const icon = iconData.value;\n if (!icon) {\n // Icon is not available\n return render(emptyIcon, props);\n }\n // Add classes\n let newProps = props;\n if (icon.classes) {\n newProps = {\n ...props,\n class: icon.classes.join(' '),\n };\n }\n // Render icon\n return render({\n ...defaultIconProps,\n ...icon.data,\n }, newProps);\n };\n}, {\n props: [\n // Icon and render mode\n 'icon',\n 'mode',\n 'ssr',\n // Layout and style\n 'width',\n 'height',\n 'style',\n 'color',\n 'inline',\n // Transformations\n 'rotate',\n 'hFlip',\n 'horizontalFlip',\n 'vFlip',\n 'verticalFlip',\n 'flip',\n // Misc\n 'id',\n 'ariaHidden',\n 'customise',\n 'title',\n ],\n emits: ['load'],\n});\n/**\n * Internal API\n */\nconst _api = {\n getAPIConfig,\n setAPIModule,\n sendAPIQuery,\n setFetch,\n getFetch,\n listAPIProviders,\n};\n\nexport { Icon, _api, addAPIProvider, addCollection, addIcon, iconToSVG as buildIcon, calculateSize, getIcon, iconLoaded, listIcons, loadIcon, loadIcons, replaceIDs, setCustomIconLoader, setCustomIconsLoader };\n","import { FileType } from '../types';\n\n/**\n * 文件图标映射(基于 material-icon-theme.json)\n *\n * 原理:\n * 1. KNOWN_TYPES:从 material-icon-theme.json 提取的所有图标名\n * 2. EXT_MAP:扩展名 → 图标名\n * 3. SPECIAL_FILES:特殊文件名 → 图标名\n * 4. 逻辑:特殊文件名匹配 → 扩展名匹配 → 兜底\n */\n\n// 从 material-icon-theme.json 提取的所有图标名(~200 个常用)\nconst KNOWN_TYPES = new Set([\n '3d', 'actionscript', 'ada', 'adobe-illustrator', 'adobe-photoshop', 'android',\n 'angular', 'applescript', 'arduino', 'asciidoc', 'assembly', 'astro', 'audio',\n 'aurelia', 'babel', 'ballerina', 'bazel', 'biome', 'blender', 'bower', 'bun',\n 'c', 'cabal', 'caddy', 'cake', 'certificate', 'changelog', 'circleci', 'claude',\n 'clojure', 'cmake', 'cobol', 'coffee', 'command', 'conduct', 'contributing',\n 'controller', 'copilot', 'cpp', 'crystal', 'csharp', 'css', 'css-map', 'cucumber',\n 'cuda', 'cursor', 'cypress', 'd', 'dart', 'database', 'deno', 'dependabot', 'diff',\n 'django', 'docker', 'document', 'drawio', 'drizzle', 'editorconfig', 'ejs',\n 'elixir', 'elm', 'email', 'ember', 'epub', 'erlang', 'esbuild', 'eslint',\n 'excalidraw', 'exe', 'favicon', 'figma', 'firebase', 'flash', 'flow', 'font',\n 'forth', 'fortran', 'freemarker', 'fsharp', 'gamemaker', 'gatsby', 'gcp', 'gemfile',\n 'gemini', 'git', 'gitlab', 'gleam', 'go', 'go-mod', 'godot', 'gradle', 'graphql',\n 'groovy', 'grunt', 'gulp', 'h', 'haml', 'handlebars', 'hardhat', 'haskell', 'haxe',\n 'hcl', 'helm', 'hjson', 'hosts', 'hpp', 'html', 'http', 'husky', 'i18n', 'image',\n 'imba', 'ionic', 'jar', 'java', 'javaclass', 'javascript', 'javascript-map',\n 'jenkins', 'jest', 'jinja', 'jsconfig', 'json', 'julia', 'jupyter', 'just',\n 'karma', 'key', 'kotlin', 'kubernetes', 'laravel', 'lean', 'lefthook', 'lerna',\n 'less', 'lib', 'license', 'lighthouse', 'liquid', 'lisp', 'livescript', 'lock',\n 'log', 'lua', 'luau', 'makefile', 'markdown', 'markdownlint', 'matlab', 'maven',\n 'mdx', 'mercurial', 'mermaid', 'meson', 'minecraft', 'mjml', 'mocha', 'mojo',\n 'nest', 'netlify', 'next', 'nginx', 'nim', 'nix', 'nodejs', 'nodemon', 'npm',\n 'nuget', 'nunjucks', 'nuxt', 'nx', 'objective-c', 'objective-cpp', 'ocaml', 'odin',\n 'openapi', 'opentofu', 'pascal', 'pdf', 'perl', 'php', 'phpstan', 'phpunit',\n 'pipeline', 'playwright', 'pnpm', 'postcss', 'powerpoint', 'powershell', 'prettier',\n 'prisma', 'processing', 'prolog', 'proto', 'pug', 'puppet', 'purescript', 'python',\n 'pytorch', 'quasar', 'r', 'racket', 'razor', 'react', 'react-ts', 'readme', 'reason',\n 'remark', 'remix', 'renovate', 'replit', 'rescript', 'riot', 'roadmap', 'robot',\n 'robots', 'rollup', 'routing', 'rspec', 'rubocop', 'ruby', 'ruff', 'rust', 'salt',\n 'san', 'sas', 'sass', 'sbt', 'scala', 'scheme', 'search', 'sentry', 'sequelize',\n 'serverless', 'settings', 'shader', 'shellcheck', 'sketch', 'slim', 'slint',\n 'smarty', 'snakemake', 'snapcraft', 'snyk', 'solidity', 'spwn', 'stackblitz',\n 'stan', 'stencil', 'storybook', 'stryker', 'stylelint', 'stylus', 'sublime',\n 'subtitles', 'supabase', 'svelte', 'svg', 'svgo', 'swagger', 'swc', 'swift',\n 'tailwindcss', 'taskfile', 'tauri', 'tcl', 'teal', 'templ', 'template', 'terraform',\n 'test-js', 'test-jsx', 'test-ts', 'tex', 'todo', 'toml', 'travis', 'tree', 'tsconfig',\n 'tsdoc', 'turborepo', 'twig', 'typescript', 'typescript-def', 'unity', 'unocss',\n 'vagrant', 'vanilla-extract', 'vercel', 'verilog', 'video', 'vim', 'vite', 'vitest',\n 'vlang', 'vscode', 'vue', 'vue-config', 'wakatime', 'wallaby', 'webassembly',\n 'webhint', 'webpack', 'windicss', 'word', 'wrangler', 'wxt', 'xaml', 'xmake',\n 'xml', 'yaml', 'yarn', 'zig', 'zip',\n]);\n\n// 扩展名 → 图标名\nconst EXT_MAP: Record<string, string> = {\n // JavaScript/TypeScript\n 'js': 'javascript', 'mjs': 'javascript', 'cjs': 'javascript',\n 'jsx': 'react',\n 'ts': 'typescript', 'mts': 'typescript', 'cts': 'typescript',\n 'tsx': 'react-ts',\n // 前端框架\n 'vue': 'vue',\n 'svelte': 'svelte',\n 'astro': 'astro',\n // 后端语言\n 'py': 'python', 'pyw': 'python', 'pyi': 'python', 'pyc': 'python',\n 'java': 'java', 'class': 'javaclass', 'jar': 'jar',\n 'c': 'c', 'h': 'h',\n 'cpp': 'cpp', 'cc': 'cpp', 'cxx': 'cpp', 'hpp': 'hpp', 'hh': 'hpp', 'hxx': 'hpp',\n 'cs': 'csharp', 'csx': 'csharp',\n 'go': 'go',\n 'rs': 'rust',\n 'php': 'php', 'phtml': 'php',\n 'rb': 'ruby', 'rake': 'ruby',\n 'swift': 'swift',\n 'kt': 'kotlin', 'kts': 'kotlin',\n 'scala': 'scala',\n 'dart': 'dart',\n 'lua': 'lua', 'luau': 'luau',\n 'r': 'r', 'rdata': 'r', 'rds': 'r',\n 'pl': 'perl', 'pm': 'perl',\n 'sh': 'command', 'bash': 'command', 'zsh': 'command', 'fish': 'command',\n 'ps1': 'powershell', 'psm1': 'powershell', 'psd1': 'powershell',\n 'bat': 'command', 'cmd': 'command',\n // 样式\n 'css': 'css',\n 'scss': 'sass', 'sass': 'sass',\n 'less': 'less',\n 'styl': 'stylus',\n // 标记/配置\n 'html': 'html', 'htm': 'html', 'xhtml': 'html',\n 'xml': 'xml', 'xsl': 'xml', 'xslt': 'xml',\n 'json': 'json', 'jsonc': 'json', 'json5': 'json',\n 'yaml': 'yaml', 'yml': 'yaml',\n 'toml': 'toml',\n 'ini': 'settings',\n 'conf': 'settings', 'config': 'settings',\n // 文档\n 'md': 'markdown', 'markdown': 'markdown', 'mdx': 'mdx',\n 'txt': 'document',\n 'pdf': 'pdf',\n 'doc': 'word', 'docx': 'word', 'dot': 'word', 'dotx': 'word', 'odt': 'word',\n 'xls': 'table', 'xlsx': 'table', 'xlsm': 'table', 'ods': 'table', 'csv': 'table',\n 'ppt': 'powerpoint', 'pptx': 'powerpoint', 'odp': 'powerpoint',\n // 图片\n 'jpg': 'image', 'jpeg': 'image', 'png': 'image', 'gif': 'image', 'webp': 'image',\n 'ico': 'image', 'bmp': 'image', 'tiff': 'image', 'tif': 'image', 'heic': 'image', 'heif': 'image',\n 'svg': 'svg',\n 'psd': 'adobe-photoshop',\n 'ai': 'adobe-illustrator',\n 'sketch': 'sketch',\n 'fig': 'figma', 'figma': 'figma',\n // 视频/音频\n 'mp4': 'video', 'mov': 'video', 'avi': 'video', 'mkv': 'video', 'webm': 'video',\n 'flv': 'video', 'wmv': 'video', 'm4v': 'video', '3gp': 'video', 'mpeg': 'video', 'mpg': 'video',\n 'mp3': 'audio', 'wav': 'audio', 'flac': 'audio', 'aac': 'audio', 'ogg': 'audio',\n 'wma': 'audio', 'm4a': 'audio', 'aiff': 'audio',\n // 压缩\n 'zip': 'zip', 'rar': 'zip', '7z': 'zip', 'tar': 'zip', 'gz': 'zip', 'bz2': 'zip',\n 'xz': 'zip', 'tgz': 'zip', 'tbz2': 'zip',\n // 数据库\n 'sql': 'database',\n 'db': 'database', 'sqlite': 'database', 'sqlite3': 'database',\n 'prisma': 'prisma',\n // 其他\n 'log': 'log',\n 'lock': 'lock',\n 'env': 'settings',\n 'graphql': 'graphql', 'gql': 'graphql',\n 'proto': 'proto',\n 'wasm': 'webassembly',\n 'zig': 'zig',\n 'nim': 'nim',\n 'nix': 'nix',\n 'hcl': 'hcl', 'tf': 'terraform',\n 'sol': 'solidity',\n 'ex': 'elixir', 'exs': 'elixir',\n 'erl': 'erlang', 'hrl': 'erlang',\n 'hs': 'haskell', 'lhs': 'haskell',\n 'ml': 'ocaml', 'mli': 'ocaml',\n 'clj': 'clojure', 'cljs': 'clojure', 'cljc': 'clojure',\n 'lisp': 'lisp', 'lsp': 'lisp', 'el': 'lisp',\n 'vim': 'vim',\n 'dockerfile': 'docker',\n};\n\n// 特殊文件名 → 图标名\nconst SPECIAL_FILES: Record<string, string> = {\n // Git\n '.gitignore': 'git', '.gitattributes': 'git', '.gitmodules': 'git', '.gitkeep': 'git',\n // 环境\n '.env': 'settings', '.env.local': 'settings', '.env.development': 'settings',\n '.env.production': 'settings', '.env.test': 'settings', '.env.example': 'settings',\n // Node/包管理\n 'package.json': 'nodejs', 'package-lock.json': 'npm',\n 'yarn.lock': 'yarn', '.yarnrc': 'yarn', '.yarnrc.yml': 'yarn',\n 'pnpm-lock.yaml': 'pnpm', '.pnpmfile.cjs': 'pnpm',\n 'bun.lockb': 'bun', 'bunfig.toml': 'bun',\n // Python\n 'requirements.txt': 'python', 'pipfile': 'python', 'pipfile.lock': 'python',\n 'pyproject.toml': 'python', 'poetry.lock': 'python', 'setup.py': 'python',\n // Rust\n 'cargo.toml': 'rust', 'cargo.lock': 'rust',\n // Go\n 'go.mod': 'go-mod', 'go.sum': 'go-mod', 'go.work': 'go-mod',\n // PHP\n 'composer.json': 'php', 'composer.lock': 'php',\n // Ruby\n 'gemfile': 'gemfile', 'gemfile.lock': 'gemfile', 'rakefile': 'ruby',\n // Docker\n 'dockerfile': 'docker', 'docker-compose.yml': 'docker', 'docker-compose.yaml': 'docker',\n '.dockerignore': 'docker',\n // 构建工具\n 'makefile': 'makefile', 'gnumakefile': 'makefile',\n 'cmakelists.txt': 'cmake',\n 'build.gradle': 'gradle', 'build.gradle.kts': 'gradle', 'settings.gradle': 'gradle',\n 'pom.xml': 'maven',\n // 配置\n 'tsconfig.json': 'tsconfig', 'jsconfig.json': 'jsconfig',\n '.prettierrc': 'prettier', '.prettierrc.json': 'prettier', '.prettierrc.js': 'prettier',\n '.prettierignore': 'prettier', 'prettier.config.js': 'prettier',\n '.eslintrc': 'eslint', '.eslintrc.json': 'eslint', '.eslintrc.js': 'eslint',\n '.eslintignore': 'eslint', 'eslint.config.js': 'eslint', 'eslint.config.mjs': 'eslint',\n '.editorconfig': 'editorconfig',\n 'vite.config.ts': 'vite', 'vite.config.js': 'vite',\n 'webpack.config.js': 'webpack', 'webpack.config.ts': 'webpack',\n 'rollup.config.js': 'rollup', 'rollup.config.ts': 'rollup',\n 'esbuild.config.js': 'esbuild',\n 'tailwind.config.js': 'tailwindcss', 'tailwind.config.ts': 'tailwindcss',\n 'postcss.config.js': 'postcss', 'postcss.config.cjs': 'postcss',\n 'babel.config.js': 'babel', '.babelrc': 'babel',\n 'jest.config.js': 'jest', 'jest.config.ts': 'jest',\n 'vitest.config.ts': 'vitest', 'vitest.config.js': 'vitest',\n 'playwright.config.ts': 'playwright', 'playwright.config.js': 'playwright',\n 'cypress.config.ts': 'cypress', 'cypress.config.js': 'cypress',\n '.swcrc': 'swc', 'swc.config.js': 'swc',\n 'turbo.json': 'turborepo',\n 'nx.json': 'nx',\n 'biome.json': 'biome',\n '.nvmrc': 'nodejs', '.node-version': 'nodejs',\n // 框架配置\n 'nuxt.config.ts': 'nuxt', 'nuxt.config.js': 'nuxt',\n 'next.config.js': 'next', 'next.config.mjs': 'next', 'next.config.ts': 'next',\n 'svelte.config.js': 'svelte',\n 'astro.config.mjs': 'astro', 'astro.config.ts': 'astro',\n 'vue.config.js': 'vue-config',\n 'angular.json': 'angular',\n 'nest-cli.json': 'nest',\n 'tauri.conf.json': 'tauri',\n // CI/CD\n '.travis.yml': 'travis',\n '.gitlab-ci.yml': 'gitlab',\n 'vercel.json': 'vercel',\n 'netlify.toml': 'netlify',\n // 其他\n 'license': 'license', 'license.md': 'license', 'license.txt': 'license',\n 'readme': 'readme', 'readme.md': 'readme', 'readme.txt': 'readme',\n 'changelog': 'changelog', 'changelog.md': 'changelog',\n '.npmrc': 'npm', '.npmignore': 'npm',\n 'robots.txt': 'robots',\n '.htaccess': 'nginx',\n 'vagrantfile': 'vagrant',\n '.stylelintrc': 'stylelint', '.stylelintrc.json': 'stylelint',\n 'nodemon.json': 'nodemon',\n '.huskyrc': 'husky',\n 'renovate.json': 'renovate',\n '.snyk': 'snyk',\n 'deno.json': 'deno', 'deno.jsonc': 'deno',\n};\n\n/**\n * 根据文件名获取 material-icon-theme 图标名称\n */\nexport function getFileTypeIcon(fileName: string, fallbackType?: FileType): string {\n const lowerName = fileName.toLowerCase();\n\n // 1. 特殊文件名匹配\n if (SPECIAL_FILES[lowerName]) {\n const type = SPECIAL_FILES[lowerName];\n if (KNOWN_TYPES.has(type)) {\n return `material-icon-theme:${type}`;\n }\n }\n\n // 2. Dockerfile 特殊处理\n if (lowerName === 'dockerfile' || lowerName.startsWith('dockerfile.')) {\n return 'material-icon-theme:docker';\n }\n\n // 3. .env 变体处理\n if (lowerName === '.env' || lowerName.startsWith('.env.')) {\n return 'material-icon-theme:settings';\n }\n\n // 4. 提取扩展名并匹配\n const lastDotIndex = fileName.lastIndexOf('.');\n const ext = lastDotIndex > 0 ? fileName.substring(lastDotIndex + 1).toLowerCase() : '';\n\n // 处理复合扩展名\n if (ext === 'ts' || ext === 'js') {\n const baseName = fileName.substring(0, lastDotIndex).toLowerCase();\n if (baseName.endsWith('.d')) {\n return 'material-icon-theme:typescript-def';\n }\n if (baseName.endsWith('.test') || baseName.endsWith('.spec')) {\n return ext === 'ts' ? 'material-icon-theme:test-ts' : 'material-icon-theme:test-js';\n }\n }\n if (ext === 'jsx' || ext === 'tsx') {\n const baseName = fileName.substring(0, lastDotIndex).toLowerCase();\n if (baseName.endsWith('.test') || baseName.endsWith('.spec')) {\n return ext === 'tsx' ? 'material-icon-theme:test-ts' : 'material-icon-theme:test-jsx';\n }\n }\n\n if (ext && EXT_MAP[ext]) {\n const type = EXT_MAP[ext];\n if (KNOWN_TYPES.has(type)) {\n return `material-icon-theme:${type}`;\n }\n }\n\n // 5. 根据 fallbackType 返回兜底图标\n if (fallbackType) {\n return getFallbackIcon(fallbackType);\n }\n\n // 6. 最终兜底\n return 'material-icon-theme:document';\n}\n\nfunction getFallbackIcon(type: FileType): string {\n switch (type) {\n case FileType.IMAGE: return 'material-icon-theme:image';\n case FileType.VIDEO: return 'material-icon-theme:video';\n case FileType.MUSIC: return 'material-icon-theme:audio';\n case FileType.CODE: return 'material-icon-theme:javascript';\n case FileType.TEXT: return 'material-icon-theme:document';\n case FileType.DOCUMENT: return 'material-icon-theme:word';\n case FileType.PDF: return 'material-icon-theme:pdf';\n case FileType.ARCHIVE: return 'material-icon-theme:zip';\n case FileType.APPLICATION: return 'material-icon-theme:exe';\n default: return 'material-icon-theme:document';\n }\n}\n\n","/**\n * 文件夹图标映射(基于 material-icon-theme.json)\n *\n * 原理:\n * 1. KNOWN_TYPES:从 material-icon-theme.json 提取的所有 folder-{type} 类型\n * 2. ALIASES:常见变体映射到标准名\n * 3. 逻辑:目录名小写 → 查别名 → 查白名单 → 命中则返回 material-icon-theme:folder-{type}\n */\n\n// 从 material-icon-theme.json 提取的所有 folder-* 类型(去掉 folder- 前缀和 -open 后缀)\nconst KNOWN_TYPES = new Set([\n 'admin', 'android', 'angular', 'animation', 'ansible', 'api', 'apollo', 'app',\n 'archive', 'astro', 'atom', 'attachment', 'audio', 'aurelia', 'aws',\n 'azure-pipelines', 'backup', 'base', 'batch', 'benchmark', 'bibliography',\n 'bicep', 'blender', 'bloc', 'bower', 'buildkite', 'cart', 'changesets', 'ci',\n 'circleci', 'class', 'claude', 'client', 'cline', 'cloud-functions', 'cloudflare',\n 'cluster', 'cobol', 'command', 'components', 'config', 'connection', 'console',\n 'constant', 'container', 'content', 'context', 'contract', 'controller', 'core',\n 'coverage', 'css', 'cue', 'cursor', 'custom', 'cypress', 'dal', 'dart', 'database',\n 'debug', 'decorators', 'delta', 'desktop', 'directive', 'dist', 'docker', 'docs',\n 'download', 'drizzle', 'dump', 'element', 'enum', 'environment', 'error', 'eslint',\n 'event', 'examples', 'expo', 'export', 'fastlane', 'favicon', 'features', 'filter',\n 'firebase', 'firestore', 'flow', 'flutter', 'font', 'forgejo', 'functions',\n 'gamemaker', 'generator', 'gh-workflows', 'git', 'gitea', 'github', 'gitlab',\n 'global', 'godot', 'gradle', 'graphql', 'guard', 'gulp', 'helm', 'helper', 'home',\n 'hook', 'husky', 'i18n', 'images', 'import', 'include', 'input', 'intellij',\n 'interceptor', 'interface', 'ios', 'java', 'javascript', 'jinja', 'job', 'json',\n 'jupyter', 'keys', 'kubernetes', 'kusto', 'layout', 'lefthook', 'less', 'lib',\n 'license', 'link', 'linux', 'liquibase', 'log', 'lottie', 'lua', 'luau', 'macos',\n 'mail', 'mappings', 'markdown', 'mercurial', 'messages', 'meta', 'metro',\n 'middleware', 'migrations', 'mjml', 'mobile', 'mock', 'mojo', 'molecule', 'moon',\n 'netlify', 'next', 'ngrx-store', 'node', 'nuxt', 'obsidian', 'organism', 'other',\n 'packages', 'pdf', 'pdm', 'php', 'phpmailer', 'pipe', 'plastic', 'plugin', 'policy',\n 'powershell', 'prisma', 'private', 'project', 'prompts', 'proto', 'public', 'python',\n 'pytorch', 'quasar', 'queue', 'react-components', 'redux-reducer', 'repository',\n 'resolver', 'resource', 'review', 'robot', 'routes', 'rules', 'rust', 'salt',\n 'sandbox', 'sass', 'scala', 'scons', 'scripts', 'secure', 'seeders', 'server',\n 'serverless', 'shader', 'shared', 'simulations', 'snapcraft', 'snippet', 'src',\n 'src-tauri', 'stack', 'stencil', 'store', 'storybook', 'stylus', 'sublime',\n 'supabase', 'svelte', 'svg', 'syntax', 'target', 'taskfile', 'tasks', 'television',\n 'temp', 'template', 'terraform', 'test', 'theme', 'toc', 'tools', 'trash', 'trigger',\n 'turborepo', 'typescript', 'ui', 'unity', 'update', 'upload', 'utils', 'vercel',\n 'verdaccio', 'video', 'views', 'vm', 'vscode', 'vue', 'vue-directives', 'vuepress',\n 'vuex-store', 'wakatime', 'webpack', 'windows', 'wordpress', 'yarn', 'zeabur',\n]);\n\n// 别名映射\nconst ALIASES: Record<string, string> = {\n // 复数/变体\n 'tests': 'test', '__tests__': 'test', '__test__': 'test', 'spec': 'test', 'specs': 'test',\n 'script': 'scripts',\n 'configs': 'config', 'configuration': 'config', 'configurations': 'config',\n 'route': 'routes', 'routing': 'routes',\n 'stories': 'storybook', 'story': 'storybook',\n 'templates': 'template',\n 'themes': 'theme',\n 'videos': 'video',\n 'imgs': 'images', 'img': 'images', 'image': 'images',\n 'fonts': 'font',\n 'styles': 'css', 'style': 'css', 'styling': 'css', 'stylesheets': 'css',\n 'view': 'views', 'pages': 'views', 'page': 'views',\n 'layouts': 'layout',\n 'models': 'database', 'model': 'database',\n 'modules': 'lib', 'module': 'lib', 'mods': 'lib',\n 'plugins': 'plugin', 'addons': 'plugin', 'extensions': 'plugin',\n 'middlewares': 'middleware',\n 'helpers': 'helper', 'utilities': 'utils', 'util': 'utils',\n 'tool': 'tools', 'tooling': 'tools',\n 'resources': 'resource', 'res': 'resource', 'assets': 'resource', 'asset': 'resource',\n 'hooks': 'hook', 'composables': 'hook',\n 'mocks': 'mock', '__mocks__': 'mock', 'fixtures': 'mock', '__fixtures__': 'mock',\n 'logs': 'log',\n 'uploads': 'upload',\n 'function': 'functions', 'func': 'functions', 'fns': 'functions',\n 'services': 'server', 'service': 'server',\n 'component': 'components', 'comp': 'components', 'comps': 'components',\n 'controllers': 'controller',\n // 常见变体\n 'source': 'src', 'sources': 'src',\n 'distribution': 'dist', 'build': 'dist', 'builds': 'dist', 'out': 'dist', 'output': 'dist',\n 'documentation': 'docs', 'doc': 'docs', 'document': 'docs', 'documents': 'docs',\n 'static': 'public', 'statics': 'public', 'publics': 'public',\n 'libs': 'lib', 'library': 'lib', 'vendor': 'lib', 'vendors': 'lib',\n 'bin': 'scripts', 'binaries': 'scripts',\n 'tmp': 'temp', 'temporary': 'temp', 'cache': 'temp', 'caches': 'temp', '.cache': 'temp', '.turbo': 'temp',\n 'types': 'typescript', '@types': 'typescript', 'typings': 'typescript', 'dts': 'typescript',\n 'locales': 'i18n', 'locale': 'i18n', 'lang': 'i18n', 'languages': 'i18n', 'translations': 'i18n',\n 'db': 'database', 'databases': 'database', 'sql': 'database', 'queries': 'database',\n 'migration': 'migrations', 'seeds': 'seeders', 'seed': 'seeders',\n // 技术栈\n '.vscode': 'vscode',\n '.github': 'github',\n '.gitlab': 'gitlab',\n '.circleci': 'circleci',\n '.husky': 'husky',\n '.docker': 'docker',\n 'node_modules': 'node',\n 'scss': 'sass',\n 'renderer': 'client', 'frontend': 'client', 'web': 'client', 'webapp': 'client', 'website': 'client',\n 'backend': 'server', 'main': 'server',\n 'preload': 'scripts',\n '.idea': 'intellij',\n '.git': 'git',\n 'k8s': 'kubernetes', 'kube': 'kubernetes',\n 'mongo': 'database', 'mongodb': 'database', 'mysql': 'database', 'postgres': 'database',\n 'api': 'api', 'apis': 'api',\n 'interfaces': 'interface',\n 'notebook': 'jupyter', 'notebooks': 'jupyter', 'ipynb': 'jupyter',\n 'notification': 'messages', 'notifications': 'messages',\n 'env': 'environment', 'envs': 'environment',\n 'redux': 'redux-reducer', 'store': 'store', 'stores': 'store',\n 'electron': 'desktop',\n 'tauri': 'src-tauri',\n};\n\n/**\n * 根据文件夹名称获取对应的 material-icon-theme 图标名\n * @returns 图标名 或 undefined(让上层兜底默认图标)\n */\nexport function getFolderTypeIcon(folderName: string): string | undefined {\n const name = (folderName || '').trim();\n if (!name) return undefined;\n\n const lower = name.replace(/[\\\\/]+$/, '').toLowerCase();\n const standardName = ALIASES[lower] ?? lower;\n\n if (KNOWN_TYPES.has(standardName)) {\n return `material-icon-theme:folder-${standardName}`;\n }\n\n return undefined;\n}\n","<template>\n <div :class=\"className\">\n <Icon :icon=\"iconName\" :width=\"size\" :height=\"size\" :class=\"iconClass\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { Icon } from '@iconify/vue';\nimport { FileType } from '../types';\nimport { getFileTypeIcon } from '../utils/fileTypeIcon';\nimport { getFolderTypeIcon } from '../utils/folderTypeIcon';\n\ninterface Props {\n type: FileType;\n name?: string;\n className?: string;\n size?: number;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n className: '',\n size: 24\n});\n\nconst iconName = computed(() => {\n if (props.type === FileType.FOLDER) {\n // 文件夹:先查特定类型图标,否则用默认 folder\n const folderIcon = props.name ? getFolderTypeIcon(props.name) : undefined;\n return folderIcon ?? 'flat-color-icons:folder';\n }\n \n // 如果有文件名,使用 material-icon-theme 图标映射(传递 type 作为兜底)\n if (props.name) {\n return getFileTypeIcon(props.name, props.type);\n }\n \n // 回退逻辑(没有文件名时)\n switch (props.type) {\n case FileType.IMAGE:\n return 'material-icon-theme:image';\n case FileType.TEXT:\n return 'material-icon-theme:document';\n case FileType.CODE:\n return 'material-icon-theme:javascript';\n case FileType.MUSIC:\n return 'material-icon-theme:audio';\n case FileType.VIDEO:\n return 'material-icon-theme:video';\n case FileType.PDF:\n return 'material-icon-theme:pdf';\n case FileType.DOCUMENT:\n return 'material-icon-theme:word';\n case FileType.APPLICATION:\n return 'material-icon-theme:exe';\n case FileType.ARCHIVE:\n return 'material-icon-theme:zip';\n default:\n return 'material-icon-theme:document';\n }\n});\n\nconst iconClass = computed(() => {\n const base = 'file-icon';\n switch (props.type) {\n case FileType.FOLDER:\n return `${base} file-icon--folder`;\n case FileType.IMAGE:\n return `${base} file-icon--image`;\n case FileType.TEXT:\n return `${base} file-icon--text`;\n case FileType.CODE:\n return `${base} file-icon--code`;\n case FileType.MUSIC:\n return `${base} file-icon--music`;\n case FileType.VIDEO:\n return `${base} file-icon--video`;\n case FileType.PDF:\n case FileType.DOCUMENT:\n return `${base} file-icon--pdf`;\n case FileType.APPLICATION:\n return `${base} file-icon--application`;\n case FileType.ARCHIVE:\n return `${base} file-icon--archive`;\n default:\n return `${base} file-icon--default`;\n }\n});\n</script>\n\n<style scoped>\n.file-icon--folder {\n color: rgb(96, 165, 250);\n fill: rgb(96, 165, 250);\n}\n\n.file-icon--image {\n color: rgb(168, 85, 247);\n}\n\n.file-icon--text {\n color: rgb(107, 114, 128);\n}\n\n.file-icon--code {\n color: rgb(34, 197, 94);\n}\n\n.file-icon--music {\n color: rgb(248, 113, 113);\n}\n\n.file-icon--video {\n color: rgb(37, 99, 235);\n}\n\n.file-icon--pdf {\n color: rgb(220, 38, 38);\n}\n\n.file-icon--application {\n color: rgb(139, 92, 246);\n}\n\n.file-icon--archive {\n color: rgb(234, 179, 8);\n}\n\n.file-icon--default {\n color: rgb(156, 163, 175);\n}\n</style>\n","<template>\n <div class=\"file-grid\" @contextmenu.prevent=\"handleEmptyContextMenu\">\n <div\n v-for=\"item in items\"\n :key=\"item.id\"\n :draggable=\"editingId !== item.id\"\n @dragstart=\"$emit('dragStart', $event, item)\"\n @dragover.prevent=\"$emit('dragOver', $event, item)\"\n @dragleave=\"$emit('dragLeave', $event)\"\n @drop.prevent=\"$emit('drop', $event, item)\"\n @click.stop=\"$emit('select', item, $event)\"\n @dblclick.stop=\"$emit('open', item)\"\n @contextmenu.prevent.stop=\"$emit('contextMenu', item, $event)\"\n :class=\"[\n 'file-grid-item',\n selectedIds.has(item.id) && editingId !== item.id\n ? 'file-grid-item--selected' \n : dragOverId === item.id \n ? 'file-grid-item--drag-over' \n : 'file-grid-item--normal'\n ]\"\n >\n <div class=\"file-grid-item-icon\">\n <!-- 应用程序图标 -->\n <img \n v-if=\"item.type === FileType.APPLICATION && getAppIconUrl?.(item)\"\n :src=\"getAppIconUrl(item)\" \n :alt=\"item.name\" \n :class=\"[\n 'file-grid-item-thumbnail file-grid-item-thumbnail--application',\n selectedIds.has(item.id) && editingId !== item.id ? 'file-grid-item-thumbnail--selected' : ''\n ]\"\n />\n <!-- 图片/视频缩略图 -->\n <template v-else-if=\"hasThumbnail(item)\">\n <!-- 视频类型必须有缩略图,如果没有缩略图说明不应该被识别为视频,按普通文件处理 -->\n <div v-if=\"item.type === FileType.VIDEO && item.thumbnailUrl\" class=\"file-grid-item-thumbnail file-grid-item-thumbnail--video\">\n <img \n :src=\"item.thumbnailUrl\"\n class=\"file-grid-item-thumbnail\"\n :alt=\"item.name\"\n @error=\"$emit('thumbnailError', item, $event)\"\n />\n <div class=\"file-grid-item-video-play\">\n <div class=\"file-grid-item-video-play-icon\" />\n </div>\n </div>\n <!-- 图片:永远只显示缩略图,不显示原始 URL -->\n <img \n v-else-if=\"item.thumbnailUrl\"\n :src=\"item.thumbnailUrl\" \n :alt=\"item.name\" \n class=\"file-grid-item-thumbnail\"\n @error=\"$emit('thumbnailError', item, $event)\"\n />\n </template>\n <FileIcon \n v-else\n :type=\"item.type\" \n :name=\"item.name\"\n :size=\"48\" \n />\n </div>\n \n <div class=\"file-grid-item-name-wrapper\">\n <input\n v-if=\"editingId === item.id\"\n type=\"text\"\n class=\"file-grid-item-rename-input\"\n :value=\"item.name\"\n @blur=\"handleRename(item, $event)\"\n @keydown.enter=\"handleEnterKey\"\n @keydown.escape=\"handleEscapeKey\"\n ref=\"renameInput\"\n autofocus\n />\n <span \n v-else\n @click.stop=\"$emit('nameClick', item, $event)\"\n :class=\"[\n 'file-grid-item-name',\n selectedIds.has(item.id) ? 'file-grid-item-name--selected' : ''\n ]\"\n :title=\"item.name\"\n >\n <template v-if=\"getFileNameParts(item).ext\">\n <span class=\"file-grid-item-name-base\">{{ getFileNameParts(item).baseName }}</span>\n <span class=\"file-grid-item-name-ext\">{{ getFileNameParts(item).ext }}</span>\n </template>\n <template v-else>{{ item.name }}</template>\n </span>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport type { FileItem } from '../types';\nimport { FileType } from '../types';\nimport FileIcon from './FileIcon.vue';\n\n/**\n * 分离文件名和扩展名\n */\nfunction splitFileName(name: string, isFolder: boolean): { baseName: string; ext: string } {\n if (isFolder) {\n return { baseName: name, ext: '' };\n }\n const lastDot = name.lastIndexOf('.');\n if (lastDot <= 0) {\n return { baseName: name, ext: '' };\n }\n return {\n baseName: name.substring(0, lastDot),\n ext: name.substring(lastDot),\n };\n}\n\n/**\n * 获取文件名各部分(带缓存)\n */\nconst fileNameCache = new Map<string, { baseName: string; ext: string }>();\nfunction getFileNameParts(item: FileItem) {\n const key = `${item.id}-${item.name}`;\n if (!fileNameCache.has(key)) {\n fileNameCache.set(key, splitFileName(item.name, item.type === FileType.FOLDER));\n }\n return fileNameCache.get(key)!;\n}\n\ninterface Props {\n items: FileItem[];\n selectedIds: Set<string>;\n editingId?: string | null;\n dragOverId?: string | null;\n /** 获取应用程序图标 URL 的函数 */\n getAppIconUrl?: (item: FileItem) => string | undefined;\n}\n\nconst props = defineProps<Props>();\n\nconst emit = defineEmits<{\n select: [item: FileItem, e: MouseEvent];\n open: [item: FileItem];\n contextMenu: [item: FileItem, e: MouseEvent];\n contextMenuEmpty: [e: MouseEvent];\n nameClick: [item: FileItem, e: MouseEvent];\n rename: [item: FileItem, newName: string];\n renameCancel: [item: FileItem];\n dragStart: [e: DragEvent, item: FileItem];\n dragOver: [e: DragEvent, item: FileItem];\n dragLeave: [e: DragEvent];\n drop: [e: DragEvent, item: FileItem];\n thumbnailError: [item: FileItem, e: Event];\n}>();\n\n/**\n * 空白处右键菜单\n */\nconst handleEmptyContextMenu = (e: MouseEvent) => {\n // 检查是否点击了文件项(文件项的 contextmenu 有 .stop,不会到这里)\n const target = e.target as HTMLElement;\n // 如果点击的不是文件项内部元素,则触发空白处菜单\n if (!target.closest('.file-grid-item')) {\n emit('contextMenuEmpty', e);\n }\n};\n\n/**\n * 判断是否有缩略图或应用程序图标\n */\nconst hasThumbnail = (item: FileItem): boolean => {\n // 应用程序图标\n if (item.type === FileType.APPLICATION && props.getAppIconUrl?.(item)) {\n return true;\n }\n // 图片:必须有缩略图才显示,永远不显示原始 URL\n if (item.type === FileType.IMAGE) {\n return !!item.thumbnailUrl;\n }\n // 视频:必须有缩略图才显示,如果没有缩略图说明不应该被识别为视频\n if (item.type === FileType.VIDEO) {\n return !!item.thumbnailUrl;\n }\n return false;\n};\n\n/**\n * 视频悬停播放\n */\nconst handleVideoHover = (e: Event, isHover: boolean) => {\n const video = e.target as HTMLVideoElement;\n if (isHover) {\n video.play().catch(() => {});\n } else {\n video.pause();\n video.currentTime = 0;\n }\n};\n\n/**\n * 处理重命名(blur 事件)\n */\nconst handleRename = (item: FileItem, e: Event) => {\n const input = e.target as HTMLInputElement;\n const newName = input.value.trim();\n if (newName && newName !== item.name) {\n emit('rename', item, newName);\n } else {\n emit('renameCancel', item);\n }\n};\n\n/**\n * Enter 键保存\n */\nconst handleEnterKey = (e: KeyboardEvent) => {\n (e.target as HTMLInputElement).blur();\n};\n\n/**\n * Escape 键取消\n */\nconst handleEscapeKey = (e: KeyboardEvent) => {\n const input = e.target as HTMLInputElement;\n // 恢复原始值,这样 blur 时会触发 renameCancel\n const item = props.items.find(i => i.id === props.editingId);\n if (item) {\n input.value = item.name;\n }\n input.blur();\n};\n</script>\n\n<style scoped>\n/**\n * FileGrid - 网格视图样式\n * 参考 macOS Finder 和 Windows Explorer 的设计\n */\n\n.file-grid {\n display: grid;\n /* macOS Finder 默认约 90-100px */\n grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));\n gap: 6px;\n padding: 12px;\n align-content: start;\n grid-auto-rows: min-content;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\n/* 网格项 - 更紧凑的布局 */\n.file-grid-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 4px;\n border-radius: 6px;\n cursor: pointer;\n border: 1px solid transparent;\n transition: background-color 120ms ease, border-color 120ms ease;\n position: relative;\n overflow: hidden;\n min-width: 0;\n width: 100%;\n}\n\n/* 拖拽时的鼠标样式 */\n.file-grid-item[draggable=\"true\"] {\n cursor: grab;\n}\n\n.file-grid-item:active {\n cursor: grabbing;\n}\n\n/* 悬停效果 - 类似 macOS */\n.file-grid-item--normal:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n/* 选中状态 - macOS 风格的蓝色高亮 */\n.file-grid-item--selected {\n background: rgba(0, 122, 255, 0.12);\n border-color: rgba(0, 122, 255, 0.2);\n}\n\n.file-grid-item--selected:hover {\n background: rgba(0, 122, 255, 0.16);\n}\n\n/* 拖拽悬停 */\n.file-grid-item--drag-over {\n background: rgba(0, 122, 255, 0.2);\n border-color: rgba(0, 122, 255, 0.4);\n}\n\n/* 图标/缩略图容器 - 统一尺寸 */\n.file-grid-item-icon {\n position: relative;\n pointer-events: none;\n display: flex;\n align-items: center;\n justify-content: center;\n /* 统一 48x48 尺寸,更紧凑 */\n width: 48px;\n height: 48px;\n flex-shrink: 0;\n}\n\n/* 缩略图样式 - 统一尺寸和圆角 */\n/* 缩略图保持原图比例,使用 object-fit: cover 填充固定尺寸容器 */\n.file-grid-item-thumbnail {\n width: 48px;\n height: 48px;\n object-fit: cover;\n object-position: center;\n border-radius: 4px;\n /* 轻微阴影增加层次感 */\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08), 0 0 0 1px rgba(0, 0, 0, 0.04);\n background: #f5f5f5;\n /* 确保图片能作为加载占位符,平滑过渡到原图 */\n display: block;\n}\n\n/* 应用程序图标 - 无背景 */\n.file-grid-item-thumbnail--application {\n object-fit: contain;\n background: transparent;\n box-shadow: none;\n border-radius: 10px;\n}\n\n.file-grid-item-thumbnail--selected {\n box-shadow: 0 2px 6px rgba(0, 122, 255, 0.2), 0 0 0 2px rgba(0, 122, 255, 0.3);\n}\n\n/* 视频缩略图容器 */\n.file-grid-item-thumbnail--video {\n position: relative;\n border-radius: 4px;\n overflow: hidden;\n background: #000;\n width: 48px;\n height: 48px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* 视频缩略图内的图片 - 保持比例,填充容器 */\n.file-grid-item-thumbnail--video > img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n object-position: center;\n display: block;\n}\n\n/* 视频播放图标 */\n.file-grid-item-video-play {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n opacity: 0.9;\n transition: opacity 150ms;\n}\n\n.file-grid-item-thumbnail--video:hover .file-grid-item-video-play {\n opacity: 0;\n}\n\n.file-grid-item-video-play-icon {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.file-grid-item-video-play-icon::before {\n content: '';\n width: 0;\n height: 0;\n border-top: 4px solid transparent;\n border-left: 7px solid white;\n border-bottom: 4px solid transparent;\n margin-left: 2px;\n}\n\n/* 文件名容器 */\n.file-grid-item-name-wrapper {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n width: 100%;\n min-height: 0;\n}\n\n/* 文件名 - macOS 风格,最多2行,保留扩展名 */\n.file-grid-item-name {\n font-size: 12px;\n line-height: 1.3;\n text-align: center;\n padding: 2px;\n border-radius: 3px;\n user-select: none;\n cursor: default;\n transition: color 100ms;\n color: #1d1d1f;\n width: 100%;\n /* 使用 flexbox 布局,让扩展名始终显示 */\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-start;\n min-height: 0;\n}\n\n/* 文件名主体部分 - 可换行,最多1行 */\n.file-grid-item-name-base {\n display: -webkit-box;\n -webkit-line-clamp: 1;\n -webkit-box-orient: vertical;\n overflow: hidden;\n word-break: break-word;\n text-overflow: ellipsis;\n width: 100%;\n text-align: center;\n}\n\n/* 扩展名部分 - 始终显示,不换行 */\n.file-grid-item-name-ext {\n display: block;\n white-space: nowrap;\n flex-shrink: 0;\n text-align: center;\n}\n\n/* 选中后点击文件名可编辑 */\n.file-grid-item-name--selected {\n cursor: text;\n}\n\n/* 重命名输入框 */\n.file-grid-item-rename-input {\n width: 100%;\n font-size: 11px;\n line-height: 1.3;\n text-align: center;\n padding: 2px 4px;\n border: 1px solid #007aff;\n border-radius: 3px;\n outline: none;\n box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.2);\n background: white;\n cursor: text;\n}\n\n/* 深色模式支持 */\n@media (prefers-color-scheme: dark) {\n .file-grid-item--normal:hover {\n background: rgba(255, 255, 255, 0.06);\n }\n\n .file-grid-item--selected {\n background: rgba(10, 132, 255, 0.25);\n border-color: rgba(10, 132, 255, 0.3);\n }\n\n .file-grid-item--selected:hover {\n background: rgba(10, 132, 255, 0.3);\n }\n\n .file-grid-item--drag-over {\n background: rgba(10, 132, 255, 0.35);\n border-color: rgba(10, 132, 255, 0.5);\n }\n\n .file-grid-item-thumbnail {\n background: #2c2c2e;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(255, 255, 255, 0.05);\n }\n\n .file-grid-item-name {\n color: #f5f5f7;\n }\n\n .file-grid-item-rename-input {\n background: #1c1c1e;\n border-color: #0a84ff;\n color: #f5f5f7;\n }\n}\n</style>\n","<template>\n <span class=\"sort-indicator\">\n <Icon :icon=\"direction === 'asc' ? 'lucide:chevron-up' : 'lucide:chevron-down'\" :width=\"12\" :height=\"12\" />\n </span>\n</template>\n\n<script setup lang=\"ts\">\nimport { Icon } from '@iconify/vue';\n\ndefineProps<{\n direction: 'asc' | 'desc';\n}>();\n</script>\n\n<style scoped>\n.sort-indicator {\n margin-left: 4px;\n display: inline-flex;\n align-items: center;\n color: rgb(59, 130, 246);\n}\n</style>\n","<template>\n <div class=\"file-list\" @contextmenu.prevent=\"handleEmptyContextMenu\">\n <table class=\"file-list-table\">\n <thead class=\"file-list-header\">\n <tr>\n <th \n class=\"file-list-header-cell file-list-header-cell--name\"\n @click=\"$emit('sort', 'name')\"\n >\n 名称\n <SortIndicator v-if=\"sortConfig?.field === 'name'\" :direction=\"sortConfig.direction\" />\n </th>\n <th \n class=\"file-list-header-cell\"\n @click=\"$emit('sort', 'dateModified')\"\n >\n 修改日期\n <SortIndicator v-if=\"sortConfig?.field === 'dateModified'\" :direction=\"sortConfig.direction\" />\n </th>\n <th \n class=\"file-list-header-cell\"\n @click=\"$emit('sort', 'size')\"\n >\n 大小\n <SortIndicator v-if=\"sortConfig?.field === 'size'\" :direction=\"sortConfig.direction\" />\n </th>\n <th \n class=\"file-list-header-cell\"\n @click=\"$emit('sort', 'type')\"\n >\n 类型\n <SortIndicator v-if=\"sortConfig?.field === 'type'\" :direction=\"sortConfig.direction\" />\n </th>\n </tr>\n </thead>\n <tbody class=\"file-list-body\">\n <tr\n v-for=\"(item, index) in items\"\n :key=\"item.id\"\n :draggable=\"editingId !== item.id\"\n @dragstart=\"$emit('dragStart', $event, item)\"\n @dragover.prevent=\"$emit('dragOver', $event, item)\"\n @dragleave=\"$emit('dragLeave', $event)\"\n @drop.prevent=\"$emit('drop', $event, item)\"\n @click.stop=\"$emit('select', item, $event)\"\n @dblclick.stop=\"$emit('open', item)\"\n @contextmenu.prevent.stop=\"$emit('contextMenu', item, $event)\"\n :class=\"[\n 'file-list-row',\n selectedIds.has(item.id) \n ? 'file-list-row--selected' \n : dragOverId === item.id \n ? 'file-list-row--drag-over'\n : index % 2 === 0 \n ? 'file-list-row--even' \n : 'file-list-row--odd'\n ]\"\n >\n <td class=\"file-list-cell file-list-cell--name\">\n <FileIcon :type=\"item.type\" :name=\"item.name\" :size=\"16\" />\n <input\n v-if=\"editingId === item.id\"\n type=\"text\"\n class=\"file-list-rename-input\"\n :value=\"item.name\"\n @blur=\"handleRename(item, $event)\"\n @keydown.enter=\"handleEnterKey\"\n @keydown.escape=\"handleEscapeKey\"\n autofocus\n />\n <span \n v-else\n @click.stop=\"$emit('nameClick', item, $event)\"\n :class=\"[\n 'file-list-name',\n selectedIds.has(item.id) ? 'file-list-name--selected' : ''\n ]\"\n >\n {{ item.name }}\n </span>\n </td>\n <td :class=\"['file-list-cell', selectedIds.has(item.id) ? 'file-list-cell--selected' : '']\">\n {{ item.dateModified || '--' }}\n </td>\n <td :class=\"['file-list-cell file-list-cell--size', selectedIds.has(item.id) ? 'file-list-cell--selected' : '']\">\n {{ item.size || '--' }}\n </td>\n <td :class=\"['file-list-cell', selectedIds.has(item.id) ? 'file-list-cell--selected' : '']\">\n {{ getTypeLabel(item.type) }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { FileItem, SortConfig } from '../types';\nimport { FileType } from '../types';\nimport FileIcon from './FileIcon.vue';\nimport SortIndicator from './SortIndicator.vue';\n\ninterface Props {\n items: FileItem[];\n selectedIds: Set<string>;\n sortConfig?: SortConfig;\n editingId?: string | null;\n dragOverId?: string | null;\n}\n\nconst props = defineProps<Props>();\n\nconst emit = defineEmits<{\n select: [item: FileItem, e: MouseEvent];\n open: [item: FileItem];\n contextMenu: [item: FileItem, e: MouseEvent];\n contextMenuEmpty: [e: MouseEvent];\n nameClick: [item: FileItem, e: MouseEvent];\n rename: [item: FileItem, newName: string];\n renameCancel: [item: FileItem];\n sort: [field: string];\n dragStart: [e: DragEvent, item: FileItem];\n dragOver: [e: DragEvent, item: FileItem];\n dragLeave: [e: DragEvent];\n drop: [e: DragEvent, item: FileItem];\n}>();\n\n/**\n * 空白处右键菜单\n */\nconst handleEmptyContextMenu = (e: MouseEvent) => {\n // 只有点击容器本身(不是表格行)时才触发\n const target = e.target as HTMLElement;\n if (!target.closest('tr')) {\n emit('contextMenuEmpty', e);\n }\n};\n\n/**\n * 获取类型标签\n */\nconst getTypeLabel = (type: FileType): string => {\n const labels: Record<FileType, string> = {\n [FileType.FOLDER]: '文件夹',\n [FileType.FILE]: '文件',\n [FileType.IMAGE]: '图片',\n [FileType.VIDEO]: '视频',\n [FileType.MUSIC]: '音频',\n [FileType.DOCUMENT]: '文档',\n [FileType.CODE]: '代码',\n [FileType.TEXT]: '文本',\n [FileType.PDF]: 'PDF',\n [FileType.ARCHIVE]: '压缩包',\n [FileType.APPLICATION]: '应用程序',\n [FileType.UNKNOWN]: '未知'\n };\n return labels[type] || type;\n};\n\n/**\n * 处理重命名(blur 事件)\n */\nconst handleRename = (item: FileItem, e: Event) => {\n const input = e.target as HTMLInputElement;\n const newName = input.value.trim();\n if (newName && newName !== item.name) {\n emit('rename', item, newName);\n } else {\n emit('renameCancel', item);\n }\n};\n\n/**\n * Enter 键保存\n */\nconst handleEnterKey = (e: KeyboardEvent) => {\n (e.target as HTMLInputElement).blur();\n};\n\n/**\n * Escape 键取消\n */\nconst handleEscapeKey = (e: KeyboardEvent) => {\n const input = e.target as HTMLInputElement;\n // 恢复原始值,这样 blur 时会触发 renameCancel\n const item = props.items.find(i => i.id === props.editingId);\n if (item) {\n input.value = item.name;\n }\n input.blur();\n};\n</script>\n\n<style scoped>\n/**\n * FileList - 列表视图样式\n * 参考 macOS Finder 和 Windows Explorer 的设计\n */\n\n.file-list {\n width: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\n.file-list-table {\n width: 100%;\n font-size: 13px;\n text-align: left;\n border-collapse: collapse;\n}\n\n/* 表头 - 更紧凑 */\n.file-list-header {\n font-size: 11px;\n color: #86868b;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n position: sticky;\n top: 0;\n background: rgba(255, 255, 255, 0.92);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n z-index: 10;\n user-select: none;\n}\n\n.file-list-header-cell {\n padding: 6px 12px;\n border-bottom: 1px solid rgba(0, 0, 0, 0.08);\n cursor: pointer;\n text-align: left;\n font-weight: 500;\n transition: background-color 100ms;\n}\n\n.file-list-header-cell:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n.file-list-header-cell--name {\n padding-left: 12px;\n padding-right: 12px;\n width: 45%;\n}\n\n.file-list-body {\n /* 无需额外边框 */\n}\n\n/* 行样式 - 更紧凑 */\n.file-list-row {\n cursor: pointer;\n user-select: none;\n transition: background-color 80ms ease;\n border-bottom: 1px solid transparent;\n}\n\n/* 可拖拽时的鼠标样式 */\n.file-list-row[draggable=\"true\"] {\n cursor: grab;\n}\n\n.file-list-row:active {\n cursor: grabbing;\n}\n\n/* 偶数行 */\n.file-list-row--even {\n background: transparent;\n}\n\n/* 奇数行 - 轻微斑马纹 */\n.file-list-row--odd {\n background: rgba(0, 0, 0, 0.015);\n}\n\n/* 悬停效果 */\n.file-list-row--even:hover,\n.file-list-row--odd:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n/* 选中状态 - macOS 风格整行高亮 */\n.file-list-row--selected {\n background: #007aff;\n color: white;\n}\n\n.file-list-row--selected:hover {\n background: #0066d6;\n}\n\n/* 拖拽悬停 */\n.file-list-row--drag-over {\n background: rgba(0, 122, 255, 0.15);\n border-bottom-color: rgba(0, 122, 255, 0.3);\n}\n\n/* 单元格 - 更紧凑的行高 */\n.file-list-cell {\n padding: 4px 12px;\n white-space: nowrap;\n color: #6e6e73;\n vertical-align: middle;\n height: 28px;\n}\n\n/* 名称列 - 图标和文字对齐 */\n.file-list-cell--name {\n padding-left: 12px;\n padding-right: 12px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* 选中时单元格颜色 */\n.file-list-cell--selected {\n color: rgba(255, 255, 255, 0.75);\n}\n\n/* 大小列 - 等宽字体 */\n.file-list-cell--size {\n font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;\n font-size: 11px;\n color: #8e8e93;\n font-variant-numeric: tabular-nums;\n}\n\n/* 文件名 */\n.file-list-name {\n overflow: hidden;\n text-overflow: ellipsis;\n flex: 1;\n color: #1d1d1f;\n cursor: default;\n font-weight: 400;\n}\n\n/* 选中后点击文件名可编辑 */\n.file-list-name--selected {\n color: white;\n font-weight: 500;\n cursor: text;\n}\n\n/* 重命名输入框 */\n.file-list-rename-input {\n flex: 1;\n font-size: 13px;\n padding: 2px 6px;\n border: 1px solid #007aff;\n border-radius: 4px;\n outline: none;\n box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.2);\n background: white;\n cursor: text;\n}\n\n/* 深色模式支持 */\n@media (prefers-color-scheme: dark) {\n .file-list-header {\n background: rgba(28, 28, 30, 0.92);\n color: #98989d;\n }\n\n .file-list-header-cell {\n border-bottom-color: rgba(255, 255, 255, 0.08);\n }\n\n .file-list-header-cell:hover {\n background: rgba(255, 255, 255, 0.04);\n }\n\n .file-list-row--odd {\n background: rgba(255, 255, 255, 0.02);\n }\n\n .file-list-row--even:hover,\n .file-list-row--odd:hover {\n background: rgba(255, 255, 255, 0.06);\n }\n\n .file-list-row--selected {\n background: #0a84ff;\n }\n\n .file-list-row--selected:hover {\n background: #0077ed;\n }\n\n .file-list-row--drag-over {\n background: rgba(10, 132, 255, 0.2);\n border-bottom-color: rgba(10, 132, 255, 0.4);\n }\n\n .file-list-cell {\n color: #98989d;\n }\n\n .file-list-cell--size {\n color: #6e6e73;\n }\n\n .file-list-name {\n color: #f5f5f7;\n }\n\n .file-list-name--selected {\n color: white;\n }\n\n .file-list-rename-input {\n background: #1c1c1e;\n border-color: #0a84ff;\n color: #f5f5f7;\n }\n}\n</style>\n","<template>\n <div \n class=\"file-list-view\"\n @click=\"handleEmptyClick\"\n @contextmenu.prevent=\"handleEmptyContextMenu\"\n >\n <!-- 加载中 -->\n <div v-if=\"loading\" class=\"file-list-view-loading\">\n <div class=\"file-list-view-spinner\"></div>\n <p>加载中...</p>\n </div>\n\n <!-- 空文件夹 -->\n <div v-else-if=\"items.length === 0\" class=\"file-list-view-empty\">\n <FolderOpen :size=\"64\" class=\"file-list-view-empty-icon\" />\n <p>文件夹为空</p>\n </div>\n\n <!-- 网格视图 -->\n <FileGrid\n v-else-if=\"viewMode === 'grid'\"\n :items=\"items\"\n :selected-ids=\"selectedIds\"\n :editing-id=\"editingId\"\n :drag-over-id=\"dragOverId\"\n :get-app-icon-url=\"getAppIconUrl\"\n @select=\"handleSelect\"\n @open=\"handleOpen\"\n @context-menu=\"handleContextMenu\"\n @context-menu-empty=\"handleEmptyContextMenuFromChild\"\n @name-click=\"handleNameClick\"\n @rename=\"handleRename\"\n @rename-cancel=\"handleRenameCancel\"\n @drag-start=\"handleDragStart\"\n @drag-over=\"handleDragOver\"\n @drag-leave=\"handleDragLeave\"\n @drop=\"handleDrop\"\n />\n\n <!-- 列表视图 -->\n <FileList\n v-else\n :items=\"items\"\n :selected-ids=\"selectedIds\"\n :editing-id=\"editingId\"\n :drag-over-id=\"dragOverId\"\n :sort-config=\"sortConfig\"\n @select=\"handleSelect\"\n @open=\"handleOpen\"\n @context-menu=\"handleContextMenu\"\n @context-menu-empty=\"handleEmptyContextMenuFromChild\"\n @name-click=\"handleNameClick\"\n @rename=\"handleRename\"\n @rename-cancel=\"handleRenameCancel\"\n @sort=\"handleSort\"\n @drag-start=\"handleDragStart\"\n @drag-over=\"handleDragOver\"\n @drag-leave=\"handleDragLeave\"\n @drop=\"handleDrop\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, computed } from 'vue';\nimport { FolderOpen } from 'lucide-vue-next';\nimport FileGrid from './FileGrid.vue';\nimport FileList from './FileList.vue';\nimport { FileType, type FileItem, type SortConfig, type FileExplorerAdapter } from '../types';\n\n// Props\nconst props = withDefaults(defineProps<{\n /** 文件列表 */\n items: FileItem[];\n /** 视图模式 */\n viewMode?: 'grid' | 'list';\n /** 是否加载中 */\n loading?: boolean;\n /** 文件操作适配器(可选,用于内置操作) */\n adapter?: FileExplorerAdapter;\n /** 当前路径(用于内置操作) */\n currentPath?: string;\n /** 获取应用程序图标 URL 的函数 */\n getAppIconUrl?: (item: FileItem) => string | undefined;\n}>(), {\n viewMode: 'grid',\n loading: false,\n});\n\n// Events\nconst emit = defineEmits<{\n /** 打开文件/文件夹 */\n (e: 'open', item: FileItem): void;\n /** 选中项变化 */\n (e: 'selection-change', ids: Set<string>, items: FileItem[]): void;\n /** 右键菜单(文件项) */\n (e: 'context-menu', event: MouseEvent, item: FileItem): void;\n /** 右键菜单(空白处) */\n (e: 'context-menu-empty', event: MouseEvent): void;\n /** 重命名 */\n (e: 'rename', item: FileItem, newName: string): void;\n /** 排序变化 */\n (e: 'sort-change', config: SortConfig): void;\n /** 拖拽移动文件 */\n (e: 'move', sourceIds: string[], targetId: string): void;\n}>();\n\n// 内部状态\nconst selectedIds = ref<Set<string>>(new Set());\nconst editingId = ref<string | null>(null);\nconst dragOverId = ref<string | null>(null);\nconst sortConfig = ref<SortConfig>({ field: 'name', direction: 'asc' });\n\n// 获取选中的文件项\nconst selectedItems = computed(() => \n props.items.filter(item => selectedIds.value.has(item.id))\n);\n\n// 选择处理\nconst handleSelect = (item: FileItem, e: MouseEvent) => {\n if (e.metaKey || e.ctrlKey) {\n // 多选\n const newSet = new Set(selectedIds.value);\n if (newSet.has(item.id)) {\n newSet.delete(item.id);\n } else {\n newSet.add(item.id);\n }\n selectedIds.value = newSet;\n } else if (e.shiftKey && selectedIds.value.size > 0) {\n // 范围选择\n const lastId = Array.from(selectedIds.value).pop();\n const lastIndex = props.items.findIndex(i => i.id === lastId);\n const currentIndex = props.items.findIndex(i => i.id === item.id);\n const start = Math.min(lastIndex, currentIndex);\n const end = Math.max(lastIndex, currentIndex);\n const newSet = new Set<string>();\n for (let i = start; i <= end; i++) {\n newSet.add(props.items[i]!.id);\n }\n selectedIds.value = newSet;\n } else {\n // 单选\n selectedIds.value = new Set([item.id]);\n }\n \n emit('selection-change', selectedIds.value, selectedItems.value);\n};\n\nconst handleEmptyClick = (e: MouseEvent) => {\n // 只有点击空白处才清除选择\n if (e.target === e.currentTarget) {\n clearSelection();\n }\n};\n\n// 清除选择\nconst clearSelection = () => {\n selectedIds.value = new Set();\n emit('selection-change', selectedIds.value, []);\n};\n\n// 打开文件/文件夹\nconst handleOpen = (item: FileItem) => {\n emit('open', item);\n};\n\n// 右键菜单\nconst handleContextMenu = (item: FileItem, e: MouseEvent) => {\n if (!selectedIds.value.has(item.id)) {\n selectedIds.value = new Set([item.id]);\n emit('selection-change', selectedIds.value, [item]);\n }\n emit('context-menu', e, item);\n};\n\nconst handleEmptyContextMenu = (e: MouseEvent) => {\n // 检查是否点击了文件项\n const target = e.target as HTMLElement;\n if (!target.closest('.file-grid-item') && !target.closest('.file-list-row')) {\n clearSelection();\n emit('context-menu-empty', e);\n }\n};\n\n// 从子组件触发的空白处右键菜单\nconst handleEmptyContextMenuFromChild = (e: MouseEvent) => {\n clearSelection();\n emit('context-menu-empty', e);\n};\n\n// 名称点击(用于重命名)\nconst handleNameClick = (item: FileItem, e: MouseEvent) => {\n if (selectedIds.value.has(item.id) && selectedIds.value.size === 1) {\n setTimeout(() => {\n if (selectedIds.value.has(item.id)) {\n editingId.value = item.id;\n }\n }, 500);\n }\n};\n\n// 重命名\nconst handleRename = (item: FileItem, newName: string) => {\n if (newName && newName !== item.name) {\n emit('rename', item, newName);\n }\n editingId.value = null;\n};\n\nconst handleRenameCancel = () => {\n editingId.value = null;\n};\n\n// 排序\nconst handleSort = (field: string) => {\n if (sortConfig.value.field === field) {\n sortConfig.value.direction = sortConfig.value.direction === 'asc' ? 'desc' : 'asc';\n } else {\n sortConfig.value.field = field as SortConfig['field'];\n sortConfig.value.direction = 'asc';\n }\n emit('sort-change', { ...sortConfig.value });\n};\n\n// 拖拽\nconst handleDragStart = (e: DragEvent, item: FileItem) => {\n if (!selectedIds.value.has(item.id)) {\n selectedIds.value = new Set([item.id]);\n emit('selection-change', selectedIds.value, [item]);\n }\n e.dataTransfer?.setData('text/plain', JSON.stringify([...selectedIds.value]));\n};\n\nconst handleDragOver = (e: DragEvent, item: FileItem) => {\n if (item.type === FileType.FOLDER && !selectedIds.value.has(item.id)) {\n dragOverId.value = item.id;\n }\n};\n\nconst handleDragLeave = () => {\n dragOverId.value = null;\n};\n\nconst handleDrop = (e: DragEvent, targetItem: FileItem) => {\n dragOverId.value = null;\n \n if (targetItem.type !== FileType.FOLDER) return;\n \n const data = e.dataTransfer?.getData('text/plain');\n if (!data) return;\n \n try {\n const draggedIds: string[] = JSON.parse(data);\n if (draggedIds.includes(targetItem.id)) return;\n \n emit('move', draggedIds, targetItem.id);\n clearSelection();\n } catch (error) {\n console.error('拖拽解析失败:', error);\n }\n};\n\n// 开始重命名(供外部调用)\nconst startRename = (id: string) => {\n editingId.value = id;\n};\n\n// 全选\nconst selectAll = () => {\n selectedIds.value = new Set(props.items.map(i => i.id));\n emit('selection-change', selectedIds.value, props.items);\n};\n\n// 暴露方法\ndefineExpose({\n clearSelection,\n startRename,\n selectAll,\n selectedIds,\n selectedItems,\n});\n</script>\n\n<style scoped>\n.file-list-view {\n flex: 1;\n overflow: auto;\n padding: 12px;\n user-select: none;\n min-height: 0;\n}\n\n.file-list-view-loading,\n.file-list-view-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: rgb(156, 163, 175);\n gap: 16px;\n}\n\n.file-list-view-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid rgba(156, 163, 175, 0.2);\n border-top-color: rgb(59, 130, 246);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n}\n\n@keyframes spin {\n to { transform: rotate(360deg); }\n}\n\n.file-list-view-empty-icon {\n opacity: 0.3;\n}\n</style>\n","<template>\n <div class=\"file-sidebar\">\n <div v-for=\"section in sections\" :key=\"section.id\" class=\"file-sidebar-section\">\n <div class=\"file-sidebar-section-title\">{{ section.title }}</div>\n <ul class=\"file-sidebar-list\">\n <li\n v-for=\"item in section.items\"\n :key=\"item.id\"\n @click=\"handleNavigate(item)\"\n :class=\"[\n 'file-sidebar-item',\n activeId === item.id ? 'file-sidebar-item--active' : ''\n ]\"\n >\n <Icon \n :icon=\"getIconName(item.icon)\" \n :width=\"18\" \n :height=\"18\" \n :class=\"activeId === item.id ? 'file-sidebar-item-icon--active' : 'file-sidebar-item-icon'\"\n />\n <span>{{ item.label }}</span>\n </li>\n </ul>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Icon } from '@iconify/vue';\nimport type { SidebarItem } from '../types';\n\ninterface SidebarSection {\n id: string;\n title: string;\n items: SidebarItem[];\n}\n\ninterface Props {\n sections: SidebarSection[];\n activeId?: string;\n}\n\ndefineProps<Props>();\n\nconst emit = defineEmits<{\n navigate: [item: SidebarItem];\n}>();\n\n// 将 Lucide 图标名称转换为 Iconify 格式\nconst getIconName = (iconName?: string): string => {\n if (!iconName) return 'mdi:folder';\n // 如果已经是 Iconify 格式,直接返回\n if (iconName.includes(':')) return iconName;\n // 否则转换为 lucide: 格式\n return `lucide:${iconName.toLowerCase()}`;\n};\n\nconst handleNavigate = (item: SidebarItem) => {\n emit('navigate', item);\n};\n</script>\n\n<style scoped>\n.file-sidebar {\n width: 12rem;\n background: rgba(243, 244, 246, 0.5);\n backdrop-filter: blur(24px);\n border-right: 1px solid rgba(229, 231, 233, 0.5);\n display: flex;\n flex-direction: column;\n padding-top: 2rem;\n padding-bottom: 1rem;\n height: 100%;\n box-sizing: border-box;\n overflow-y: auto;\n overflow-x: hidden;\n user-select: none;\n -webkit-app-region: drag; /* 整个侧边栏可拖拽 */\n}\n\n/* 自定义滚动条样式 */\n.file-sidebar::-webkit-scrollbar {\n width: 6px;\n}\n\n.file-sidebar::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.file-sidebar::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.2);\n border-radius: 3px;\n}\n\n.file-sidebar::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.3);\n}\n\n.file-sidebar-section {\n margin-bottom: 0;\n -webkit-app-region: no-drag; /* section 内容区域不可拖拽 */\n}\n\n.file-sidebar-section-title {\n padding: 0 1rem;\n margin-bottom: 0.5rem;\n font-size: 0.75rem;\n font-weight: 600;\n color: rgb(107, 114, 128);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.file-sidebar-section + .file-sidebar-section .file-sidebar-section-title {\n margin-top: 1.5rem;\n}\n\n.file-sidebar-list {\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n padding: 0 0.5rem;\n margin: 0;\n}\n\n.file-sidebar-item {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.375rem 0.75rem;\n border-radius: 0.375rem;\n cursor: pointer;\n font-size: 0.875rem;\n font-weight: 500;\n color: rgb(75, 85, 99);\n transition: all 200ms;\n /* no-drag 已由 section 继承 */\n}\n\n.file-sidebar-item:hover {\n background: rgba(229, 231, 233, 0.5);\n color: black;\n}\n\n.file-sidebar-item--active {\n background: rgba(209, 213, 219, 0.6);\n color: black;\n}\n\n.file-sidebar-item-icon {\n color: rgb(107, 114, 128);\n}\n\n.file-sidebar-item-icon--active {\n color: rgb(37, 99, 235);\n}\n</style>\n","<template>\n <div class=\"file-breadcrumb\">\n <span \n v-for=\"(item, index) in items\" \n :key=\"item.id\"\n class=\"file-breadcrumb-item\"\n >\n <span \n @click=\"handleClick(item, index)\"\n :class=\"[\n 'file-breadcrumb-link',\n index === items.length - 1 ? 'file-breadcrumb-link--current' : ''\n ]\"\n >\n {{ item.name }}\n </span>\n <Icon \n v-if=\"index < items.length - 1\" \n icon=\"lucide:chevron-right\" \n :width=\"14\" \n :height=\"14\" \n class=\"file-breadcrumb-separator\" \n />\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Icon } from '@iconify/vue';\nimport type { BreadcrumbItem } from '../types';\n\n// Props\nconst props = defineProps<{\n items: BreadcrumbItem[];\n}>();\n\n// Events\nconst emit = defineEmits<{\n (e: 'navigate', item: BreadcrumbItem, index: number): void;\n}>();\n\nconst handleClick = (item: BreadcrumbItem, index: number) => {\n // 点击最后一项不触发导航\n if (index < props.items.length - 1) {\n emit('navigate', item, index);\n }\n};\n</script>\n\n<style scoped>\n.file-breadcrumb {\n display: inline-flex;\n align-items: center;\n gap: 0.125rem;\n overflow-x: auto;\n padding: 0 0.25rem;\n max-width: 100%;\n scrollbar-width: none;\n -ms-overflow-style: none;\n -webkit-app-region: no-drag; /* 面包屑内容不可拖拽,但空白区域可拖拽 */\n}\n\n.file-breadcrumb::-webkit-scrollbar {\n display: none;\n}\n\n.file-breadcrumb-item {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n}\n\n.file-breadcrumb-link {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem;\n border-radius: 0.375rem;\n font-size: 0.875rem;\n transition: all 200ms;\n border: none;\n background: transparent;\n cursor: pointer;\n color: rgb(75, 85, 99);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.file-breadcrumb-link:hover {\n background: rgba(229, 231, 233, 0.6);\n color: rgb(17, 24, 39);\n}\n\n.file-breadcrumb-link--current {\n font-weight: 600;\n color: rgb(17, 24, 39);\n background: rgba(229, 231, 233, 0.5);\n cursor: default;\n}\n\n.file-breadcrumb-link--current:hover {\n background: rgba(229, 231, 233, 0.5);\n}\n\n.file-breadcrumb-separator {\n color: rgb(156, 163, 175);\n margin: 0 0.25rem;\n flex-shrink: 0;\n}\n</style>\n","<template>\n <div class=\"file-toolbar\" :class=\"{ 'file-toolbar--draggable': draggable }\">\n <!-- 导航按钮 -->\n <div class=\"file-toolbar-nav\">\n <button \n class=\"file-toolbar-button\" \n @click=\"emit('back')\" \n :disabled=\"!canGoBack\"\n title=\"后退\"\n >\n <Icon icon=\"lucide:chevron-left\" :width=\"18\" :height=\"18\" />\n </button>\n <button \n class=\"file-toolbar-button\" \n @click=\"emit('forward')\" \n :disabled=\"!canGoForward\"\n title=\"前进\"\n >\n <Icon icon=\"lucide:chevron-right\" :width=\"18\" :height=\"18\" />\n </button>\n </div>\n\n <!-- 面包屑插槽 -->\n <div class=\"file-toolbar-breadcrumb\">\n <slot name=\"breadcrumb\">\n <Breadcrumb\n v-if=\"breadcrumbs.length > 0\"\n :items=\"breadcrumbs\"\n @navigate=\"(item) => emit('breadcrumb-navigate', item)\"\n />\n </slot>\n </div>\n\n <!-- 自定义内容插槽 -->\n <div v-if=\"$slots.default\" class=\"file-toolbar-custom\">\n <slot></slot>\n </div>\n\n <!-- 操作区 -->\n <div class=\"file-toolbar-actions\">\n <!-- 搜索框 -->\n <div v-if=\"showSearch\" class=\"file-toolbar-search\">\n <Icon icon=\"lucide:search\" :width=\"16\" :height=\"16\" class=\"file-toolbar-search-icon\" />\n <input\n type=\"text\"\n :value=\"searchQuery\"\n @input=\"emit('update:searchQuery', ($event.target as HTMLInputElement).value)\"\n placeholder=\"搜索\"\n class=\"file-toolbar-search-input\"\n />\n </div>\n\n <!-- 视图切换 -->\n <div v-if=\"showViewToggle\" class=\"file-toolbar-view-toggle\">\n <button \n @click=\"emit('update:viewMode', 'grid')\" \n :class=\"['file-toolbar-button', viewMode === 'grid' ? 'file-toolbar-button--active' : '']\"\n title=\"网格视图\"\n >\n <Icon icon=\"lucide:layout-grid\" :width=\"18\" :height=\"18\" />\n </button>\n <button \n @click=\"emit('update:viewMode', 'list')\" \n :class=\"['file-toolbar-button', viewMode === 'list' ? 'file-toolbar-button--active' : '']\"\n title=\"列表视图\"\n >\n <Icon icon=\"lucide:list\" :width=\"18\" :height=\"18\" />\n </button>\n </div>\n\n <!-- 额外操作插槽 -->\n <slot name=\"actions\"></slot>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Icon } from '@iconify/vue';\nimport Breadcrumb from './Breadcrumb.vue';\nimport type { BreadcrumbItem } from '../types';\n\n// Props\nwithDefaults(defineProps<{\n /** 是否可后退 */\n canGoBack?: boolean;\n /** 是否可前进 */\n canGoForward?: boolean;\n /** 面包屑数据 */\n breadcrumbs?: BreadcrumbItem[];\n /** 视图模式 */\n viewMode?: 'grid' | 'list';\n /** 搜索关键词 */\n searchQuery?: string;\n /** 是否显示搜索框 */\n showSearch?: boolean;\n /** 是否显示视图切换 */\n showViewToggle?: boolean;\n /** 是否可拖拽(用于窗口拖动) */\n draggable?: boolean;\n}>(), {\n canGoBack: false,\n canGoForward: false,\n breadcrumbs: () => [],\n viewMode: 'grid',\n searchQuery: '',\n showSearch: false,\n showViewToggle: true,\n draggable: false,\n});\n\n// Events\nconst emit = defineEmits<{\n (e: 'back'): void;\n (e: 'forward'): void;\n (e: 'breadcrumb-navigate', item: BreadcrumbItem): void;\n (e: 'update:viewMode', mode: 'grid' | 'list'): void;\n (e: 'update:searchQuery', query: string): void;\n}>();\n</script>\n\n<style scoped>\n.file-toolbar {\n height: 3rem;\n background: rgba(249, 250, 251, 0.9);\n backdrop-filter: blur(12px);\n border-bottom: 1px solid rgb(229, 231, 233);\n display: flex;\n align-items: center;\n padding: 0 1rem;\n user-select: none;\n flex-shrink: 0;\n z-index: 30;\n position: relative;\n}\n\n.file-toolbar--draggable {\n -webkit-app-region: drag;\n}\n\n.file-toolbar-nav {\n display: flex;\n align-items: center;\n color: rgb(75, 85, 99);\n background: rgba(229, 231, 233, 0.5);\n border-radius: 0.5rem;\n padding: 0.125rem;\n flex-shrink: 0;\n -webkit-app-region: no-drag;\n}\n\n.file-toolbar-button {\n padding: 0.25rem;\n border-radius: 0.375rem;\n transition: all 200ms;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: rgb(31, 41, 55);\n}\n\n.file-toolbar-button:hover:not(:disabled) {\n background: rgb(209, 213, 219);\n}\n\n.file-toolbar-button:disabled {\n color: rgb(156, 163, 175);\n cursor: default;\n}\n\n.file-toolbar-button--active {\n background: white;\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n color: rgb(31, 41, 55);\n}\n\n.file-toolbar-breadcrumb {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n margin-left: 1rem;\n /* 不设置 no-drag,让空白区域可拖拽 */\n}\n\n.file-toolbar-custom {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n -webkit-app-region: no-drag;\n}\n\n.file-toolbar-actions {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex-shrink: 0;\n margin-left: auto;\n -webkit-app-region: no-drag;\n}\n\n.file-toolbar-search {\n position: relative;\n display: none;\n}\n\n@media (min-width: 768px) {\n .file-toolbar-search {\n display: block;\n }\n}\n\n.file-toolbar-search-icon {\n position: absolute;\n left: 0.625rem;\n top: 50%;\n transform: translateY(-50%);\n color: rgb(156, 163, 175);\n transition: color 200ms;\n}\n\n.file-toolbar-search:focus-within .file-toolbar-search-icon {\n color: rgb(59, 130, 246);\n}\n\n.file-toolbar-search-input {\n background: rgb(243, 244, 246);\n border: 1px solid transparent;\n border-radius: 0.375rem;\n padding-left: 2rem;\n padding-right: 0.75rem;\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n font-size: 0.875rem;\n outline: none;\n transition: all 200ms;\n width: 8rem;\n color: rgb(55, 65, 81);\n}\n\n.file-toolbar-search-input::placeholder {\n color: rgb(156, 163, 175);\n}\n\n.file-toolbar-search-input:focus {\n background: white;\n border-color: rgb(96, 165, 250);\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\n width: 12rem;\n}\n\n.file-toolbar-view-toggle {\n display: flex;\n align-items: center;\n background: rgba(229, 231, 233, 0.5);\n border-radius: 0.5rem;\n padding: 0.125rem;\n color: rgb(75, 85, 99);\n}\n\n.file-toolbar-view-toggle .file-toolbar-button--active {\n background: white;\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n color: rgb(31, 41, 55);\n}\n\n.file-toolbar-view-toggle .file-toolbar-button:not(.file-toolbar-button--active):hover {\n background: rgba(209, 213, 219, 0.5);\n}\n</style>\n","<template>\n <div class=\"file-status-bar\">\n <slot>\n <span>{{ itemCount }} 个项目</span>\n <span v-if=\"selectedCount > 0\"> • 已选择 {{ selectedCount }} 个</span>\n </slot>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n// Props\nwithDefaults(defineProps<{\n /** 项目总数 */\n itemCount?: number;\n /** 选中数量 */\n selectedCount?: number;\n}>(), {\n itemCount: 0,\n selectedCount: 0,\n});\n</script>\n\n<style scoped>\n.file-status-bar {\n height: 1.5rem;\n background-color: rgb(249, 250, 251);\n border-top: 1px solid rgb(229, 231, 233);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 8px;\n font-size: 10px;\n color: rgb(107, 114, 128);\n user-select: none;\n flex-shrink: 0;\n z-index: 20;\n gap: 4px;\n}\n\n.file-status-bar > * {\n flex-shrink: 0;\n}\n</style>\n","<template>\n <Teleport to=\"body\">\n <div v-if=\"visible\" class=\"context-menu-container\">\n <!-- 主菜单 - 不使用 overlay,通过 document mousedown 事件来关闭菜单 -->\n <div \n ref=\"menuRef\"\n class=\"context-menu\"\n :style=\"menuStyle\"\n >\n <template v-for=\"(option, index) in options\" :key=\"option.id || index\">\n <div v-if=\"option.separator\" class=\"context-menu-separator\" />\n <div\n v-else\n :ref=\"(el) => setItemRef(option.id, el)\"\n :class=\"[\n 'context-menu-item',\n option.disabled ? 'context-menu-item--disabled' : '',\n option.danger ? 'context-menu-item--danger' : '',\n hasChildren(option) ? 'context-menu-item--has-children' : '',\n hoveredItemId === option.id ? 'context-menu-item--active' : ''\n ]\"\n @click=\"handleOptionClick(option)\"\n @mouseenter=\"handleItemMouseEnter(option)\"\n >\n <Icon \n v-if=\"option.icon\" \n :icon=\"option.icon\" \n width=\"16\" \n height=\"16\" \n class=\"context-menu-item-icon\" \n />\n <span class=\"context-menu-item-label\">{{ option.label }}</span>\n <Icon \n v-if=\"option.checked\" \n icon=\"lucide:check\" \n width=\"14\" \n height=\"14\" \n class=\"context-menu-item-check\" \n />\n <span v-if=\"option.shortcut && !hasChildren(option)\" class=\"context-menu-item-shortcut\">\n {{ option.shortcut }}\n </span>\n <Icon \n v-if=\"hasChildren(option)\"\n icon=\"lucide:chevron-right\" \n width=\"14\" \n height=\"14\" \n class=\"context-menu-item-arrow\" \n />\n </div>\n </template>\n </div>\n \n <!-- 二级菜单(独立渲染,避免定位问题) -->\n <div\n v-if=\"hoveredItem && submenuPosition\"\n class=\"context-menu context-menu-submenu\"\n :style=\"submenuStyle\"\n @mouseenter=\"keepSubmenuOpen\"\n @mouseleave=\"closeSubmenu\"\n >\n <template v-for=\"(child, childIndex) in hoveredItem.children\" :key=\"child.id || childIndex\">\n <div v-if=\"child.separator\" class=\"context-menu-separator\" />\n <div\n v-else\n :class=\"[\n 'context-menu-item',\n child.disabled ? 'context-menu-item--disabled' : '',\n child.danger ? 'context-menu-item--danger' : ''\n ]\"\n @click=\"handleOptionClick(child)\"\n >\n <Icon \n v-if=\"child.icon\" \n :icon=\"child.icon\" \n width=\"16\" \n height=\"16\" \n class=\"context-menu-item-icon\" \n />\n <span class=\"context-menu-item-label\">{{ child.label }}</span>\n <Icon \n v-if=\"child.checked\" \n icon=\"lucide:check\" \n width=\"14\" \n height=\"14\" \n class=\"context-menu-item-check\" \n />\n <span v-if=\"child.shortcut\" class=\"context-menu-item-shortcut\">\n {{ child.shortcut }}\n </span>\n </div>\n </template>\n </div>\n </div>\n </Teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch, nextTick, onMounted, onUnmounted } from 'vue';\nimport { Icon } from '@iconify/vue';\nimport type { ContextMenuItem } from '../types';\n\ninterface Props {\n visible: boolean;\n x: number;\n y: number;\n options: ContextMenuItem[];\n}\n\nconst props = defineProps<Props>();\n\nconst emit = defineEmits<{\n close: [];\n select: [option: ContextMenuItem];\n}>();\n\n/** 边距常量 */\nconst MARGIN = 8;\n/** 菜单固定宽度 */\nconst MENU_WIDTH = 220;\n/** 菜单项高度 */\nconst MENU_ITEM_HEIGHT = 32;\n/** 分隔线高度 */\nconst SEPARATOR_HEIGHT = 9;\n/** 菜单内边距 */\nconst MENU_PADDING = 8;\n/** 子菜单与父菜单的间距 */\nconst SUBMENU_GAP = 0;\n\n/**\n * 估算菜单高度(根据菜单项数量)\n */\nfunction estimateMenuHeight(items: ContextMenuItem[]): number {\n let height = MENU_PADDING;\n for (const item of items) {\n height += item.separator ? SEPARATOR_HEIGHT : MENU_ITEM_HEIGHT;\n }\n return height;\n}\n\n/**\n * 计算自适应菜单位置\n * 使用固定宽度,只需测量高度,简化计算逻辑\n */\nfunction calculateMenuPosition(\n clickX: number,\n clickY: number,\n menuHeight: number\n): { x: number; y: number } {\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n let adjustedX = clickX;\n let adjustedY = clickY;\n\n // 水平方向调整(使用固定宽度)\n const spaceRight = viewportWidth - clickX;\n const spaceLeft = clickX;\n\n // 如果右边空间不足,尝试在左边显示\n if (spaceRight < MENU_WIDTH + MARGIN) {\n // 左边空间足够,在左边显示\n if (spaceLeft >= MENU_WIDTH + MARGIN) {\n adjustedX = clickX - MENU_WIDTH;\n } else {\n // 左右空间都不足,选择空间更大的一边,并留出边距\n if (spaceRight > spaceLeft) {\n adjustedX = viewportWidth - MENU_WIDTH - MARGIN;\n } else {\n adjustedX = MARGIN;\n }\n }\n }\n\n // 垂直方向调整\n const spaceBottom = viewportHeight - clickY;\n const spaceTop = clickY;\n\n // 如果下边空间不足,尝试在上边显示\n if (spaceBottom < menuHeight + MARGIN) {\n // 上边空间足够,在上边显示\n if (spaceTop >= menuHeight + MARGIN) {\n adjustedY = clickY - menuHeight;\n } else {\n // 上下空间都不足,选择空间更大的一边,并留出边距\n if (spaceBottom > spaceTop) {\n adjustedY = viewportHeight - menuHeight - MARGIN;\n } else {\n adjustedY = MARGIN;\n }\n }\n }\n\n // 最终边界检查,确保不会超出视口\n adjustedX = Math.max(MARGIN, Math.min(adjustedX, viewportWidth - MENU_WIDTH - MARGIN));\n adjustedY = Math.max(MARGIN, Math.min(adjustedY, viewportHeight - menuHeight - MARGIN));\n\n return { x: adjustedX, y: adjustedY };\n}\n\n/**\n * 计算二级菜单位置(Windows/Mac 标准行为:优先右侧,空间不足时左侧)\n */\nfunction calculateSubmenuPosition(\n parentRect: DOMRect,\n submenuHeight: number\n): { x: number; y: number } {\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n // 计算可用空间\n const spaceRight = viewportWidth - parentRect.right;\n const spaceLeft = parentRect.left;\n\n let submenuX: number;\n let submenuY: number;\n\n // 水平方向:优先右侧,空间不足时左侧(Windows/Mac 标准行为)\n if (spaceRight >= MENU_WIDTH + SUBMENU_GAP + MARGIN) {\n // 右侧有足够空间,在右侧显示(紧贴父菜单右边缘)\n submenuX = parentRect.right + SUBMENU_GAP;\n } else if (spaceLeft >= MENU_WIDTH + SUBMENU_GAP + MARGIN) {\n // 右侧空间不足,左侧有足够空间,在左侧显示(紧贴父菜单左边缘)\n submenuX = parentRect.left - MENU_WIDTH - SUBMENU_GAP;\n } else {\n // 左右空间都不足,选择空间更大的一边\n if (spaceRight > spaceLeft) {\n submenuX = viewportWidth - MENU_WIDTH - MARGIN;\n } else {\n submenuX = MARGIN;\n }\n }\n\n // 垂直方向:与父菜单项顶部对齐(Windows/Mac 标准行为)\n submenuY = parentRect.top;\n\n // 如果子菜单底部超出视口,向上调整\n if (submenuY + submenuHeight > viewportHeight - MARGIN) {\n submenuY = viewportHeight - submenuHeight - MARGIN;\n }\n\n // 如果子菜单顶部超出视口,向下调整\n if (submenuY < MARGIN) {\n submenuY = MARGIN;\n }\n\n return { x: submenuX, y: submenuY };\n}\n\nconst menuRef = ref<HTMLDivElement | null>(null);\nconst hoveredItemId = ref<string | null>(null);\nconst submenuPosition = ref<{ x: number; y: number } | null>(null);\nconst itemRefs = ref<Map<string, HTMLElement>>(new Map());\n\n// 使用 computed 在渲染前计算位置(使用估算高度,避免位置调整动画)\nconst position = computed(() => {\n const estimatedHeight = estimateMenuHeight(props.options);\n return calculateMenuPosition(props.x, props.y, estimatedHeight);\n});\n\nconst menuStyle = computed(() => ({\n left: `${position.value.x}px`,\n top: `${position.value.y}px`\n}));\n\nconst submenuStyle = computed(() => {\n if (!submenuPosition.value) return {};\n return {\n left: `${submenuPosition.value.x}px`,\n top: `${submenuPosition.value.y}px`\n };\n});\n\n// 获取当前悬停项的子菜单\nconst hoveredItem = computed(() => {\n if (!hoveredItemId.value) return null;\n return props.options.find(opt => opt.id === hoveredItemId.value && opt.children && opt.children.length > 0);\n});\n\n// 设置菜单项 ref\nconst setItemRef = (id: string, el: unknown) => {\n if (el && el instanceof HTMLElement) {\n itemRefs.value.set(id, el);\n } else {\n itemRefs.value.delete(id);\n }\n};\n\n// 检查是否有子菜单\nconst hasChildren = (option: ContextMenuItem) => {\n return option.children && option.children.length > 0;\n};\n\n// 计算子菜单位置\nwatch(hoveredItemId, (newId) => {\n if (!newId || !hoveredItem.value) {\n submenuPosition.value = null;\n return;\n }\n\n nextTick(() => {\n const itemEl = itemRefs.value.get(newId);\n if (!itemEl || !hoveredItem.value?.children) {\n submenuPosition.value = null;\n return;\n }\n\n const rect = itemEl.getBoundingClientRect();\n const submenuHeight = estimateMenuHeight(hoveredItem.value.children);\n submenuPosition.value = calculateSubmenuPosition(rect, submenuHeight);\n });\n});\n\n// 重置状态当菜单关闭时\nwatch(() => props.visible, (visible) => {\n if (!visible) {\n hoveredItemId.value = null;\n submenuPosition.value = null;\n }\n});\n\n// 点击外部或按 ESC 键时关闭(事件处理函数定义在外部,确保引用一致)\nconst handleClickOutside = (e: MouseEvent) => {\n const target = e.target as Node;\n \n // 检查是否点击在菜单内(包括主菜单和子菜单)\n const menuContainer = document.querySelector('.context-menu-container');\n if (menuContainer && menuContainer.contains(target)) {\n return;\n }\n\n emit('close');\n};\n\nconst handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n emit('close');\n }\n};\n\n// 监听 visible 变化,添加/移除事件监听器\nwatch(() => props.visible, (visible) => {\n if (visible) {\n // 使用 mousedown 来更快响应(Windows/Mac 标准行为)\n document.addEventListener('mousedown', handleClickOutside);\n document.addEventListener('keydown', handleEscape);\n } else {\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('keydown', handleEscape);\n }\n}, { immediate: true });\n\n// 组件卸载时移除事件监听器\nonUnmounted(() => {\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('keydown', handleEscape);\n});\n\n\nconst handleOptionClick = (option: ContextMenuItem) => {\n if (option.disabled) return;\n \n // 如果有子菜单,不执行 action,只显示子菜单\n if (option.children && option.children.length > 0) {\n return;\n }\n \n if (option.action) {\n option.action();\n }\n emit('select', option);\n emit('close');\n};\n\n// 处理菜单项鼠标进入\nconst handleItemMouseEnter = (option: ContextMenuItem) => {\n if (option.children && option.children.length > 0) {\n hoveredItemId.value = option.id;\n } else {\n hoveredItemId.value = null;\n }\n};\n\n// 保持子菜单打开\nconst keepSubmenuOpen = () => {\n // 当鼠标在子菜单上时,保持 hoveredItemId 不变\n};\n\n// 关闭子菜单\nconst closeSubmenu = () => {\n hoveredItemId.value = null;\n};\n</script>\n\n<style scoped>\n/* container 不拦截事件,让右键事件可以穿透到下层文件列表 */\n.context-menu-container {\n position: fixed;\n inset: 0;\n z-index: 9999;\n pointer-events: none;\n}\n\n.context-menu {\n position: fixed;\n z-index: 10000;\n width: 220px; /* 固定宽度,与 calculateMenuPosition 中的 MENU_WIDTH 一致 */\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(24px);\n border: 1px solid rgba(229, 231, 233, 0.5);\n border-radius: 0.5rem;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.15), 0 4px 6px -2px rgba(0, 0, 0, 0.1);\n padding: 0.25rem 0;\n font-size: 0.875rem;\n user-select: none;\n animation: fade-in 100ms ease-out, zoom-in 100ms ease-out;\n pointer-events: auto;\n}\n\n@keyframes fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@keyframes zoom-in {\n from { transform: scale(0.95); }\n to { transform: scale(1); }\n}\n\n.context-menu-item {\n width: 100%;\n text-align: left;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.375rem 1rem;\n color: rgb(55, 65, 81);\n transition: all 200ms;\n border: none;\n background: transparent;\n cursor: pointer;\n}\n\n.context-menu-item:hover {\n background: rgb(59, 130, 246);\n color: white;\n}\n\n.context-menu-item:hover .context-menu-item-icon {\n color: white;\n}\n\n.context-menu-item:hover .context-menu-item-shortcut {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.context-menu-item--disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.context-menu-item--disabled:hover {\n background: transparent;\n color: rgb(55, 65, 81);\n}\n\n.context-menu-item--disabled:hover .context-menu-item-icon {\n color: rgb(107, 114, 128);\n}\n\n.context-menu-item--danger {\n color: rgb(220, 38, 38);\n}\n\n.context-menu-item--danger:hover {\n background: rgb(220, 38, 38);\n color: white;\n}\n\n.context-menu-item--danger .context-menu-item-icon {\n color: rgb(220, 38, 38);\n}\n\n.context-menu-item--danger:hover .context-menu-item-icon {\n color: white;\n}\n\n.context-menu-item--has-children {\n position: relative;\n}\n\n.context-menu-item--active {\n background: rgb(59, 130, 246);\n color: white;\n}\n\n.context-menu-item--active .context-menu-item-icon {\n color: white;\n}\n\n.context-menu-item--active .context-menu-item-shortcut {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.context-menu-item-icon {\n color: rgb(107, 114, 128);\n flex-shrink: 0;\n}\n\n.context-menu-item-label {\n flex: 1;\n}\n\n.context-menu-item-shortcut {\n color: rgb(156, 163, 175);\n font-size: 0.6875rem;\n}\n\n.context-menu-separator {\n height: 1px;\n background: rgb(229, 231, 233);\n margin: 0.25rem 0.5rem;\n}\n\n.context-menu-item-check {\n color: rgb(107, 114, 128);\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.context-menu-item:hover .context-menu-item-check,\n.context-menu-item--active .context-menu-item-check {\n color: white;\n}\n\n.context-menu-item-arrow {\n color: rgb(156, 163, 175);\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.context-menu-item:hover .context-menu-item-arrow,\n.context-menu-item--active .context-menu-item-arrow {\n color: white;\n}\n\n.context-menu-submenu {\n z-index: 10001;\n}\n</style>\n","import { ref, watch, onUnmounted } from 'vue';\n\n/**\n * 窗口拖拽功能管理\n */\nexport function useWindowDrag() {\n const position = ref({ x: 0, y: 0 });\n const isDragging = ref(false);\n\n /**\n * 鼠标移动处理\n */\n const handleMouseMove = (e: MouseEvent) => {\n if (!isDragging.value) return;\n position.value = {\n x: position.value.x + e.movementX,\n y: position.value.y + e.movementY\n };\n };\n\n /**\n * 鼠标释放处理\n */\n const handleMouseUp = () => {\n isDragging.value = false;\n };\n\n /**\n * 开始拖拽\n */\n const startDrag = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n // 检查是否点击在可拖拽区域,但排除按钮\n if (target.closest('.draggable-area') && !target.closest('button')) {\n e.preventDefault();\n isDragging.value = true;\n }\n };\n\n /**\n * 监听拖拽状态变化\n */\n watch(isDragging, (dragging) => {\n if (dragging) {\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n } else {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n }\n });\n\n /**\n * 清理事件监听\n */\n onUnmounted(() => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n });\n\n return {\n position,\n isDragging,\n startDrag\n };\n}\n","import { ref, watch, onUnmounted } from 'vue';\n\ntype ResizeDirection = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';\n\n/**\n * 窗口调整大小功能管理\n */\nexport function useWindowResize(\n initialWidth: number,\n initialHeight: number,\n minWidth: number,\n minHeight: number,\n maxWidth: number,\n maxHeight: number\n) {\n const width = ref(initialWidth);\n const height = ref(initialHeight);\n const isResizing = ref(false);\n const resizeDirection = ref<ResizeDirection | null>(null);\n const startX = ref(0);\n const startY = ref(0);\n const startWidth = ref(0);\n const startHeight = ref(0);\n\n /**\n * 鼠标移动处理\n */\n const handleMouseMove = (e: MouseEvent) => {\n if (!isResizing.value || !resizeDirection.value) return;\n\n const deltaX = e.clientX - startX.value;\n const deltaY = e.clientY - startY.value;\n\n let newWidth = startWidth.value;\n let newHeight = startHeight.value;\n\n const direction = resizeDirection.value;\n\n // 处理水平方向\n if (direction.includes('e')) {\n newWidth = Math.min(Math.max(startWidth.value + deltaX, minWidth), maxWidth);\n } else if (direction.includes('w')) {\n newWidth = Math.min(Math.max(startWidth.value - deltaX, minWidth), maxWidth);\n }\n\n // 处理垂直方向\n if (direction.includes('s')) {\n newHeight = Math.min(Math.max(startHeight.value + deltaY, minHeight), maxHeight);\n } else if (direction.includes('n')) {\n newHeight = Math.min(Math.max(startHeight.value - deltaY, minHeight), maxHeight);\n }\n\n width.value = newWidth;\n height.value = newHeight;\n };\n\n /**\n * 鼠标释放处理\n */\n const handleMouseUp = () => {\n isResizing.value = false;\n resizeDirection.value = null;\n };\n\n /**\n * 开始调整大小\n */\n const startResize = (\n e: MouseEvent,\n direction: ResizeDirection,\n currentWidth: number,\n currentHeight: number\n ) => {\n e.preventDefault();\n e.stopPropagation();\n isResizing.value = true;\n resizeDirection.value = direction;\n startX.value = e.clientX;\n startY.value = e.clientY;\n startWidth.value = currentWidth;\n startHeight.value = currentHeight;\n };\n\n /**\n * 获取对应方向的鼠标样式\n */\n const getCursorForDirection = (direction: ResizeDirection): string => {\n const cursors: Record<ResizeDirection, string> = {\n n: 'n-resize',\n s: 's-resize',\n e: 'e-resize',\n w: 'w-resize',\n ne: 'ne-resize',\n nw: 'nw-resize',\n se: 'se-resize',\n sw: 'sw-resize'\n };\n return cursors[direction];\n };\n\n /**\n * 监听调整大小状态变化\n */\n watch(isResizing, (resizing) => {\n if (resizing) {\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n document.body.style.cursor = getCursorForDirection(resizeDirection.value || 'se');\n document.body.style.userSelect = 'none';\n } else {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n }\n });\n\n /**\n * 清理事件监听\n */\n onUnmounted(() => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n });\n\n return {\n width,\n height,\n isResizing,\n startResize\n };\n}\n","<template>\n <Teleport to=\"body\">\n <div \n class=\"window-overlay\"\n @click=\"handleBackdropClick\"\n >\n <div \n ref=\"windowContainerRef\"\n class=\"window-container\"\n :style=\"windowStyle\"\n @click.stop\n >\n <!-- Title Bar -->\n <div \n v-if=\"showTitleBar\"\n class=\"window-title-bar draggable-area\"\n @mousedown=\"handleDragStart\"\n >\n <div class=\"window-controls\">\n <button \n @click.stop=\"handleClose\" \n class=\"window-control-button window-control-button--close\"\n >\n <X :size=\"7\" class=\"window-control-icon\" />\n </button>\n <button \n v-if=\"showMinimize\"\n @click.stop=\"handleMinimize\" \n class=\"window-control-button window-control-button--minimize\"\n >\n <Minus :size=\"7\" class=\"window-control-icon\" />\n </button>\n <button \n v-if=\"showMaximize\"\n @click.stop=\"handleMaximize\" \n class=\"window-control-button window-control-button--maximize\"\n >\n <Maximize2 :size=\"7\" class=\"window-control-icon\" />\n </button>\n </div>\n \n <div class=\"window-title-info\">\n <slot name=\"title\">\n <span class=\"window-title-text\">{{ title }}</span>\n </slot>\n </div>\n\n <div class=\"window-title-actions\">\n <slot name=\"actions\"></slot>\n </div>\n </div>\n\n <!-- Content -->\n <div class=\"window-content\">\n <slot></slot>\n </div>\n\n <!-- Resize Handles -->\n <template v-if=\"resizable\">\n <div \n class=\"window-resize-handle window-resize-handle--n\"\n @mousedown=\"(e) => handleResizeStart(e, 'n')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--s\"\n @mousedown=\"(e) => handleResizeStart(e, 's')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--e\"\n @mousedown=\"(e) => handleResizeStart(e, 'e')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--w\"\n @mousedown=\"(e) => handleResizeStart(e, 'w')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--ne\"\n @mousedown=\"(e) => handleResizeStart(e, 'ne')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--nw\"\n @mousedown=\"(e) => handleResizeStart(e, 'nw')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--se\"\n @mousedown=\"(e) => handleResizeStart(e, 'se')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--sw\"\n @mousedown=\"(e) => handleResizeStart(e, 'sw')\"\n ></div>\n </template>\n </div>\n </div>\n </Teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, onMounted, onUnmounted } from 'vue';\nimport { X, Minus, Maximize2 } from 'lucide-vue-next';\nimport { useWindowDrag } from '../composables/useWindowDrag';\nimport { useWindowResize } from '../composables/useWindowResize';\n\ninterface Props {\n title?: string;\n showTitleBar?: boolean;\n showMinimize?: boolean;\n showMaximize?: boolean;\n draggable?: boolean;\n resizable?: boolean;\n /** 窗口宽度,'auto' 表示自适应内容,'fit-content' 也表示自适应 */\n width?: string | number;\n /** 窗口高度,'auto' 表示自适应内容,'fit-content' 也表示自适应 */\n height?: string | number;\n minWidth?: string | number;\n minHeight?: string | number;\n maxWidth?: string | number;\n maxHeight?: string | number;\n closeOnBackdrop?: boolean;\n /** 是否自适应内容大小(不使用固定初始尺寸) */\n fitContent?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showTitleBar: true,\n showMinimize: false,\n showMaximize: false,\n draggable: true,\n resizable: true,\n closeOnBackdrop: true,\n width: 'auto',\n height: 'auto',\n minWidth: 300,\n minHeight: 200,\n maxWidth: '80vw',\n maxHeight: '80vh',\n fitContent: false\n});\n\nconst emit = defineEmits<{\n close: [];\n minimize: [];\n maximize: [];\n}>();\n\nconst windowContainerRef = ref<HTMLElement | null>(null);\nconst windowDrag = props.draggable ? useWindowDrag() : null;\n\n/**\n * 是否使用自适应内容模式\n */\nconst isAutoSize = computed(() => {\n return props.fitContent || \n props.width === 'auto' || \n props.width === 'fit-content' ||\n props.height === 'auto' ||\n props.height === 'fit-content';\n});\n\n/**\n * 计算初始尺寸\n */\nconst getInitialSize = () => {\n // 自适应模式不设置固定初始尺寸\n if (isAutoSize.value) {\n return { initialWidth: 0, initialHeight: 0 };\n }\n \n const defaultWidth = 600;\n const defaultHeight = 500;\n \n let initialWidth = defaultWidth;\n let initialHeight = defaultHeight;\n \n if (props.width !== 'auto' && props.width !== 'fit-content') {\n initialWidth = typeof props.width === 'number' ? props.width : parseInt(props.width);\n }\n if (props.height !== 'auto' && props.height !== 'fit-content') {\n initialHeight = typeof props.height === 'number' ? props.height : parseInt(props.height);\n }\n \n return { initialWidth, initialHeight };\n};\n\n/**\n * 解析尺寸限制\n */\nconst parseSize = (size: string | number, defaultPx: number): number => {\n if (typeof size === 'number') return size;\n if (size.endsWith('px')) return parseInt(size);\n if (size.endsWith('vw')) return (parseInt(size) / 100) * window.innerWidth;\n if (size.endsWith('vh')) return (parseInt(size) / 100) * window.innerHeight;\n return defaultPx;\n};\n\nconst { initialWidth, initialHeight } = getInitialSize();\nconst minW = parseSize(props.minWidth, 500);\nconst minH = parseSize(props.minHeight, 350);\nconst maxW = parseSize(props.maxWidth, window.innerWidth * 0.8);\nconst maxH = parseSize(props.maxHeight, window.innerHeight * 0.8);\n\nconst windowResize = props.resizable \n ? useWindowResize(initialWidth, initialHeight, minW, minH, maxW, maxH)\n : null;\n\nconst windowStyle = computed(() => {\n const baseStyle: Record<string, string> = {\n left: '50%',\n top: '50%',\n };\n\n // 计算位置和缩放(组合 transform)\n let translateX = '-50%';\n let translateY = '-50%';\n \n if (props.draggable && windowDrag) {\n translateX = `calc(-50% + ${windowDrag.position.value.x}px)`;\n translateY = `calc(-50% + ${windowDrag.position.value.y}px)`;\n }\n \n baseStyle.transform = `translate(${translateX}, ${translateY})`;\n baseStyle.transformOrigin = 'center center';\n\n // 自适应模式:不设置固定宽高,让内容决定\n if (isAutoSize.value) {\n // 只有在用户手动调整过大小时才应用\n if (props.resizable && windowResize && windowResize.width.value > 0) {\n baseStyle.width = `${windowResize.width.value}px`;\n baseStyle.height = `${windowResize.height.value}px`;\n }\n // 否则不设置 width/height,让 CSS fit-content 生效\n } else {\n // 固定尺寸模式\n if (props.resizable && windowResize) {\n baseStyle.width = `${windowResize.width.value}px`;\n baseStyle.height = `${windowResize.height.value}px`;\n } else {\n if (props.width !== 'auto' && props.width !== 'fit-content') {\n baseStyle.width = typeof props.width === 'number' ? `${props.width}px` : props.width;\n }\n if (props.height !== 'auto' && props.height !== 'fit-content') {\n baseStyle.height = typeof props.height === 'number' ? `${props.height}px` : props.height;\n }\n }\n }\n \n if (props.minWidth) {\n baseStyle.minWidth = typeof props.minWidth === 'number' ? `${props.minWidth}px` : props.minWidth;\n }\n if (props.minHeight) {\n baseStyle.minHeight = typeof props.minHeight === 'number' ? `${props.minHeight}px` : props.minHeight;\n }\n if (props.maxWidth) {\n baseStyle.maxWidth = typeof props.maxWidth === 'number' ? `${props.maxWidth}px` : props.maxWidth;\n }\n if (props.maxHeight) {\n baseStyle.maxHeight = typeof props.maxHeight === 'number' ? `${props.maxHeight}px` : props.maxHeight;\n }\n\n return baseStyle;\n});\n\nconst handleBackdropClick = (e: MouseEvent) => {\n if (props.closeOnBackdrop && e.target === e.currentTarget) {\n emit('close');\n }\n};\n\nconst handleDragStart = (e: MouseEvent) => {\n if (props.draggable && windowDrag) {\n windowDrag.startDrag(e);\n }\n};\n\nconst handleClose = () => {\n emit('close');\n};\n\nconst handleMinimize = () => {\n emit('minimize');\n};\n\nconst handleMaximize = () => {\n emit('maximize');\n};\n\nconst handleResizeStart = (e: MouseEvent, direction: 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw') => {\n if (!props.resizable || !windowResize || !windowContainerRef.value) return;\n \n const rect = windowContainerRef.value.getBoundingClientRect();\n const currentWidth = rect.width;\n const currentHeight = rect.height;\n \n windowResize.startResize(e, direction, currentWidth, currentHeight);\n};\n\n/**\n * ESC 键关闭\n */\nonMounted(() => {\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n emit('close');\n }\n };\n window.addEventListener('keydown', handleEsc);\n \n onUnmounted(() => {\n window.removeEventListener('keydown', handleEsc);\n });\n});\n</script>\n\n<style scoped>\n.window-overlay {\n position: fixed;\n inset: 0;\n z-index: 100;\n background: rgba(0, 0, 0, 0.3);\n animation: fade-in 200ms ease-out;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.window-container {\n position: absolute;\n display: flex;\n flex-direction: column;\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(24px);\n border: 1px solid rgb(229, 231, 233);\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n border-radius: 0.5rem;\n overflow: hidden;\n animation: window-fade-in 200ms ease-out;\n}\n\n.window-title-bar {\n height: 2.5rem;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0 0.75rem;\n border-bottom: 1px solid rgb(229, 231, 233);\n flex-shrink: 0;\n user-select: none;\n background: rgba(249, 250, 251, 0.8);\n z-index: 20;\n cursor: grab;\n}\n\n.window-title-bar:active {\n cursor: grabbing;\n}\n\n.window-controls {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.window-control-button {\n width: 0.75rem;\n height: 0.75rem;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid;\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n outline: none;\n cursor: pointer;\n padding: 0;\n background: transparent;\n flex-shrink: 0;\n position: relative;\n}\n\n.window-control-button svg {\n width: 7px !important;\n height: 7px !important;\n display: block;\n flex-shrink: 0;\n}\n\n.window-control-button .window-control-icon {\n width: 7px !important;\n height: 7px !important;\n min-width: 7px;\n min-height: 7px;\n}\n\n.window-control-button--close {\n background-color: rgb(255, 95, 87);\n border-color: rgb(224, 68, 62);\n}\n\n.window-control-button--minimize {\n background-color: rgb(254, 188, 46);\n border-color: rgb(216, 158, 36);\n}\n\n.window-control-button--maximize {\n background-color: rgb(40, 200, 64);\n border-color: rgb(26, 171, 41);\n}\n\n.window-control-icon {\n color: rgba(0, 0, 0, 0.5);\n opacity: 0;\n transition: opacity 200ms;\n width: 7px;\n height: 7px;\n flex-shrink: 0;\n}\n\n.window-controls:hover .window-control-icon {\n opacity: 1;\n}\n\n.window-control-button--close:hover {\n background-color: rgba(255, 95, 87, 0.8);\n}\n\n.window-control-button--minimize:hover {\n background-color: rgba(254, 188, 46, 0.8);\n}\n\n.window-control-button--maximize:hover {\n background-color: rgba(40, 200, 64, 0.8);\n}\n\n.window-title-info {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1;\n margin: 0 1rem;\n overflow: hidden;\n pointer-events: none;\n}\n\n.window-title-text {\n font-weight: 500;\n font-size: 0.75rem;\n color: rgb(75, 85, 99);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n width: 100%;\n text-align: center;\n}\n\n.window-title-actions {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n min-width: 4rem;\n flex-shrink: 0;\n}\n\n.window-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n/* Resize Handles */\n.window-resize-handle {\n position: absolute;\n background: transparent;\n z-index: 30;\n}\n\n.window-resize-handle--n {\n top: 0;\n left: 0;\n right: 0;\n height: 4px;\n cursor: n-resize;\n}\n\n.window-resize-handle--s {\n bottom: 0;\n left: 0;\n right: 0;\n height: 4px;\n cursor: s-resize;\n}\n\n.window-resize-handle--e {\n top: 0;\n right: 0;\n bottom: 0;\n width: 4px;\n cursor: e-resize;\n}\n\n.window-resize-handle--w {\n top: 0;\n left: 0;\n bottom: 0;\n width: 4px;\n cursor: w-resize;\n}\n\n.window-resize-handle--ne {\n top: 0;\n right: 0;\n width: 8px;\n height: 8px;\n cursor: ne-resize;\n}\n\n.window-resize-handle--nw {\n top: 0;\n left: 0;\n width: 8px;\n height: 8px;\n cursor: nw-resize;\n}\n\n.window-resize-handle--se {\n bottom: 0;\n right: 0;\n width: 8px;\n height: 8px;\n cursor: se-resize;\n}\n\n.window-resize-handle--sw {\n bottom: 0;\n left: 0;\n width: 8px;\n height: 8px;\n cursor: sw-resize;\n}\n\n@keyframes fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@keyframes window-fade-in {\n from {\n opacity: 0;\n transform: translate(-50%, -50%) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n}\n</style>\n","<template>\n <Teleport to=\"body\">\n <div v-if=\"visible\" class=\"compress-dialog-overlay\" @click=\"emit('cancel')\">\n <div class=\"compress-dialog\" @click.stop>\n <!-- 头部 -->\n <div class=\"compress-dialog-header\">\n <div class=\"compress-dialog-title\">\n <Archive :size=\"20\" />\n <span>压缩文件</span>\n </div>\n <button class=\"compress-dialog-close\" @click=\"emit('cancel')\">\n <X :size=\"18\" />\n </button>\n </div>\n\n <!-- 内容 -->\n <div class=\"compress-dialog-content\">\n <!-- 文件信息 -->\n <div class=\"compress-dialog-info\">\n <FileArchive :size=\"16\" />\n <span>{{ fileDisplayName }}</span>\n </div>\n\n <!-- 输出文件名 -->\n <div class=\"compress-dialog-field\">\n <label>文件名</label>\n <div class=\"compress-dialog-input-group\">\n <input\n type=\"text\"\n v-model=\"outputName\"\n placeholder=\"输入文件名\"\n />\n <span class=\"compress-dialog-ext\">{{ currentExt }}</span>\n </div>\n </div>\n\n <!-- 压缩格式 -->\n <div class=\"compress-dialog-field\">\n <label>压缩格式</label>\n <select v-model=\"format\">\n <option v-for=\"opt in FORMAT_OPTIONS\" :key=\"opt.value\" :value=\"opt.value\">\n {{ opt.label }}\n </option>\n </select>\n </div>\n\n <!-- 压缩级别 -->\n <div class=\"compress-dialog-field\">\n <label>压缩级别</label>\n <div class=\"compress-dialog-levels\">\n <label v-for=\"opt in LEVEL_OPTIONS\" :key=\"opt.value\" class=\"compress-dialog-level\">\n <input\n type=\"radio\"\n name=\"level\"\n :value=\"opt.value\"\n v-model=\"level\"\n />\n <span class=\"compress-dialog-level-label\">{{ opt.label }}</span>\n <span class=\"compress-dialog-level-desc\">{{ opt.desc }}</span>\n </label>\n </div>\n </div>\n\n <!-- 密码保护(仅 zip/7z) -->\n <div v-if=\"supportsPassword\" class=\"compress-dialog-field\">\n <label>密码保护(可选)</label>\n <div class=\"compress-dialog-input-group\">\n <input\n :type=\"showPassword ? 'text' : 'password'\"\n v-model=\"password\"\n placeholder=\"设置密码\"\n />\n <button\n type=\"button\"\n class=\"compress-dialog-toggle-password\"\n @click=\"showPassword = !showPassword\"\n >\n {{ showPassword ? '隐藏' : '显示' }}\n </button>\n </div>\n </div>\n\n <!-- 删除源文件选项 -->\n <div class=\"compress-dialog-field compress-dialog-checkbox\">\n <label>\n <input type=\"checkbox\" v-model=\"deleteSource\" />\n <span>压缩后删除源文件</span>\n </label>\n </div>\n\n <!-- 输出路径预览 -->\n <div class=\"compress-dialog-preview\">\n <span class=\"compress-dialog-preview-label\">输出位置:</span>\n <span class=\"compress-dialog-preview-path\">{{ fullOutputPath }}</span>\n </div>\n </div>\n\n <!-- 底部按钮 -->\n <div class=\"compress-dialog-footer\">\n <button class=\"compress-dialog-btn compress-dialog-btn-cancel\" @click=\"emit('cancel')\">\n 取消\n </button>\n <button \n class=\"compress-dialog-btn compress-dialog-btn-confirm\" \n @click=\"handleConfirm\"\n :disabled=\"!outputName.trim()\"\n >\n 压缩\n </button>\n </div>\n </div>\n </div>\n </Teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch } from 'vue';\nimport { Archive, FileArchive, X } from 'lucide-vue-next';\nimport type { CompressFormat, CompressLevel, CompressOptions } from '../types';\n\ntype CompressDialogOptions = Omit<CompressOptions, 'outputDir'>;\n\ninterface Props {\n visible: boolean;\n filePaths: string[];\n outputDir: string;\n}\n\nconst props = defineProps<Props>();\n\nconst emit = defineEmits<{\n confirm: [options: CompressDialogOptions];\n cancel: [];\n}>();\n\n/** 格式选项配置 */\nconst FORMAT_OPTIONS: { value: CompressFormat; label: string; ext: string }[] = [\n { value: 'zip', label: 'ZIP', ext: '.zip' },\n { value: 'tgz', label: 'TAR.GZ (gzip)', ext: '.tar.gz' },\n { value: 'tarbz2', label: 'TAR.BZ2 (bzip2)', ext: '.tar.bz2' },\n { value: 'tar', label: 'TAR (无压缩)', ext: '.tar' },\n];\n\n/** 压缩级别选项 */\nconst LEVEL_OPTIONS = [\n { value: 'fast', label: '快速', desc: '压缩速度快,文件较大' },\n { value: 'normal', label: '标准', desc: '平衡速度和大小' },\n { value: 'best', label: '最佳', desc: '文件最小,速度较慢' },\n] as const;\n\nconst format = ref<CompressFormat>('zip');\nconst level = ref<CompressLevel>('normal');\nconst outputName = ref('');\nconst deleteSource = ref(false);\nconst password = ref('');\nconst showPassword = ref(false);\n\n// 根据选中文件生成默认输出名称\nconst defaultOutputName = computed(() => {\n if (props.filePaths.length === 0) return 'archive';\n if (props.filePaths.length === 1) {\n const name = props.filePaths[0].split('/').pop() || 'archive';\n return name.replace(/\\.[^.]+$/, '');\n }\n return '压缩文件';\n});\n\n// 文件显示名称\nconst fileDisplayName = computed(() => {\n if (props.filePaths.length === 1) {\n return props.filePaths[0].split('/').pop();\n }\n return `${props.filePaths.length} 个项目`;\n});\n\n// 当前格式的扩展名\nconst currentExt = computed(() => {\n return FORMAT_OPTIONS.find(f => f.value === format.value)?.ext || '.zip';\n});\n\n// 完整输出路径预览\nconst fullOutputPath = computed(() => {\n return `${props.outputDir}/${outputName.value}${currentExt.value}`;\n});\n\n// 是否支持密码\nconst supportsPassword = computed(() => {\n // 当前后端未实现密码压缩,避免 UI 误导:直接关闭密码选项\n return false;\n});\n\n// 初始化\nwatch(() => props.visible, (visible) => {\n if (visible) {\n outputName.value = defaultOutputName.value;\n format.value = 'zip';\n level.value = 'normal';\n deleteSource.value = false;\n password.value = '';\n }\n});\n\nconst handleConfirm = () => {\n emit('confirm', {\n format: format.value,\n level: level.value,\n outputName: outputName.value + currentExt.value,\n deleteSource: deleteSource.value,\n });\n};\n</script>\n\n<style scoped>\n.compress-dialog-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n}\n\n.compress-dialog {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);\n width: 420px;\n max-width: 90vw;\n max-height: 90vh;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.compress-dialog-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid rgb(229, 231, 233);\n}\n\n.compress-dialog-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n font-size: 16px;\n color: rgb(17, 24, 39);\n}\n\n.compress-dialog-close {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: rgb(107, 114, 128);\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.compress-dialog-close:hover {\n background: rgb(243, 244, 246);\n color: rgb(55, 65, 81);\n}\n\n.compress-dialog-content {\n padding: 20px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.compress-dialog-info {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n background: rgb(249, 250, 251);\n border-radius: 8px;\n color: rgb(55, 65, 81);\n font-size: 14px;\n}\n\n.compress-dialog-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.compress-dialog-field > label {\n font-size: 13px;\n font-weight: 500;\n color: rgb(55, 65, 81);\n}\n\n.compress-dialog-input-group {\n display: flex;\n align-items: stretch;\n}\n\n.compress-dialog-input-group input {\n flex: 1;\n padding: 8px 12px;\n border: 1px solid rgb(209, 213, 219);\n border-radius: 6px 0 0 6px;\n font-size: 14px;\n outline: none;\n transition: border-color 0.2s;\n}\n\n.compress-dialog-input-group input:focus {\n border-color: rgb(59, 130, 246);\n}\n\n.compress-dialog-ext {\n padding: 8px 12px;\n background: rgb(243, 244, 246);\n border: 1px solid rgb(209, 213, 219);\n border-left: none;\n border-radius: 0 6px 6px 0;\n font-size: 14px;\n color: rgb(107, 114, 128);\n}\n\n.compress-dialog-toggle-password {\n padding: 8px 12px;\n background: rgb(243, 244, 246);\n border: 1px solid rgb(209, 213, 219);\n border-left: none;\n border-radius: 0 6px 6px 0;\n font-size: 12px;\n color: rgb(59, 130, 246);\n cursor: pointer;\n}\n\n.compress-dialog-toggle-password:hover {\n background: rgb(229, 231, 235);\n}\n\n.compress-dialog-field select {\n padding: 8px 12px;\n border: 1px solid rgb(209, 213, 219);\n border-radius: 6px;\n font-size: 14px;\n outline: none;\n background: white;\n cursor: pointer;\n}\n\n.compress-dialog-field select:focus {\n border-color: rgb(59, 130, 246);\n}\n\n.compress-dialog-levels {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.compress-dialog-level {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border: 1px solid rgb(229, 231, 233);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.compress-dialog-level:hover {\n background: rgb(249, 250, 251);\n}\n\n.compress-dialog-level:has(input:checked) {\n border-color: rgb(59, 130, 246);\n background: rgb(239, 246, 255);\n}\n\n.compress-dialog-level input {\n margin: 0;\n}\n\n.compress-dialog-level-label {\n font-size: 14px;\n font-weight: 500;\n color: rgb(17, 24, 39);\n}\n\n.compress-dialog-level-desc {\n font-size: 12px;\n color: rgb(107, 114, 128);\n margin-left: auto;\n}\n\n.compress-dialog-checkbox label {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n font-size: 14px;\n color: rgb(55, 65, 81);\n}\n\n.compress-dialog-checkbox input {\n margin: 0;\n width: 16px;\n height: 16px;\n}\n\n.compress-dialog-preview {\n padding: 10px 12px;\n background: rgb(249, 250, 251);\n border-radius: 6px;\n font-size: 12px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.compress-dialog-preview-label {\n color: rgb(107, 114, 128);\n}\n\n.compress-dialog-preview-path {\n color: rgb(55, 65, 81);\n word-break: break-all;\n}\n\n.compress-dialog-footer {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid rgb(229, 231, 233);\n}\n\n.compress-dialog-btn {\n padding: 8px 20px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.compress-dialog-btn-cancel {\n background: white;\n border: 1px solid rgb(209, 213, 219);\n color: rgb(55, 65, 81);\n}\n\n.compress-dialog-btn-cancel:hover {\n background: rgb(249, 250, 251);\n}\n\n.compress-dialog-btn-confirm {\n background: rgb(59, 130, 246);\n border: 1px solid rgb(59, 130, 246);\n color: white;\n}\n\n.compress-dialog-btn-confirm:hover {\n background: rgb(37, 99, 235);\n}\n\n.compress-dialog-btn-confirm:disabled {\n background: rgb(156, 163, 175);\n border-color: rgb(156, 163, 175);\n cursor: not-allowed;\n}\n</style>\n\n","<template>\n <Teleport to=\"body\">\n <div v-if=\"visible\" class=\"progress-dialog-overlay\">\n <div class=\"progress-dialog\">\n <!-- 头部 -->\n <div class=\"progress-dialog-header\">\n <div class=\"progress-dialog-title\">\n <component :is=\"statusIcon\" :size=\"24\" :class=\"statusIconClass\" />\n <span>{{ title }}</span>\n </div>\n <button v-if=\"isCompleted\" class=\"progress-dialog-close\" @click=\"handleClose\">\n <X :size=\"18\" />\n </button>\n </div>\n\n <!-- 内容 -->\n <div class=\"progress-dialog-content\">\n <!-- 状态文本 -->\n <div class=\"progress-dialog-status\">{{ statusText }}</div>\n\n <!-- 进度条 -->\n <div v-if=\"progress.status === 'processing'\" class=\"progress-dialog-bar-container\">\n <div class=\"progress-dialog-bar\">\n <div \n class=\"progress-dialog-bar-fill\"\n :style=\"{ width: `${progress.percent}%` }\"\n />\n </div>\n <span class=\"progress-dialog-percent\">{{ progress.percent }}%</span>\n </div>\n\n <!-- 当前文件 -->\n <div v-if=\"progress.currentFile && progress.status === 'processing'\" class=\"progress-dialog-current-file\">\n {{ progress.currentFile }}\n </div>\n\n <!-- 文件计数 -->\n <div v-if=\"progress.totalCount && progress.totalCount > 0 && progress.status === 'processing'\" class=\"progress-dialog-count\">\n {{ progress.processedCount || 0 }} / {{ progress.totalCount }} 个文件\n </div>\n\n <!-- 错误信息 -->\n <div v-if=\"progress.error\" class=\"progress-dialog-error\">\n {{ progress.error }}\n </div>\n\n <!-- 成功后显示输出路径 -->\n <div v-if=\"progress.status === 'success' && progress.outputPath\" class=\"progress-dialog-output\">\n <span class=\"progress-dialog-output-label\">输出位置:</span>\n <span class=\"progress-dialog-output-path\">{{ progress.outputPath }}</span>\n </div>\n </div>\n\n <!-- 底部按钮 -->\n <div class=\"progress-dialog-footer\">\n <button \n v-if=\"progress.status === 'processing'\" \n class=\"progress-dialog-btn progress-dialog-btn-cancel\" \n @click=\"emit('cancel')\"\n >\n 取消\n </button>\n <button \n v-if=\"progress.status === 'success' && progress.outputPath\"\n class=\"progress-dialog-btn progress-dialog-btn-folder\" \n @click=\"emit('openFolder', progress.outputPath!)\"\n >\n <FolderOpen :size=\"16\" />\n 打开文件夹\n </button>\n <button \n v-if=\"isCompleted\"\n class=\"progress-dialog-btn progress-dialog-btn-close\" \n @click=\"handleClose\"\n >\n 关闭\n </button>\n </div>\n </div>\n </div>\n </Teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { X, Loader2, CheckCircle, XCircle, Archive, FolderOpen } from 'lucide-vue-next';\n\n/** 进度状态 */\nexport type ProgressStatus = 'pending' | 'processing' | 'success' | 'error';\n\n/** 进度信息 */\nexport interface ProgressInfo {\n type: 'compress' | 'extract';\n status: ProgressStatus;\n percent: number;\n currentFile?: string;\n processedCount?: number;\n totalCount?: number;\n error?: string;\n outputPath?: string;\n}\n\ninterface Props {\n visible: boolean;\n progress: ProgressInfo;\n}\n\nconst props = defineProps<Props>();\n\nconst emit = defineEmits<{\n cancel: [];\n close: [];\n openFolder: [path: string];\n}>();\n\nconst title = computed(() => props.progress.type === 'compress' ? '压缩文件' : '解压文件');\nconst isCompleted = computed(() => props.progress.status === 'success' || props.progress.status === 'error');\n\nconst statusIcon = computed(() => {\n switch (props.progress.status) {\n case 'processing': return Loader2;\n case 'success': return CheckCircle;\n case 'error': return XCircle;\n default: return Archive;\n }\n});\n\nconst statusIconClass = computed(() => {\n switch (props.progress.status) {\n case 'processing': return 'progress-dialog-icon-spin';\n case 'success': return 'progress-dialog-icon-success';\n case 'error': return 'progress-dialog-icon-error';\n default: return '';\n }\n});\n\nconst statusText = computed(() => {\n switch (props.progress.status) {\n case 'pending': return '准备中...';\n case 'processing': return props.progress.type === 'compress' ? '正在压缩...' : '正在解压...';\n case 'success': return props.progress.type === 'compress' ? '压缩完成' : '解压完成';\n case 'error': return '操作失败';\n default: return '';\n }\n});\n\nconst handleClose = () => {\n if (isCompleted.value) {\n emit('close');\n } else {\n emit('cancel');\n }\n};\n</script>\n\n<style scoped>\n.progress-dialog-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10001;\n}\n\n.progress-dialog {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);\n width: 380px;\n max-width: 90vw;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.progress-dialog-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid rgb(229, 231, 233);\n}\n\n.progress-dialog-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-weight: 600;\n font-size: 16px;\n color: rgb(17, 24, 39);\n}\n\n.progress-dialog-close {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: rgb(107, 114, 128);\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.progress-dialog-close:hover {\n background: rgb(243, 244, 246);\n color: rgb(55, 65, 81);\n}\n\n.progress-dialog-content {\n padding: 24px 20px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.progress-dialog-status {\n font-size: 14px;\n color: rgb(55, 65, 81);\n text-align: center;\n}\n\n.progress-dialog-bar-container {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.progress-dialog-bar {\n flex: 1;\n height: 8px;\n background: rgb(229, 231, 233);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.progress-dialog-bar-fill {\n height: 100%;\n background: rgb(59, 130, 246);\n border-radius: 4px;\n transition: width 0.3s ease;\n}\n\n.progress-dialog-percent {\n font-size: 13px;\n font-weight: 500;\n color: rgb(55, 65, 81);\n min-width: 40px;\n text-align: right;\n}\n\n.progress-dialog-current-file {\n font-size: 12px;\n color: rgb(107, 114, 128);\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.progress-dialog-count {\n font-size: 12px;\n color: rgb(107, 114, 128);\n text-align: center;\n}\n\n.progress-dialog-error {\n padding: 12px;\n background: rgb(254, 242, 242);\n border: 1px solid rgb(254, 202, 202);\n border-radius: 6px;\n color: rgb(185, 28, 28);\n font-size: 13px;\n}\n\n.progress-dialog-output {\n padding: 12px;\n background: rgb(240, 253, 244);\n border: 1px solid rgb(187, 247, 208);\n border-radius: 6px;\n font-size: 12px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.progress-dialog-output-label {\n color: rgb(22, 101, 52);\n font-weight: 500;\n}\n\n.progress-dialog-output-path {\n color: rgb(21, 128, 61);\n word-break: break-all;\n}\n\n.progress-dialog-footer {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid rgb(229, 231, 233);\n}\n\n.progress-dialog-btn {\n padding: 8px 16px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.progress-dialog-btn-cancel {\n background: white;\n border: 1px solid rgb(209, 213, 219);\n color: rgb(55, 65, 81);\n}\n\n.progress-dialog-btn-cancel:hover {\n background: rgb(249, 250, 251);\n}\n\n.progress-dialog-btn-folder {\n background: rgb(240, 253, 244);\n border: 1px solid rgb(187, 247, 208);\n color: rgb(22, 101, 52);\n}\n\n.progress-dialog-btn-folder:hover {\n background: rgb(220, 252, 231);\n}\n\n.progress-dialog-btn-close {\n background: rgb(59, 130, 246);\n border: 1px solid rgb(59, 130, 246);\n color: white;\n}\n\n.progress-dialog-btn-close:hover {\n background: rgb(37, 99, 235);\n}\n\n/* 旋转动画 */\n.progress-dialog-icon-spin {\n animation: spin 1s linear infinite;\n color: rgb(59, 130, 246);\n}\n\n@keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n\n.progress-dialog-icon-success {\n color: rgb(34, 197, 94);\n}\n\n.progress-dialog-icon-error {\n color: rgb(239, 68, 68);\n}\n</style>\n\n","<!--\n FileInfoDialog - 文件信息弹窗组件\n 显示文件/文件夹的详细信息\n-->\n<template>\n <Teleport to=\"body\">\n <div v-if=\"visible && item\" class=\"file-info-dialog-overlay\" @click=\"handleBackdropClick\">\n <div class=\"file-info-dialog\">\n <!-- 头部 -->\n <div class=\"file-info-dialog-header\">\n <div class=\"file-info-dialog-title\">\n <Icon :icon=\"getFileIcon(item.type, item.name)\" width=\"48\" height=\"48\" class=\"file-info-icon\" :class=\"getIconClass(item.type)\" />\n <span class=\"file-info-dialog-name\" :title=\"item.name\">\n {{ item.name }}\n </span>\n </div>\n <button class=\"file-info-dialog-close\" @click=\"emit('close')\">\n <X :size=\"18\" />\n </button>\n </div>\n\n <!-- 内容 -->\n <div class=\"file-info-dialog-content\">\n <!-- 类型 -->\n <div class=\"file-info-row\">\n <div class=\"file-info-label\">\n <File :size=\"14\" />\n <span>类型</span>\n </div>\n <div class=\"file-info-value\">\n {{ getFileTypeName(item.type, extension) }}\n </div>\n </div>\n\n <!-- 大小 -->\n <div v-if=\"item.type !== FileType.FOLDER && item.size\" class=\"file-info-row\">\n <div class=\"file-info-label\">\n <HardDrive :size=\"14\" />\n <span>大小</span>\n </div>\n <div class=\"file-info-value\">\n {{ item.size }}\n </div>\n </div>\n\n <!-- 位置 -->\n <div class=\"file-info-row\">\n <div class=\"file-info-label\">\n <MapPin :size=\"14\" />\n <span>位置</span>\n </div>\n <div class=\"file-info-value file-info-value--path\" :title=\"directory\">\n {{ directory }}\n </div>\n </div>\n\n <!-- 完整路径 -->\n <div class=\"file-info-row\">\n <div class=\"file-info-label\">\n <MapPin :size=\"14\" />\n <span>完整路径</span>\n </div>\n <div class=\"file-info-value file-info-value--path\" :title=\"item.id\">\n {{ item.id }}\n </div>\n </div>\n\n <!-- 修改时间 -->\n <div v-if=\"item.dateModified\" class=\"file-info-row\">\n <div class=\"file-info-label\">\n <Clock :size=\"14\" />\n <span>修改时间</span>\n </div>\n <div class=\"file-info-value\">\n {{ item.dateModified }}\n </div>\n </div>\n </div>\n\n <!-- 底部按钮 -->\n <div class=\"file-info-dialog-footer\">\n <button class=\"file-info-dialog-btn\" @click=\"emit('close')\">\n 关闭\n </button>\n </div>\n </div>\n </div>\n </Teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onMounted, onUnmounted } from 'vue';\nimport { Icon } from '@iconify/vue';\nimport { \n File, \n Image, \n Video, \n Music, \n FileText, \n Code,\n Archive,\n X,\n MapPin,\n HardDrive,\n Clock\n} from 'lucide-vue-next';\nimport { FileType, type FileItem } from '../types';\nimport { getFileTypeIcon } from '../utils/fileTypeIcon';\n\nconst props = defineProps<{\n /** 是否显示 */\n visible: boolean;\n /** 文件项 */\n item: FileItem | null;\n}>();\n\nconst emit = defineEmits<{\n close: [];\n}>();\n\n/** 获取文件类型图标 */\nfunction getFileIcon(type: FileType, name?: string): string {\n // 文件夹使用 material-icon-theme:folder\n if (type === FileType.FOLDER) {\n return 'flat-color-icons:folder';\n }\n \n // 如果有文件名,使用 material-icon-theme 图标映射(传递 type 作为兜底)\n if (name) {\n return getFileTypeIcon(name, type);\n }\n \n // 回退逻辑(没有文件名时)\n switch (type) {\n case FileType.IMAGE: return 'material-icon-theme:image';\n case FileType.VIDEO: return 'material-icon-theme:video';\n case FileType.MUSIC: return 'material-icon-theme:audio';\n case FileType.DOCUMENT: return 'material-icon-theme:word';\n case FileType.CODE: return 'material-icon-theme:javascript';\n case FileType.ARCHIVE: return 'material-icon-theme:zip';\n default: return 'material-icon-theme:document';\n }\n}\n\n/** 获取图标样式类 */\nfunction getIconClass(type: FileType): string {\n switch (type) {\n case FileType.FOLDER: return 'file-info-icon--folder';\n case FileType.IMAGE: return 'file-info-icon--image';\n case FileType.VIDEO: return 'file-info-icon--video';\n case FileType.MUSIC: return 'file-info-icon--music';\n case FileType.DOCUMENT: return 'file-info-icon--document';\n case FileType.CODE: return 'file-info-icon--code';\n case FileType.ARCHIVE: return 'file-info-icon--archive';\n default: return 'file-info-icon--file';\n }\n}\n\n/** 获取文件类型名称 */\nfunction getFileTypeName(type: FileType, ext?: string): string {\n switch (type) {\n case FileType.FOLDER: return '文件夹';\n case FileType.IMAGE: return `图片${ext ? ` (${ext.toUpperCase()})` : ''}`;\n case FileType.VIDEO: return `视频${ext ? ` (${ext.toUpperCase()})` : ''}`;\n case FileType.MUSIC: return `音频${ext ? ` (${ext.toUpperCase()})` : ''}`;\n case FileType.DOCUMENT: return `文档${ext ? ` (${ext.toUpperCase()})` : ''}`;\n case FileType.CODE: return `代码文件${ext ? ` (${ext.toUpperCase()})` : ''}`;\n case FileType.ARCHIVE: return `压缩包${ext ? ` (${ext.toUpperCase()})` : ''}`;\n default: return ext ? `${ext.toUpperCase()} 文件` : '文件';\n }\n}\n\n/** 获取文件扩展名 */\nconst extension = computed(() => {\n if (!props.item) return undefined;\n const lastDot = props.item.name.lastIndexOf('.');\n if (lastDot === -1 || lastDot === 0) return undefined;\n return props.item.name.substring(lastDot + 1).toLowerCase();\n});\n\n/** 获取文件所在目录 */\nconst directory = computed(() => {\n if (!props.item) return '';\n const lastSlash = props.item.id.lastIndexOf('/');\n if (lastSlash === -1) return props.item.id;\n return props.item.id.substring(0, lastSlash) || '/';\n});\n\n/** 点击背景关闭 */\nfunction handleBackdropClick(e: MouseEvent) {\n if (e.target === e.currentTarget) {\n emit('close');\n }\n}\n\n/** ESC 关闭 */\nfunction handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape' && props.visible) {\n emit('close');\n }\n}\n\nonMounted(() => {\n document.addEventListener('keydown', handleKeyDown);\n});\n\nonUnmounted(() => {\n document.removeEventListener('keydown', handleKeyDown);\n});\n</script>\n\n<style scoped>\n/* FileInfoDialog 样式 */\n\n.file-info-dialog-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n animation: file-info-fadeIn 0.15s ease-out;\n}\n\n@keyframes file-info-fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.file-info-dialog {\n background: #ffffff;\n border: 1px solid #e0e0e0;\n border-radius: 12px;\n width: 420px;\n max-width: 90vw;\n max-height: 80vh;\n display: flex;\n flex-direction: column;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15), 0 2px 8px rgba(0, 0, 0, 0.1);\n animation: file-info-slideIn 0.2s ease-out;\n}\n\n@keyframes file-info-slideIn {\n from {\n opacity: 0;\n transform: scale(0.95) translateY(-10px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n\n/* 深色模式 */\n@media (prefers-color-scheme: dark) {\n .file-info-dialog {\n background: #2d2d2d;\n border-color: #404040;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n }\n}\n\n/* 头部 */\n.file-info-dialog-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid #e0e0e0;\n gap: 12px;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-dialog-header {\n border-bottom-color: #404040;\n }\n}\n\n.file-info-dialog-title {\n display: flex;\n align-items: center;\n gap: 10px;\n min-width: 0;\n flex: 1;\n}\n\n.file-info-dialog-name {\n font-size: 16px;\n font-weight: 600;\n color: #1a1a1a;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-dialog-name {\n color: #e0e0e0;\n }\n}\n\n.file-info-dialog-close {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: #666;\n border-radius: 6px;\n cursor: pointer;\n flex-shrink: 0;\n transition: all 0.15s ease;\n}\n\n.file-info-dialog-close:hover {\n background: #f0f0f0;\n color: #333;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-dialog-close {\n color: #888;\n }\n .file-info-dialog-close:hover {\n background: #404040;\n color: #e0e0e0;\n }\n}\n\n/* 内容 */\n.file-info-dialog-content {\n padding: 16px 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n overflow-y: auto;\n}\n\n.file-info-row {\n display: flex;\n align-items: flex-start;\n gap: 16px;\n}\n\n.file-info-label {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 90px;\n flex-shrink: 0;\n color: #666;\n font-size: 13px;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-label {\n color: #888;\n }\n}\n\n.file-info-label svg {\n flex-shrink: 0;\n}\n\n.file-info-value {\n flex: 1;\n color: #1a1a1a;\n font-size: 13px;\n word-break: break-all;\n line-height: 1.4;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-value {\n color: #e0e0e0;\n }\n}\n\n.file-info-value--path {\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', monospace;\n font-size: 12px;\n background: #f5f5f5;\n padding: 4px 8px;\n border-radius: 4px;\n user-select: all;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-value--path {\n background: #383838;\n }\n}\n\n/* 图标样式 */\n.file-info-icon {\n width: 32px;\n height: 32px;\n flex-shrink: 0;\n}\n\n.file-info-icon--folder {\n color: #dcb67a;\n}\n\n.file-info-icon--image {\n color: #7ec699;\n}\n\n.file-info-icon--video {\n color: #c678dd;\n}\n\n.file-info-icon--music {\n color: #e06c75;\n}\n\n.file-info-icon--document {\n color: #61afef;\n}\n\n.file-info-icon--code {\n color: #98c379;\n}\n\n.file-info-icon--archive {\n color: #d19a66;\n}\n\n.file-info-icon--file {\n color: #abb2bf;\n}\n\n/* 底部 */\n.file-info-dialog-footer {\n display: flex;\n justify-content: flex-end;\n padding: 12px 20px;\n border-top: 1px solid #e0e0e0;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-dialog-footer {\n border-top-color: #404040;\n }\n}\n\n.file-info-dialog-btn {\n padding: 6px 16px;\n border: none;\n border-radius: 6px;\n font-size: 13px;\n cursor: pointer;\n transition: all 0.15s ease;\n background: #007aff;\n color: white;\n}\n\n.file-info-dialog-btn:hover {\n background: #0066d6;\n}\n</style>\n\n","import { ref } from 'vue';\nimport type { FileItem } from '../types';\n\n/**\n * 文件选择状态管理\n */\nexport function useSelection() {\n const selectedIds = ref<Set<string>>(new Set());\n const lastSelectedId = ref<string | null>(null);\n const editingId = ref<string | null>(null);\n\n /**\n * 清除选择\n */\n const clearSelection = () => {\n selectedIds.value = new Set();\n lastSelectedId.value = null;\n };\n\n /**\n * 选择项目\n * @param id 项目 ID(null 表示清除选择)\n * @param items 当前显示的项目列表\n * @param multi 是否多选(Cmd/Ctrl)\n * @param range 是否范围选择(Shift)\n */\n const selectItem = (\n id: string | null, \n items: FileItem[],\n multi: boolean = false, \n range: boolean = false\n ) => {\n if (!id) {\n clearSelection();\n return;\n }\n\n // 范围选择\n if (range && lastSelectedId.value) {\n const indexA = items.findIndex(i => i.id === lastSelectedId.value);\n const indexB = items.findIndex(i => i.id === id);\n \n if (indexA !== -1 && indexB !== -1) {\n const start = Math.min(indexA, indexB);\n const end = Math.max(indexA, indexB);\n const newSet = new Set(multi ? selectedIds.value : []);\n for (let i = start; i <= end; i++) {\n const item = items[i];\n if (item) {\n newSet.add(item.id);\n }\n }\n selectedIds.value = newSet;\n return;\n }\n }\n\n // 多选切换\n if (multi) {\n const newSet = new Set(selectedIds.value);\n if (newSet.has(id)) {\n newSet.delete(id);\n } else {\n newSet.add(id);\n }\n lastSelectedId.value = id;\n selectedIds.value = newSet;\n return;\n }\n\n // 单选\n lastSelectedId.value = id;\n selectedIds.value = new Set([id]);\n };\n\n /**\n * 全选\n */\n const selectAll = (items: FileItem[]) => {\n selectedIds.value = new Set(items.map(i => i.id));\n };\n\n /**\n * 设置编辑状态\n */\n const setEditing = (id: string | null) => {\n editingId.value = id;\n };\n\n /**\n * 检查是否选中\n */\n const isSelected = (id: string): boolean => {\n return selectedIds.value.has(id);\n };\n\n return {\n selectedIds,\n lastSelectedId,\n editingId,\n clearSelection,\n selectItem,\n selectAll,\n setEditing,\n isSelected\n };\n}\n","import { ref } from 'vue';\nimport type { FileItem } from '../types';\nimport { FileType } from '../types';\n\n/**\n * 拖拽操作管理\n */\nexport function useDragAndDrop(\n getSelectedIds: () => Set<string>,\n onSelect: (id: string, multi: boolean, range: boolean) => void,\n onMove: (targetFolderId: string, itemIds: Set<string>) => void\n) {\n const dragOverId = ref<string | null>(null);\n const isDragging = ref(false);\n\n /**\n * 开始拖拽\n */\n const handleDragStart = (e: DragEvent, itemId: string) => {\n if (!e.dataTransfer) return;\n \n const selectedIds = getSelectedIds();\n \n // 如果拖拽的项目未被选中,先选中它\n if (!selectedIds.has(itemId)) {\n onSelect(itemId, false, false);\n }\n\n // 设置拖拽数据\n const draggedIds = selectedIds.has(itemId) ? selectedIds : new Set([itemId]);\n e.dataTransfer.setData('text/plain', JSON.stringify([...draggedIds]));\n e.dataTransfer.effectAllowed = 'move';\n \n isDragging.value = true;\n };\n\n /**\n * 拖拽经过\n */\n const handleDragOver = (e: DragEvent, item: FileItem) => {\n if (!isDragging.value) return;\n \n // 只有文件夹可以作为放置目标\n if (item.type === FileType.FOLDER) {\n const selectedIds = getSelectedIds();\n // 不能拖拽到自己身上\n if (!selectedIds.has(item.id)) {\n e.preventDefault();\n dragOverId.value = item.id;\n }\n }\n };\n\n /**\n * 拖拽离开\n */\n const handleDragLeave = () => {\n dragOverId.value = null;\n };\n\n /**\n * 放置\n */\n const handleDrop = (e: DragEvent, targetItem: FileItem) => {\n dragOverId.value = null;\n isDragging.value = false;\n\n if (!e.dataTransfer || targetItem.type !== FileType.FOLDER) return;\n\n const data = e.dataTransfer.getData('text/plain');\n if (!data) return;\n\n try {\n const draggedIds: string[] = JSON.parse(data);\n const itemIds = new Set(draggedIds);\n \n // 不能移动到自己\n if (itemIds.has(targetItem.id)) return;\n \n onMove(targetItem.id, itemIds);\n } catch {\n // 忽略解析错误\n }\n };\n\n /**\n * 拖拽结束\n */\n const handleDragEnd = () => {\n dragOverId.value = null;\n isDragging.value = false;\n };\n\n return {\n dragOverId,\n isDragging,\n handleDragStart,\n handleDragOver,\n handleDragLeave,\n handleDrop,\n handleDragEnd\n };\n}\n","import { ref, nextTick } from 'vue';\nimport { FileType } from '../types';\n\n/**\n * 媒体播放器功能管理\n */\nexport function useMediaPlayer(\n mediaType: FileType,\n mediaRef: () => HTMLVideoElement | HTMLAudioElement | null\n) {\n const isPlaying = ref(false);\n const progress = ref(0);\n const currentTime = ref(0);\n const duration = ref(0);\n const isMuted = ref(false);\n const volume = ref(1);\n const lastVolume = ref(1);\n const showControls = ref(false);\n\n const isAudio = mediaType === FileType.MUSIC;\n\n /**\n * 更新播放进度\n */\n const updateProgress = () => {\n const media = mediaRef();\n if (media) {\n const curr = media.currentTime;\n const dur = media.duration;\n currentTime.value = curr;\n if (dur && !isNaN(dur)) {\n duration.value = dur;\n progress.value = (curr / dur) * 100;\n }\n }\n };\n\n /**\n * 切换播放/暂停\n */\n const togglePlay = () => {\n const media = mediaRef();\n if (media) {\n if (isPlaying.value) {\n media.pause();\n isPlaying.value = false;\n } else {\n media.play();\n isPlaying.value = true;\n }\n }\n };\n\n /**\n * 切换静音\n */\n const toggleMute = () => {\n const media = mediaRef();\n if (media) {\n if (isMuted.value) {\n const volToRestore = lastVolume.value || 1;\n media.volume = volToRestore;\n media.muted = false;\n volume.value = volToRestore;\n isMuted.value = false;\n } else {\n lastVolume.value = volume.value;\n media.volume = 0;\n media.muted = true;\n volume.value = 0;\n isMuted.value = true;\n }\n }\n };\n\n /**\n * 音量变化\n */\n const handleVolumeChange = (val: number) => {\n volume.value = val;\n const media = mediaRef();\n if (media) {\n media.volume = val;\n if (val === 0) {\n isMuted.value = true;\n media.muted = true;\n } else {\n isMuted.value = false;\n media.muted = false;\n }\n }\n };\n\n /**\n * 跳转到指定时间\n */\n const seekTo = (time: number) => {\n const media = mediaRef();\n if (media && duration.value) {\n media.currentTime = time;\n currentTime.value = time;\n progress.value = (time / duration.value) * 100;\n }\n };\n\n /**\n * 格式化时间显示\n */\n const formatTime = (time: number) => {\n if (isNaN(time)) return '0:00';\n const minutes = Math.floor(time / 60);\n const seconds = Math.floor(time % 60);\n return `${minutes}:${seconds.toString().padStart(2, '0')}`;\n };\n\n /**\n * 自动播放\n */\n const autoPlay = () => {\n nextTick(() => {\n const media = mediaRef();\n if ((mediaType === FileType.VIDEO || isAudio) && media) {\n media.volume = volume.value;\n media.play().catch(() => {});\n isPlaying.value = true;\n }\n });\n };\n\n /**\n * 监听媒体事件\n */\n const setupMediaListeners = () => {\n const media = mediaRef();\n if (media) {\n media.addEventListener('timeupdate', updateProgress);\n media.addEventListener('loadedmetadata', updateProgress);\n media.addEventListener('ended', () => {\n isPlaying.value = false;\n });\n }\n };\n\n /**\n * 清理媒体事件监听\n */\n const cleanupMediaListeners = () => {\n const media = mediaRef();\n if (media) {\n media.removeEventListener('timeupdate', updateProgress);\n media.removeEventListener('loadedmetadata', updateProgress);\n }\n };\n\n return {\n isPlaying,\n progress,\n currentTime,\n duration,\n isMuted,\n volume,\n showControls,\n isAudio,\n togglePlay,\n toggleMute,\n handleVolumeChange,\n seekTo,\n formatTime,\n autoPlay,\n setupMediaListeners,\n cleanupMediaListeners,\n updateProgress\n };\n}\n","import { ref, watch } from 'vue';\nimport type { FileItem } from '../types';\nimport { FileType } from '../types';\n\n// 扩展 Window 类型\ndeclare global {\n interface Window {\n fileExplorerAPI?: {\n getApplicationIcon?: (appPath: string) => Promise<string | null>;\n };\n }\n}\n\n/**\n * 应用程序图标管理 composable\n */\nexport function useApplicationIcon(items: () => FileItem[]) {\n // 应用程序图标缓存(避免重复请求)\n const appIconCache = new Map<string, string>();\n\n // 使用响应式的图标 URL 映射\n const appIconUrls = ref<Map<string, string>>(new Map());\n\n /**\n * 为应用程序获取图标\n */\n const loadApplicationIcon = async (item: FileItem) => {\n if (item.type !== FileType.APPLICATION || !item.id) return;\n \n // 检查缓存\n if (appIconCache.has(item.id)) {\n const cachedUrl = appIconCache.get(item.id);\n if (cachedUrl) {\n appIconUrls.value.set(item.id, cachedUrl);\n }\n return;\n }\n \n // 检查响应式映射\n if (appIconUrls.value.has(item.id)) {\n return;\n }\n \n if (typeof window.fileExplorerAPI !== 'undefined' && window.fileExplorerAPI.getApplicationIcon) {\n try {\n const iconUrl = await window.fileExplorerAPI.getApplicationIcon(item.id);\n if (iconUrl) {\n appIconCache.set(item.id, iconUrl);\n appIconUrls.value.set(item.id, iconUrl);\n }\n } catch (error) {\n console.error(`Failed to load application icon for ${item.name}:`, error);\n }\n }\n };\n\n /**\n * 监听 items 变化,为应用程序加载图标\n */\n watch(items, (newItems) => {\n newItems.forEach(item => {\n if (item.type === FileType.APPLICATION && !appIconUrls.value.has(item.id)) {\n loadApplicationIcon(item);\n }\n });\n }, { immediate: true, deep: true });\n\n /**\n * 获取应用程序图标的响应式 URL\n */\n const getAppIconUrl = (item: FileItem): string | undefined => {\n return appIconUrls.value.get(item.id);\n };\n\n return {\n getAppIconUrl,\n loadApplicationIcon\n };\n}\n"],"names":["FileType","matchIconName","stringToIcon","value","validate","allowSimpleName","provider","colonSeparated","name2","prefix","result","validateIconName","name","dashSeparated","icon","defaultIconDimensions","defaultIconTransformations","defaultIconProps","defaultExtendedIconProps","mergeIconTransformations","obj1","obj2","rotate","mergeIconData","parent","child","key","getIconsTree","data","names","icons","aliases","resolved","resolve","internalGetIconData","tree","currentProps","parse","parseIconSet","callback","item","optionalPropertyDefaults","checkOptionalProps","defaults","prop","quicklyValidateIconSet","obj","dataStorage","newStorage","getStorage","providerStorage","addIconSet","storage","addIconToStorage","simpleNames","allowSimpleNames","allow","getIconData","iconName","addIcon","addCollection","added","defaultIconSizeCustomisations","defaultIconCustomisations","unitsSplit","unitsTest","calculateSize","size","ratio","precision","oldParts","newParts","code","isNumber","num","splitSVGDefs","content","tag","defs","index","start","end","endEnd","mergeDefsAndContent","wrapSVGContent","body","split","isUnsetKeyword","iconToSVG","customisations","fullIcon","fullCustomisations","box","props","transformations","hFlip","vFlip","rotation","tempValue","customisationsWidth","customisationsHeight","boxWidth","boxHeight","width","height","attributes","setAttr","viewBox","regex","randomPrefix","counter","replaceIDs","ids","match","suffix","id","newID","escapedID","setAPIModule","getAPIModule","createAPIConfig","source","resources","configStorage","fallBackAPISources","fallBackAPI","addAPIProvider","customConfig","config","getAPIConfig","detectFetch","fetchModule","calculateMaxLength","maxHostLength","url","shouldAbort","status","prepare","results","maxLength","type","length","getPath","send","host","params","path","iconsList","urlParams","uri","defaultError","response","fetchAPIModule","sortIcons","a","b","lastIcon","localStorage","list","removeCallback","storages","items","row","updateCallbacks","hasPending","oldLength","idCounter","storeCallback","pendingSources","abort","listToIcons","defaultConfig","sendQuery","payload","query","done","resourcesCount","startIndex","nextIndex","startTime","queriesSent","lastError","timer","queue","doneCallbacks","resetTimer","subscribe","overwrite","getQueryStatus","failQuery","clearQueue","moduleResponse","isError","queued","execNext","resource","status2","initRedundancy","cfg","queries","cleanup","queryCallback","doneCallback","query2","error","find","emptyCallback$1","redundancyCache","getRedundancyCache","redundancy","cachedReundancy","sendAPIQuery","target","api","cached","moduleKey","emptyCallback","loadedNewIcons","checkIconNamesForAPI","valid","invalid","parseLoaderResponse","checkMissing","pending","err","parsePossiblyAsyncResponse","loadNewIcons","icons2","customIconLoader","iconSet","loadIcons","cleanedIcons","sortedIcons","callCallback","newIcons","sources","lastProvider","lastPrefix","providerNewIcons","pendingQueue","mergeCustomisations","valueType","separator","flipFromString","custom","flip","str","rotateFromString","defaultValue","units","value2","iconToHTML","renderAttribsHTML","attr","encodeSVGforURL","svg","svgToData","svgToURL","defaultExtendedIconCustomisations","svgDefaults","commonProps","monotoneProps","coloredProps","propsToAdd","propsToAddTo","customisationAliases","fixSize","render","componentProps","mode","style","propsStyle","customStyle","alias","renderAttribs","localCounter","h","useMask","html","_window","preload","providers","emptyIcon","Icon","defineComponent","emit","loader","ref","abortLoading","_b","_a","rendering","lastRenderedIconName","iconData","shallowRef","getIcon","oldState","updateIconData","nextTick","customise","customised","classes","onMounted","watch","onUnmounted","newProps","KNOWN_TYPES","EXT_MAP","SPECIAL_FILES","getFileTypeIcon","fileName","fallbackType","lowerName","lastDotIndex","ext","baseName","getFallbackIcon","ALIASES","getFolderTypeIcon","folderName","lower","standardName","__props","computed","iconClass","base","_createElementBlock","_createVNode","_unref","splitFileName","isFolder","lastDot","fileNameCache","getFileNameParts","__emit","handleEmptyContextMenu","e","hasThumbnail","handleRename","newName","handleEnterKey","handleEscapeKey","input","i","_Fragment","_renderList","$event","$emit","_withModifiers","_cache","_normalizeClass","_createElementVNode","_hoisted_2","_openBlock","_hoisted_4","_createBlock","FileIcon","_hoisted_7","_hoisted_10","_toDisplayString","_hoisted_11","_createTextVNode","_hoisted_1","getTypeLabel","SortIndicator","_c","_d","_hoisted_3","_hoisted_5","selectedIds","editingId","dragOverId","sortConfig","selectedItems","handleSelect","newSet","lastId","lastIndex","currentIndex","handleEmptyClick","clearSelection","handleOpen","handleContextMenu","handleEmptyContextMenuFromChild","handleNameClick","handleRenameCancel","handleSort","field","handleDragStart","handleDragOver","handleDragLeave","handleDrop","targetItem","draggedIds","__expose","FolderOpen","FileGrid","FileList","getIconName","handleNavigate","section","handleClick","_renderSlot","_ctx","Breadcrumb","$slots","_hoisted_6","_hoisted_9","MARGIN","MENU_WIDTH","MENU_ITEM_HEIGHT","SEPARATOR_HEIGHT","MENU_PADDING","SUBMENU_GAP","estimateMenuHeight","calculateMenuPosition","clickX","clickY","menuHeight","viewportWidth","viewportHeight","adjustedX","adjustedY","spaceRight","spaceLeft","spaceBottom","spaceTop","calculateSubmenuPosition","parentRect","submenuHeight","submenuX","submenuY","menuRef","hoveredItemId","submenuPosition","itemRefs","position","estimatedHeight","menuStyle","submenuStyle","hoveredItem","opt","setItemRef","el","hasChildren","option","newId","itemEl","rect","visible","handleClickOutside","menuContainer","handleEscape","handleOptionClick","handleItemMouseEnter","keepSubmenuOpen","closeSubmenu","_Teleport","childIndex","_hoisted_8","useWindowDrag","isDragging","handleMouseMove","handleMouseUp","startDrag","dragging","useWindowResize","initialWidth","initialHeight","minWidth","minHeight","maxWidth","maxHeight","isResizing","resizeDirection","startX","startY","startWidth","startHeight","deltaX","deltaY","newWidth","newHeight","direction","startResize","currentWidth","currentHeight","getCursorForDirection","resizing","windowContainerRef","windowDrag","isAutoSize","getInitialSize","defaultWidth","defaultHeight","parseSize","defaultPx","minW","minH","maxW","maxH","windowResize","windowStyle","baseStyle","translateX","translateY","handleBackdropClick","handleClose","handleMinimize","handleMaximize","handleResizeStart","handleEsc","X","Minus","Maximize2","FORMAT_OPTIONS","LEVEL_OPTIONS","format","level","outputName","deleteSource","password","showPassword","defaultOutputName","fileDisplayName","currentExt","f","fullOutputPath","supportsPassword","handleConfirm","Archive","FileArchive","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","title","isCompleted","statusIcon","Loader2","CheckCircle","XCircle","statusIconClass","statusText","_resolveDynamicComponent","_normalizeStyle","_hoisted_12","getFileIcon","getIconClass","getFileTypeName","extension","directory","lastSlash","handleKeyDown","File","HardDrive","MapPin","_hoisted_17","Clock","useSelection","lastSelectedId","multi","range","indexA","indexB","useDragAndDrop","getSelectedIds","onSelect","onMove","itemId","itemIds","useMediaPlayer","mediaType","mediaRef","isPlaying","progress","currentTime","duration","isMuted","volume","lastVolume","showControls","isAudio","updateProgress","media","curr","dur","volToRestore","val","time","minutes","seconds","useApplicationIcon","appIconCache","appIconUrls","loadApplicationIcon","cachedUrl","iconUrl","newItems"],"mappings":"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","x_google_ignoreList":[1]}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/types/index.ts","../src/utils/fileTypeIcon.ts","../src/utils/folderTypeIcon.ts","../src/components/FileIcon.vue","../src/components/FileGrid.vue","../src/components/SortIndicator.vue","../src/components/FileList.vue","../src/components/FileListView.vue","../src/components/FileSidebar.vue","../src/components/Breadcrumb.vue","../src/components/Toolbar.vue","../src/components/StatusBar.vue","../src/components/ContextMenu.vue","../src/composables/useWindowDrag.ts","../src/composables/useWindowResize.ts","../src/components/Window.vue","../src/components/CompressDialog.vue","../src/components/ProgressDialog.vue","../src/components/FileInfoDialog.vue","../src/composables/useSelection.ts","../src/composables/useDragAndDrop.ts","../src/composables/useMediaPlayer.ts","../src/composables/useApplicationIcon.ts"],"sourcesContent":["/**\n * 文件类型(使用 const object 而非 enum,更好的 tree-shaking)\n */\nexport const FileType = {\n FOLDER: 'folder',\n FILE: 'file',\n IMAGE: 'image',\n VIDEO: 'video',\n MUSIC: 'music',\n DOCUMENT: 'document',\n CODE: 'code',\n TEXT: 'text',\n PDF: 'pdf',\n ARCHIVE: 'archive',\n APPLICATION: 'application',\n UNKNOWN: 'unknown'\n} as const;\n\nexport type FileType = typeof FileType[keyof typeof FileType];\n\n/**\n * 文件系统项\n */\nexport interface FileItem {\n /** 唯一标识(通常是完整路径) */\n id: string;\n name: string;\n type: FileType;\n size?: string;\n dateModified?: string;\n url?: string;\n thumbnailUrl?: string;\n children?: FileItem[];\n}\n\n/**\n * 视图模式\n */\nexport type ViewMode = 'grid' | 'list' | 'columns';\n\n/**\n * 排序配置\n */\nexport interface SortConfig {\n field: 'name' | 'dateModified' | 'size' | 'type';\n direction: 'asc' | 'desc';\n}\n\n/**\n * 侧边栏项目\n */\nexport interface SidebarItem {\n id: string;\n label: string;\n icon?: string;\n path?: string;\n children?: SidebarItem[];\n}\n\n/**\n * 面包屑项\n */\nexport interface BreadcrumbItem {\n id: string;\n name: string;\n}\n\n/**\n * 操作结果\n */\nexport interface OperationResult<T = void> {\n success: boolean;\n data?: T;\n error?: string;\n}\n\n/** 压缩格式 */\nexport type CompressFormat = 'zip' | 'tar' | 'tgz' | 'tarbz2';\n\n/** 压缩级别 */\nexport type CompressLevel = 'fast' | 'normal' | 'best';\n\n/** 压缩选项 */\nexport interface CompressOptions {\n format: CompressFormat;\n level?: CompressLevel;\n outputName: string;\n outputDir: string;\n deleteSource?: boolean;\n}\n\n/** 解压选项 */\nexport interface ExtractOptions {\n targetDir: string;\n deleteArchive?: boolean;\n}\n\n/** 压缩进度 */\nexport interface CompressProgress {\n currentFile: string;\n processedCount: number;\n totalCount: number;\n percent: number;\n}\n\n/** 压缩结果 */\nexport interface CompressResult {\n success: boolean;\n outputPath?: string;\n error?: string;\n}\n\n/** 进度状态 */\nexport type ProgressStatus = 'pending' | 'processing' | 'success' | 'error';\n\n/** 进度信息(UI 使用) */\nexport interface ProgressInfo {\n type: 'compress' | 'extract';\n status: ProgressStatus;\n percent: number;\n currentFile?: string;\n processedCount?: number;\n totalCount?: number;\n error?: string;\n outputPath?: string;\n}\n\n/**\n * 文件操作适配器接口\n */\nexport interface FileExplorerAdapter {\n /** 读取目录 */\n readDirectory(dirPath: string): Promise<FileItem[]>;\n /** 读取系统路径目录 */\n readSystemPath(pathId: string): Promise<FileItem[]>;\n /** 获取系统路径 */\n getSystemPath(pathId: string): Promise<string | null>;\n /** 读取文件内容 */\n readFileContent(filePath: string): Promise<string>;\n /** 写入文件内容 */\n writeFileContent(filePath: string, content: string): Promise<OperationResult>;\n /** 创建文件夹 */\n createFolder(parentDir: string, folderName: string): Promise<OperationResult<{ finalPath: string }>>;\n /** 创建文件 */\n createFile(parentDir: string, fileName: string, content?: string): Promise<OperationResult<{ finalPath: string }>>;\n /** 删除文件 */\n deleteFiles(paths: string[]): Promise<OperationResult>;\n /** 重命名文件 */\n renameFile(oldPath: string, newPath: string): Promise<OperationResult>;\n /** 复制文件 */\n copyFiles(sourcePaths: string[], targetDir: string): Promise<OperationResult<{ copiedPaths: string[] }>>;\n /** 移动文件 */\n moveFiles(sourcePaths: string[], targetDir: string): Promise<OperationResult<{ movedPaths: string[] }>>;\n /** 使用系统默认应用打开 */\n openPath(filePath: string): Promise<OperationResult>;\n /** 复制文件到剪贴板 */\n copyFilesToClipboard(filePaths: string[]): Promise<OperationResult>;\n /** 获取剪贴板文件 */\n getClipboardFiles(): Promise<OperationResult<{ files: string[] }>>;\n /** 粘贴文件 */\n pasteFiles(targetDir: string, sourcePaths: string[]): Promise<OperationResult<{ pastedPaths: string[] }>>;\n /** 流式搜索文件 */\n searchFilesStream(searchPath: string, pattern: string, searchId: string): Promise<OperationResult>;\n /** 监听搜索结果 */\n onSearchResults(callback: (data: { searchId: string; items: FileItem[]; done: boolean }) => void): () => void;\n /** 压缩文件 */\n compressFiles(sources: string[], options: CompressOptions): Promise<CompressResult>;\n /** 解压文件 */\n extractArchive(archivePath: string, options: ExtractOptions): Promise<CompressResult>;\n /** 判断是否为压缩文件 */\n isArchiveFile(filePath: string): Promise<boolean>;\n /** 监听压缩进度 */\n onCompressProgress(callback: (data: CompressProgress) => void): () => void;\n /** 监听解压进度 */\n onExtractProgress(callback: (data: CompressProgress) => void): () => void;\n /** 监听目录变化 */\n watchDirectory(dirPath: string, watchId: string): Promise<OperationResult>;\n /** 停止监听目录 */\n unwatchDirectory(watchId: string): Promise<OperationResult>;\n /** 监听文件变化事件 */\n onWatchEvent(callback: (data: { watchId: string; event: WatchEvent }) => void): () => void;\n /** 显示文件/文件夹的系统属性窗口 */\n showFileInfo(filePath: string): Promise<OperationResult>;\n /** 在终端中打开目录 */\n openInTerminal(dirPath: string): Promise<OperationResult>;\n /** 通过 Cursor 打开 */\n openInEditor(targetPath: string): Promise<OperationResult>;\n /** 在新窗口中打开文件夹(使用系统文件管理器) */\n openInNewWindow(folderPath: string): Promise<OperationResult>;\n /** 请求窗口聚焦(用于右键打开菜单前激活窗口) */\n requestWindowFocus(): void;\n \n // ===== 媒体服务 =====\n \n /** 检测媒体文件是否需要转码 */\n mediaNeedsTranscode?(filePath: string): Promise<OperationResult<TranscodeInfo>>;\n /** 获取可播放的媒体 URL(自动转码) */\n mediaGetPlayableUrl?(filePath: string): Promise<{ success: boolean; url?: string; error?: string }>;\n /** 获取媒体元数据 */\n mediaGetMetadata?(filePath: string): Promise<OperationResult<MediaMetadata>>;\n /** 监听转码进度 */\n onMediaTranscodeProgress?(callback: (data: { filePath: string; progress: MediaTranscodeProgress }) => void): () => void;\n /** 清理指定文件的转码缓存 */\n mediaCleanupFile?(filePath: string): Promise<OperationResult>;\n \n // ===== 媒体预览窗口 =====\n \n /** 打开媒体预览窗口(原生窗口) */\n openMediaPreviewWindow?(filePath: string, mediaType: 'image' | 'video' | 'audio'): Promise<OperationResult>;\n /** 关闭媒体预览窗口 */\n closeMediaPreviewWindow?(filePath: string): Promise<OperationResult>;\n}\n\n/** 文件变化事件类型 */\nexport type WatchEventType = 'add' | 'change' | 'remove' | 'rename';\n\n/** 文件变化事件 */\nexport interface WatchEvent {\n type: WatchEventType;\n path: string;\n filename: string;\n}\n\n// ===== 媒体服务类型 =====\n\n/** 媒体转码方式 */\nexport type TranscodeMethod = 'direct' | 'remux' | 'transcode';\n\n/** 媒体转码状态 */\nexport type TranscodeStatus = 'idle' | 'checking' | 'transcoding' | 'ready' | 'error';\n\n/** 媒体转码信息 */\nexport interface TranscodeInfo {\n type: 'video' | 'audio';\n needsTranscode: boolean;\n method: TranscodeMethod;\n estimatedTime?: number;\n targetFormat?: string;\n}\n\n/** 媒体转码进度 */\nexport interface MediaTranscodeProgress {\n percent: number;\n time?: number;\n duration?: number;\n speed?: string;\n}\n\n/** 媒体元数据 */\nexport interface MediaMetadata {\n filePath: string;\n type: 'video' | 'audio';\n duration: number;\n title?: string;\n artist?: string;\n album?: string;\n}\n\n/**\n * 右键菜单项\n */\nexport interface ContextMenuItem {\n id: string;\n label: string;\n icon?: string;\n shortcut?: string;\n disabled?: boolean;\n separator?: boolean;\n danger?: boolean; // 危险操作标记(如删除)\n checked?: boolean; // 勾选状态(显示在右侧)\n action?: () => void;\n children?: ContextMenuItem[];\n}\n","import { FileType } from '../types';\n\n/**\n * 文件图标映射(基于 material-icon-theme.json)\n *\n * 原理:\n * 1. KNOWN_TYPES:从 material-icon-theme.json 提取的所有图标名\n * 2. EXT_MAP:扩展名 → 图标名\n * 3. SPECIAL_FILES:特殊文件名 → 图标名\n * 4. 逻辑:特殊文件名匹配 → 扩展名匹配 → 兜底\n */\n\n// 从 material-icon-theme.json 提取的所有图标名(~200 个常用)\nconst KNOWN_TYPES = new Set([\n '3d', 'actionscript', 'ada', 'adobe-illustrator', 'adobe-photoshop', 'android',\n 'angular', 'applescript', 'arduino', 'asciidoc', 'assembly', 'astro', 'audio',\n 'aurelia', 'babel', 'ballerina', 'bazel', 'biome', 'blender', 'bower', 'bun',\n 'c', 'cabal', 'caddy', 'cake', 'certificate', 'changelog', 'circleci', 'claude',\n 'clojure', 'cmake', 'cobol', 'coffee', 'command', 'conduct', 'contributing',\n 'controller', 'copilot', 'cpp', 'crystal', 'csharp', 'css', 'css-map', 'cucumber',\n 'cuda', 'cursor', 'cypress', 'd', 'dart', 'database', 'deno', 'dependabot', 'diff',\n 'django', 'docker', 'document', 'drawio', 'drizzle', 'editorconfig', 'ejs',\n 'elixir', 'elm', 'email', 'ember', 'epub', 'erlang', 'esbuild', 'eslint',\n 'excalidraw', 'exe', 'favicon', 'figma', 'firebase', 'flash', 'flow', 'font',\n 'forth', 'fortran', 'freemarker', 'fsharp', 'gamemaker', 'gatsby', 'gcp', 'gemfile',\n 'gemini', 'git', 'gitlab', 'gleam', 'go', 'go-mod', 'godot', 'gradle', 'graphql',\n 'groovy', 'grunt', 'gulp', 'h', 'haml', 'handlebars', 'hardhat', 'haskell', 'haxe',\n 'hcl', 'helm', 'hjson', 'hosts', 'hpp', 'html', 'http', 'husky', 'i18n', 'image',\n 'imba', 'ionic', 'jar', 'java', 'javaclass', 'javascript', 'javascript-map',\n 'jenkins', 'jest', 'jinja', 'jsconfig', 'json', 'julia', 'jupyter', 'just',\n 'karma', 'key', 'kotlin', 'kubernetes', 'laravel', 'lean', 'lefthook', 'lerna',\n 'less', 'lib', 'license', 'lighthouse', 'liquid', 'lisp', 'livescript', 'lock',\n 'log', 'lua', 'luau', 'makefile', 'markdown', 'markdownlint', 'matlab', 'maven',\n 'mdx', 'mercurial', 'mermaid', 'meson', 'minecraft', 'mjml', 'mocha', 'mojo',\n 'nest', 'netlify', 'next', 'nginx', 'nim', 'nix', 'nodejs', 'nodemon', 'npm',\n 'nuget', 'nunjucks', 'nuxt', 'nx', 'objective-c', 'objective-cpp', 'ocaml', 'odin',\n 'openapi', 'opentofu', 'pascal', 'pdf', 'perl', 'php', 'phpstan', 'phpunit',\n 'pipeline', 'playwright', 'pnpm', 'postcss', 'powerpoint', 'powershell', 'prettier',\n 'prisma', 'processing', 'prolog', 'proto', 'pug', 'puppet', 'purescript', 'python',\n 'pytorch', 'quasar', 'r', 'racket', 'razor', 'react', 'react-ts', 'readme', 'reason',\n 'remark', 'remix', 'renovate', 'replit', 'rescript', 'riot', 'roadmap', 'robot',\n 'robots', 'rollup', 'routing', 'rspec', 'rubocop', 'ruby', 'ruff', 'rust', 'salt',\n 'san', 'sas', 'sass', 'sbt', 'scala', 'scheme', 'search', 'sentry', 'sequelize',\n 'serverless', 'settings', 'shader', 'shellcheck', 'sketch', 'slim', 'slint',\n 'smarty', 'snakemake', 'snapcraft', 'snyk', 'solidity', 'spwn', 'stackblitz',\n 'stan', 'stencil', 'storybook', 'stryker', 'stylelint', 'stylus', 'sublime',\n 'subtitles', 'supabase', 'svelte', 'svg', 'svgo', 'swagger', 'swc', 'swift',\n 'tailwindcss', 'taskfile', 'tauri', 'tcl', 'teal', 'templ', 'template', 'terraform',\n 'test-js', 'test-jsx', 'test-ts', 'tex', 'todo', 'toml', 'travis', 'tree', 'tsconfig',\n 'tsdoc', 'turborepo', 'twig', 'typescript', 'typescript-def', 'unity', 'unocss',\n 'vagrant', 'vanilla-extract', 'vercel', 'verilog', 'video', 'vim', 'vite', 'vitest',\n 'vlang', 'vscode', 'vue', 'vue-config', 'wakatime', 'wallaby', 'webassembly',\n 'webhint', 'webpack', 'windicss', 'word', 'wrangler', 'wxt', 'xaml', 'xmake',\n 'xml', 'yaml', 'yarn', 'zig', 'zip',\n]);\n\n// 扩展名 → 图标名\nconst EXT_MAP: Record<string, string> = {\n // JavaScript/TypeScript\n 'js': 'javascript', 'mjs': 'javascript', 'cjs': 'javascript',\n 'jsx': 'react',\n 'ts': 'typescript', 'mts': 'typescript', 'cts': 'typescript',\n 'tsx': 'react-ts',\n // 前端框架\n 'vue': 'vue',\n 'svelte': 'svelte',\n 'astro': 'astro',\n // 后端语言\n 'py': 'python', 'pyw': 'python', 'pyi': 'python', 'pyc': 'python',\n 'java': 'java', 'class': 'javaclass', 'jar': 'jar',\n 'c': 'c', 'h': 'h',\n 'cpp': 'cpp', 'cc': 'cpp', 'cxx': 'cpp', 'hpp': 'hpp', 'hh': 'hpp', 'hxx': 'hpp',\n 'cs': 'csharp', 'csx': 'csharp',\n 'go': 'go',\n 'rs': 'rust',\n 'php': 'php', 'phtml': 'php',\n 'rb': 'ruby', 'rake': 'ruby',\n 'swift': 'swift',\n 'kt': 'kotlin', 'kts': 'kotlin',\n 'scala': 'scala',\n 'dart': 'dart',\n 'lua': 'lua', 'luau': 'luau',\n 'r': 'r', 'rdata': 'r', 'rds': 'r',\n 'pl': 'perl', 'pm': 'perl',\n 'sh': 'command', 'bash': 'command', 'zsh': 'command', 'fish': 'command',\n 'ps1': 'powershell', 'psm1': 'powershell', 'psd1': 'powershell',\n 'bat': 'command', 'cmd': 'command',\n // 样式\n 'css': 'css',\n 'scss': 'sass', 'sass': 'sass',\n 'less': 'less',\n 'styl': 'stylus',\n // 标记/配置\n 'html': 'html', 'htm': 'html', 'xhtml': 'html',\n 'xml': 'xml', 'xsl': 'xml', 'xslt': 'xml',\n 'json': 'json', 'jsonc': 'json', 'json5': 'json',\n 'yaml': 'yaml', 'yml': 'yaml',\n 'toml': 'toml',\n 'ini': 'settings',\n 'conf': 'settings', 'config': 'settings',\n // 文档\n 'md': 'markdown', 'markdown': 'markdown', 'mdx': 'mdx',\n 'txt': 'document',\n 'pdf': 'pdf',\n 'doc': 'word', 'docx': 'word', 'dot': 'word', 'dotx': 'word', 'odt': 'word',\n 'xls': 'table', 'xlsx': 'table', 'xlsm': 'table', 'ods': 'table', 'csv': 'table',\n 'ppt': 'powerpoint', 'pptx': 'powerpoint', 'odp': 'powerpoint',\n // 图片\n 'jpg': 'image', 'jpeg': 'image', 'png': 'image', 'gif': 'image', 'webp': 'image',\n 'ico': 'image', 'bmp': 'image', 'tiff': 'image', 'tif': 'image', 'heic': 'image', 'heif': 'image',\n 'svg': 'svg',\n 'psd': 'adobe-photoshop',\n 'ai': 'adobe-illustrator',\n 'sketch': 'sketch',\n 'fig': 'figma', 'figma': 'figma',\n // 视频/音频\n 'mp4': 'video', 'mov': 'video', 'avi': 'video', 'mkv': 'video', 'webm': 'video',\n 'flv': 'video', 'wmv': 'video', 'm4v': 'video', '3gp': 'video', 'mpeg': 'video', 'mpg': 'video',\n 'mp3': 'audio', 'wav': 'audio', 'flac': 'audio', 'aac': 'audio', 'ogg': 'audio',\n 'wma': 'audio', 'm4a': 'audio', 'aiff': 'audio',\n // 压缩\n 'zip': 'zip', 'rar': 'zip', '7z': 'zip', 'tar': 'zip', 'gz': 'zip', 'bz2': 'zip',\n 'xz': 'zip', 'tgz': 'zip', 'tbz2': 'zip',\n // 数据库\n 'sql': 'database',\n 'db': 'database', 'sqlite': 'database', 'sqlite3': 'database',\n 'prisma': 'prisma',\n // 其他\n 'log': 'log',\n 'lock': 'lock',\n 'env': 'settings',\n 'graphql': 'graphql', 'gql': 'graphql',\n 'proto': 'proto',\n 'wasm': 'webassembly',\n 'zig': 'zig',\n 'nim': 'nim',\n 'nix': 'nix',\n 'hcl': 'hcl', 'tf': 'terraform',\n 'sol': 'solidity',\n 'ex': 'elixir', 'exs': 'elixir',\n 'erl': 'erlang', 'hrl': 'erlang',\n 'hs': 'haskell', 'lhs': 'haskell',\n 'ml': 'ocaml', 'mli': 'ocaml',\n 'clj': 'clojure', 'cljs': 'clojure', 'cljc': 'clojure',\n 'lisp': 'lisp', 'lsp': 'lisp', 'el': 'lisp',\n 'vim': 'vim',\n 'dockerfile': 'docker',\n};\n\n// 特殊文件名 → 图标名\nconst SPECIAL_FILES: Record<string, string> = {\n // Git\n '.gitignore': 'git', '.gitattributes': 'git', '.gitmodules': 'git', '.gitkeep': 'git',\n // 环境\n '.env': 'settings', '.env.local': 'settings', '.env.development': 'settings',\n '.env.production': 'settings', '.env.test': 'settings', '.env.example': 'settings',\n // Node/包管理\n 'package.json': 'nodejs', 'package-lock.json': 'npm',\n 'yarn.lock': 'yarn', '.yarnrc': 'yarn', '.yarnrc.yml': 'yarn',\n 'pnpm-lock.yaml': 'pnpm', '.pnpmfile.cjs': 'pnpm',\n 'bun.lockb': 'bun', 'bunfig.toml': 'bun',\n // Python\n 'requirements.txt': 'python', 'pipfile': 'python', 'pipfile.lock': 'python',\n 'pyproject.toml': 'python', 'poetry.lock': 'python', 'setup.py': 'python',\n // Rust\n 'cargo.toml': 'rust', 'cargo.lock': 'rust',\n // Go\n 'go.mod': 'go-mod', 'go.sum': 'go-mod', 'go.work': 'go-mod',\n // PHP\n 'composer.json': 'php', 'composer.lock': 'php',\n // Ruby\n 'gemfile': 'gemfile', 'gemfile.lock': 'gemfile', 'rakefile': 'ruby',\n // Docker\n 'dockerfile': 'docker', 'docker-compose.yml': 'docker', 'docker-compose.yaml': 'docker',\n '.dockerignore': 'docker',\n // 构建工具\n 'makefile': 'makefile', 'gnumakefile': 'makefile',\n 'cmakelists.txt': 'cmake',\n 'build.gradle': 'gradle', 'build.gradle.kts': 'gradle', 'settings.gradle': 'gradle',\n 'pom.xml': 'maven',\n // 配置\n 'tsconfig.json': 'tsconfig', 'jsconfig.json': 'jsconfig',\n '.prettierrc': 'prettier', '.prettierrc.json': 'prettier', '.prettierrc.js': 'prettier',\n '.prettierignore': 'prettier', 'prettier.config.js': 'prettier',\n '.eslintrc': 'eslint', '.eslintrc.json': 'eslint', '.eslintrc.js': 'eslint',\n '.eslintignore': 'eslint', 'eslint.config.js': 'eslint', 'eslint.config.mjs': 'eslint',\n '.editorconfig': 'editorconfig',\n 'vite.config.ts': 'vite', 'vite.config.js': 'vite',\n 'webpack.config.js': 'webpack', 'webpack.config.ts': 'webpack',\n 'rollup.config.js': 'rollup', 'rollup.config.ts': 'rollup',\n 'esbuild.config.js': 'esbuild',\n 'tailwind.config.js': 'tailwindcss', 'tailwind.config.ts': 'tailwindcss',\n 'postcss.config.js': 'postcss', 'postcss.config.cjs': 'postcss',\n 'babel.config.js': 'babel', '.babelrc': 'babel',\n 'jest.config.js': 'jest', 'jest.config.ts': 'jest',\n 'vitest.config.ts': 'vitest', 'vitest.config.js': 'vitest',\n 'playwright.config.ts': 'playwright', 'playwright.config.js': 'playwright',\n 'cypress.config.ts': 'cypress', 'cypress.config.js': 'cypress',\n '.swcrc': 'swc', 'swc.config.js': 'swc',\n 'turbo.json': 'turborepo',\n 'nx.json': 'nx',\n 'biome.json': 'biome',\n '.nvmrc': 'nodejs', '.node-version': 'nodejs',\n // 框架配置\n 'nuxt.config.ts': 'nuxt', 'nuxt.config.js': 'nuxt',\n 'next.config.js': 'next', 'next.config.mjs': 'next', 'next.config.ts': 'next',\n 'svelte.config.js': 'svelte',\n 'astro.config.mjs': 'astro', 'astro.config.ts': 'astro',\n 'vue.config.js': 'vue-config',\n 'angular.json': 'angular',\n 'nest-cli.json': 'nest',\n 'tauri.conf.json': 'tauri',\n // CI/CD\n '.travis.yml': 'travis',\n '.gitlab-ci.yml': 'gitlab',\n 'vercel.json': 'vercel',\n 'netlify.toml': 'netlify',\n // 其他\n 'license': 'license', 'license.md': 'license', 'license.txt': 'license',\n 'readme': 'readme', 'readme.md': 'readme', 'readme.txt': 'readme',\n 'changelog': 'changelog', 'changelog.md': 'changelog',\n '.npmrc': 'npm', '.npmignore': 'npm',\n 'robots.txt': 'robots',\n '.htaccess': 'nginx',\n 'vagrantfile': 'vagrant',\n '.stylelintrc': 'stylelint', '.stylelintrc.json': 'stylelint',\n 'nodemon.json': 'nodemon',\n '.huskyrc': 'husky',\n 'renovate.json': 'renovate',\n '.snyk': 'snyk',\n 'deno.json': 'deno', 'deno.jsonc': 'deno',\n};\n\n/**\n * 根据文件名获取 material-icon-theme 图标名称\n */\nexport function getFileTypeIcon(fileName: string, fallbackType?: FileType): string {\n const lowerName = fileName.toLowerCase();\n\n // 1. 特殊文件名匹配\n if (SPECIAL_FILES[lowerName]) {\n const type = SPECIAL_FILES[lowerName];\n if (KNOWN_TYPES.has(type)) {\n return `material-icon-theme:${type}`;\n }\n }\n\n // 2. Dockerfile 特殊处理\n if (lowerName === 'dockerfile' || lowerName.startsWith('dockerfile.')) {\n return 'material-icon-theme:docker';\n }\n\n // 3. .env 变体处理\n if (lowerName === '.env' || lowerName.startsWith('.env.')) {\n return 'material-icon-theme:settings';\n }\n\n // 4. 提取扩展名并匹配\n const lastDotIndex = fileName.lastIndexOf('.');\n const ext = lastDotIndex > 0 ? fileName.substring(lastDotIndex + 1).toLowerCase() : '';\n\n // 处理复合扩展名\n if (ext === 'ts' || ext === 'js') {\n const baseName = fileName.substring(0, lastDotIndex).toLowerCase();\n if (baseName.endsWith('.d')) {\n return 'material-icon-theme:typescript-def';\n }\n if (baseName.endsWith('.test') || baseName.endsWith('.spec')) {\n return ext === 'ts' ? 'material-icon-theme:test-ts' : 'material-icon-theme:test-js';\n }\n }\n if (ext === 'jsx' || ext === 'tsx') {\n const baseName = fileName.substring(0, lastDotIndex).toLowerCase();\n if (baseName.endsWith('.test') || baseName.endsWith('.spec')) {\n return ext === 'tsx' ? 'material-icon-theme:test-ts' : 'material-icon-theme:test-jsx';\n }\n }\n\n if (ext && EXT_MAP[ext]) {\n const type = EXT_MAP[ext];\n if (KNOWN_TYPES.has(type)) {\n return `material-icon-theme:${type}`;\n }\n }\n\n // 5. 根据 fallbackType 返回兜底图标\n if (fallbackType) {\n return getFallbackIcon(fallbackType);\n }\n\n // 6. 最终兜底\n return 'material-icon-theme:document';\n}\n\nfunction getFallbackIcon(type: FileType): string {\n switch (type) {\n case FileType.IMAGE: return 'material-icon-theme:image';\n case FileType.VIDEO: return 'material-icon-theme:video';\n case FileType.MUSIC: return 'material-icon-theme:audio';\n case FileType.CODE: return 'material-icon-theme:javascript';\n case FileType.TEXT: return 'material-icon-theme:document';\n case FileType.DOCUMENT: return 'material-icon-theme:word';\n case FileType.PDF: return 'material-icon-theme:pdf';\n case FileType.ARCHIVE: return 'material-icon-theme:zip';\n case FileType.APPLICATION: return 'material-icon-theme:exe';\n default: return 'material-icon-theme:document';\n }\n}\n\n","/**\n * 文件夹图标映射(基于 material-icon-theme.json)\n *\n * 原理:\n * 1. KNOWN_TYPES:从 material-icon-theme.json 提取的所有 folder-{type} 类型\n * 2. ALIASES:常见变体映射到标准名\n * 3. 逻辑:目录名小写 → 查别名 → 查白名单 → 命中则返回 material-icon-theme:folder-{type}\n */\n\n// 从 material-icon-theme.json 提取的所有 folder-* 类型(去掉 folder- 前缀和 -open 后缀)\nconst KNOWN_TYPES = new Set([\n 'admin', 'android', 'angular', 'animation', 'ansible', 'api', 'apollo', 'app',\n 'archive', 'astro', 'atom', 'attachment', 'audio', 'aurelia', 'aws',\n 'azure-pipelines', 'backup', 'base', 'batch', 'benchmark', 'bibliography',\n 'bicep', 'blender', 'bloc', 'bower', 'buildkite', 'cart', 'changesets', 'ci',\n 'circleci', 'class', 'claude', 'client', 'cline', 'cloud-functions', 'cloudflare',\n 'cluster', 'cobol', 'command', 'components', 'config', 'connection', 'console',\n 'constant', 'container', 'content', 'context', 'contract', 'controller', 'core',\n 'coverage', 'css', 'cue', 'cursor', 'custom', 'cypress', 'dal', 'dart', 'database',\n 'debug', 'decorators', 'delta', 'desktop', 'directive', 'dist', 'docker', 'docs',\n 'download', 'drizzle', 'dump', 'element', 'enum', 'environment', 'error', 'eslint',\n 'event', 'examples', 'expo', 'export', 'fastlane', 'favicon', 'features', 'filter',\n 'firebase', 'firestore', 'flow', 'flutter', 'font', 'forgejo', 'functions',\n 'gamemaker', 'generator', 'gh-workflows', 'git', 'gitea', 'github', 'gitlab',\n 'global', 'godot', 'gradle', 'graphql', 'guard', 'gulp', 'helm', 'helper', 'home',\n 'hook', 'husky', 'i18n', 'images', 'import', 'include', 'input', 'intellij',\n 'interceptor', 'interface', 'ios', 'java', 'javascript', 'jinja', 'job', 'json',\n 'jupyter', 'keys', 'kubernetes', 'kusto', 'layout', 'lefthook', 'less', 'lib',\n 'license', 'link', 'linux', 'liquibase', 'log', 'lottie', 'lua', 'luau', 'macos',\n 'mail', 'mappings', 'markdown', 'mercurial', 'messages', 'meta', 'metro',\n 'middleware', 'migrations', 'mjml', 'mobile', 'mock', 'mojo', 'molecule', 'moon',\n 'netlify', 'next', 'ngrx-store', 'node', 'nuxt', 'obsidian', 'organism', 'other',\n 'packages', 'pdf', 'pdm', 'php', 'phpmailer', 'pipe', 'plastic', 'plugin', 'policy',\n 'powershell', 'prisma', 'private', 'project', 'prompts', 'proto', 'public', 'python',\n 'pytorch', 'quasar', 'queue', 'react-components', 'redux-reducer', 'repository',\n 'resolver', 'resource', 'review', 'robot', 'routes', 'rules', 'rust', 'salt',\n 'sandbox', 'sass', 'scala', 'scons', 'scripts', 'secure', 'seeders', 'server',\n 'serverless', 'shader', 'shared', 'simulations', 'snapcraft', 'snippet', 'src',\n 'src-tauri', 'stack', 'stencil', 'store', 'storybook', 'stylus', 'sublime',\n 'supabase', 'svelte', 'svg', 'syntax', 'target', 'taskfile', 'tasks', 'television',\n 'temp', 'template', 'terraform', 'test', 'theme', 'toc', 'tools', 'trash', 'trigger',\n 'turborepo', 'typescript', 'ui', 'unity', 'update', 'upload', 'utils', 'vercel',\n 'verdaccio', 'video', 'views', 'vm', 'vscode', 'vue', 'vue-directives', 'vuepress',\n 'vuex-store', 'wakatime', 'webpack', 'windows', 'wordpress', 'yarn', 'zeabur',\n]);\n\n// 别名映射\nconst ALIASES: Record<string, string> = {\n // 复数/变体\n 'tests': 'test', '__tests__': 'test', '__test__': 'test', 'spec': 'test', 'specs': 'test',\n 'script': 'scripts',\n 'configs': 'config', 'configuration': 'config', 'configurations': 'config',\n 'route': 'routes', 'routing': 'routes',\n 'stories': 'storybook', 'story': 'storybook',\n 'templates': 'template',\n 'themes': 'theme',\n 'videos': 'video',\n 'imgs': 'images', 'img': 'images', 'image': 'images',\n 'fonts': 'font',\n 'styles': 'css', 'style': 'css', 'styling': 'css', 'stylesheets': 'css',\n 'view': 'views', 'pages': 'views', 'page': 'views',\n 'layouts': 'layout',\n 'models': 'database', 'model': 'database',\n 'modules': 'lib', 'module': 'lib', 'mods': 'lib',\n 'plugins': 'plugin', 'addons': 'plugin', 'extensions': 'plugin',\n 'middlewares': 'middleware',\n 'helpers': 'helper', 'utilities': 'utils', 'util': 'utils',\n 'tool': 'tools', 'tooling': 'tools',\n 'resources': 'resource', 'res': 'resource', 'assets': 'resource', 'asset': 'resource',\n 'hooks': 'hook', 'composables': 'hook',\n 'mocks': 'mock', '__mocks__': 'mock', 'fixtures': 'mock', '__fixtures__': 'mock',\n 'logs': 'log',\n 'uploads': 'upload',\n 'function': 'functions', 'func': 'functions', 'fns': 'functions',\n 'services': 'server', 'service': 'server',\n 'component': 'components', 'comp': 'components', 'comps': 'components',\n 'controllers': 'controller',\n // 常见变体\n 'source': 'src', 'sources': 'src',\n 'distribution': 'dist', 'build': 'dist', 'builds': 'dist', 'out': 'dist', 'output': 'dist',\n 'documentation': 'docs', 'doc': 'docs', 'document': 'docs', 'documents': 'docs',\n 'static': 'public', 'statics': 'public', 'publics': 'public',\n 'libs': 'lib', 'library': 'lib', 'vendor': 'lib', 'vendors': 'lib',\n 'bin': 'scripts', 'binaries': 'scripts',\n 'tmp': 'temp', 'temporary': 'temp', 'cache': 'temp', 'caches': 'temp', '.cache': 'temp', '.turbo': 'temp',\n 'types': 'typescript', '@types': 'typescript', 'typings': 'typescript', 'dts': 'typescript',\n 'locales': 'i18n', 'locale': 'i18n', 'lang': 'i18n', 'languages': 'i18n', 'translations': 'i18n',\n 'db': 'database', 'databases': 'database', 'sql': 'database', 'queries': 'database',\n 'migration': 'migrations', 'seeds': 'seeders', 'seed': 'seeders',\n // 技术栈\n '.vscode': 'vscode',\n '.github': 'github',\n '.gitlab': 'gitlab',\n '.circleci': 'circleci',\n '.husky': 'husky',\n '.docker': 'docker',\n 'node_modules': 'node',\n 'scss': 'sass',\n 'renderer': 'client', 'frontend': 'client', 'web': 'client', 'webapp': 'client', 'website': 'client',\n 'backend': 'server', 'main': 'server',\n 'preload': 'scripts',\n '.idea': 'intellij',\n '.git': 'git',\n 'k8s': 'kubernetes', 'kube': 'kubernetes',\n 'mongo': 'database', 'mongodb': 'database', 'mysql': 'database', 'postgres': 'database',\n 'api': 'api', 'apis': 'api',\n 'interfaces': 'interface',\n 'notebook': 'jupyter', 'notebooks': 'jupyter', 'ipynb': 'jupyter',\n 'notification': 'messages', 'notifications': 'messages',\n 'env': 'environment', 'envs': 'environment',\n 'redux': 'redux-reducer', 'store': 'store', 'stores': 'store',\n 'electron': 'desktop',\n 'tauri': 'src-tauri',\n};\n\n/**\n * 根据文件夹名称获取对应的 material-icon-theme 图标名\n * @returns 图标名 或 undefined(让上层兜底默认图标)\n */\nexport function getFolderTypeIcon(folderName: string): string | undefined {\n const name = (folderName || '').trim();\n if (!name) return undefined;\n\n const lower = name.replace(/[\\\\/]+$/, '').toLowerCase();\n const standardName = ALIASES[lower] ?? lower;\n\n if (KNOWN_TYPES.has(standardName)) {\n return `material-icon-theme:folder-${standardName}`;\n }\n\n return undefined;\n}\n","<template>\n <div :class=\"className\">\n <Icon :icon=\"iconName\" :width=\"size\" :height=\"size\" :class=\"iconClass\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { Icon } from '@iconify/vue';\nimport { FileType } from '../types';\nimport { getFileTypeIcon } from '../utils/fileTypeIcon';\nimport { getFolderTypeIcon } from '../utils/folderTypeIcon';\n\ninterface Props {\n type: FileType;\n name?: string;\n className?: string;\n size?: number;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n className: '',\n size: 24\n});\n\nconst iconName = computed(() => {\n if (props.type === FileType.FOLDER) {\n // 文件夹:先查特定类型图标,否则用默认 folder\n const folderIcon = props.name ? getFolderTypeIcon(props.name) : undefined;\n return folderIcon ?? 'flat-color-icons:folder';\n }\n \n // 如果有文件名,使用 material-icon-theme 图标映射(传递 type 作为兜底)\n if (props.name) {\n return getFileTypeIcon(props.name, props.type);\n }\n \n // 回退逻辑(没有文件名时)\n switch (props.type) {\n case FileType.IMAGE:\n return 'material-icon-theme:image';\n case FileType.TEXT:\n return 'material-icon-theme:document';\n case FileType.CODE:\n return 'material-icon-theme:javascript';\n case FileType.MUSIC:\n return 'material-icon-theme:audio';\n case FileType.VIDEO:\n return 'material-icon-theme:video';\n case FileType.PDF:\n return 'material-icon-theme:pdf';\n case FileType.DOCUMENT:\n return 'material-icon-theme:word';\n case FileType.APPLICATION:\n return 'material-icon-theme:exe';\n case FileType.ARCHIVE:\n return 'material-icon-theme:zip';\n default:\n return 'material-icon-theme:document';\n }\n});\n\nconst iconClass = computed(() => {\n const base = 'file-icon';\n switch (props.type) {\n case FileType.FOLDER:\n return `${base} file-icon--folder`;\n case FileType.IMAGE:\n return `${base} file-icon--image`;\n case FileType.TEXT:\n return `${base} file-icon--text`;\n case FileType.CODE:\n return `${base} file-icon--code`;\n case FileType.MUSIC:\n return `${base} file-icon--music`;\n case FileType.VIDEO:\n return `${base} file-icon--video`;\n case FileType.PDF:\n case FileType.DOCUMENT:\n return `${base} file-icon--pdf`;\n case FileType.APPLICATION:\n return `${base} file-icon--application`;\n case FileType.ARCHIVE:\n return `${base} file-icon--archive`;\n default:\n return `${base} file-icon--default`;\n }\n});\n</script>\n\n<style scoped>\n.file-icon--folder {\n color: rgb(96, 165, 250);\n fill: rgb(96, 165, 250);\n}\n\n.file-icon--image {\n color: rgb(168, 85, 247);\n}\n\n.file-icon--text {\n color: rgb(107, 114, 128);\n}\n\n.file-icon--code {\n color: rgb(34, 197, 94);\n}\n\n.file-icon--music {\n color: rgb(248, 113, 113);\n}\n\n.file-icon--video {\n color: rgb(37, 99, 235);\n}\n\n.file-icon--pdf {\n color: rgb(220, 38, 38);\n}\n\n.file-icon--application {\n color: rgb(139, 92, 246);\n}\n\n.file-icon--archive {\n color: rgb(234, 179, 8);\n}\n\n.file-icon--default {\n color: rgb(156, 163, 175);\n}\n</style>\n","<template>\n <div class=\"file-grid\" @contextmenu.prevent=\"handleEmptyContextMenu\">\n <div\n v-for=\"item in items\"\n :key=\"item.id\"\n :draggable=\"editingId !== item.id\"\n @dragstart=\"$emit('dragStart', $event, item)\"\n @dragover.prevent=\"$emit('dragOver', $event, item)\"\n @dragleave=\"$emit('dragLeave', $event)\"\n @drop.prevent=\"$emit('drop', $event, item)\"\n @click.stop=\"$emit('select', item, $event)\"\n @dblclick.stop=\"$emit('open', item)\"\n @contextmenu.prevent.stop=\"$emit('contextMenu', item, $event)\"\n :class=\"[\n 'file-grid-item',\n selectedIds.has(item.id) && editingId !== item.id\n ? 'file-grid-item--selected' \n : dragOverId === item.id \n ? 'file-grid-item--drag-over' \n : 'file-grid-item--normal'\n ]\"\n >\n <div class=\"file-grid-item-icon\">\n <!-- 应用程序图标 -->\n <img \n v-if=\"item.type === FileType.APPLICATION && getAppIconUrl?.(item)\"\n :src=\"getAppIconUrl(item)\" \n :alt=\"item.name\" \n :class=\"[\n 'file-grid-item-thumbnail file-grid-item-thumbnail--application',\n selectedIds.has(item.id) && editingId !== item.id ? 'file-grid-item-thumbnail--selected' : ''\n ]\"\n />\n <!-- 图片/视频缩略图 -->\n <template v-else-if=\"hasThumbnail(item)\">\n <!-- 视频类型必须有缩略图,如果没有缩略图说明不应该被识别为视频,按普通文件处理 -->\n <div v-if=\"item.type === FileType.VIDEO && item.thumbnailUrl\" class=\"file-grid-item-thumbnail file-grid-item-thumbnail--video\">\n <img \n :src=\"item.thumbnailUrl\"\n class=\"file-grid-item-thumbnail\"\n :alt=\"item.name\"\n @error=\"$emit('thumbnailError', item, $event)\"\n />\n <div class=\"file-grid-item-video-play\">\n <div class=\"file-grid-item-video-play-icon\" />\n </div>\n </div>\n <!-- 图片:永远只显示缩略图,不显示原始 URL -->\n <img \n v-else-if=\"item.thumbnailUrl\"\n :src=\"item.thumbnailUrl\" \n :alt=\"item.name\" \n class=\"file-grid-item-thumbnail\"\n @error=\"$emit('thumbnailError', item, $event)\"\n />\n </template>\n <FileIcon \n v-else\n :type=\"item.type\" \n :name=\"item.name\"\n :size=\"48\" \n />\n </div>\n \n <div class=\"file-grid-item-name-wrapper\">\n <input\n v-if=\"editingId === item.id\"\n type=\"text\"\n class=\"file-grid-item-rename-input\"\n :value=\"item.name\"\n @blur=\"handleRename(item, $event)\"\n @keydown.enter=\"handleEnterKey\"\n @keydown.escape=\"handleEscapeKey\"\n ref=\"renameInput\"\n autofocus\n />\n <span \n v-else\n @click.stop=\"$emit('nameClick', item, $event)\"\n :class=\"[\n 'file-grid-item-name',\n selectedIds.has(item.id) ? 'file-grid-item-name--selected' : ''\n ]\"\n :title=\"item.name\"\n >\n <template v-if=\"getFileNameParts(item).ext\">\n <span class=\"file-grid-item-name-base\">{{ getFileNameParts(item).baseName }}</span>\n <span class=\"file-grid-item-name-ext\">{{ getFileNameParts(item).ext }}</span>\n </template>\n <template v-else>{{ item.name }}</template>\n </span>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport type { FileItem } from '../types';\nimport { FileType } from '../types';\nimport FileIcon from './FileIcon.vue';\n\n/**\n * 分离文件名和扩展名\n */\nfunction splitFileName(name: string, isFolder: boolean): { baseName: string; ext: string } {\n if (isFolder) {\n return { baseName: name, ext: '' };\n }\n const lastDot = name.lastIndexOf('.');\n if (lastDot <= 0) {\n return { baseName: name, ext: '' };\n }\n return {\n baseName: name.substring(0, lastDot),\n ext: name.substring(lastDot),\n };\n}\n\n/**\n * 获取文件名各部分(带缓存)\n */\nconst fileNameCache = new Map<string, { baseName: string; ext: string }>();\nfunction getFileNameParts(item: FileItem) {\n const key = `${item.id}-${item.name}`;\n if (!fileNameCache.has(key)) {\n fileNameCache.set(key, splitFileName(item.name, item.type === FileType.FOLDER));\n }\n return fileNameCache.get(key)!;\n}\n\ninterface Props {\n items: FileItem[];\n selectedIds: Set<string>;\n editingId?: string | null;\n dragOverId?: string | null;\n /** 获取应用程序图标 URL 的函数 */\n getAppIconUrl?: (item: FileItem) => string | undefined;\n}\n\nconst props = defineProps<Props>();\n\nconst emit = defineEmits<{\n select: [item: FileItem, e: MouseEvent];\n open: [item: FileItem];\n contextMenu: [item: FileItem, e: MouseEvent];\n contextMenuEmpty: [e: MouseEvent];\n nameClick: [item: FileItem, e: MouseEvent];\n rename: [item: FileItem, newName: string];\n renameCancel: [item: FileItem];\n dragStart: [e: DragEvent, item: FileItem];\n dragOver: [e: DragEvent, item: FileItem];\n dragLeave: [e: DragEvent];\n drop: [e: DragEvent, item: FileItem];\n thumbnailError: [item: FileItem, e: Event];\n}>();\n\n/**\n * 空白处右键菜单\n */\nconst handleEmptyContextMenu = (e: MouseEvent) => {\n // 检查是否点击了文件项(文件项的 contextmenu 有 .stop,不会到这里)\n const target = e.target as HTMLElement;\n // 如果点击的不是文件项内部元素,则触发空白处菜单\n if (!target.closest('.file-grid-item')) {\n emit('contextMenuEmpty', e);\n }\n};\n\n/**\n * 判断是否有缩略图或应用程序图标\n */\nconst hasThumbnail = (item: FileItem): boolean => {\n // 应用程序图标\n if (item.type === FileType.APPLICATION && props.getAppIconUrl?.(item)) {\n return true;\n }\n // 图片:必须有缩略图才显示,永远不显示原始 URL\n if (item.type === FileType.IMAGE) {\n return !!item.thumbnailUrl;\n }\n // 视频:必须有缩略图才显示,如果没有缩略图说明不应该被识别为视频\n if (item.type === FileType.VIDEO) {\n return !!item.thumbnailUrl;\n }\n return false;\n};\n\n/**\n * 视频悬停播放\n */\nconst handleVideoHover = (e: Event, isHover: boolean) => {\n const video = e.target as HTMLVideoElement;\n if (isHover) {\n video.play().catch(() => {});\n } else {\n video.pause();\n video.currentTime = 0;\n }\n};\n\n/**\n * 处理重命名(blur 事件)\n */\nconst handleRename = (item: FileItem, e: Event) => {\n const input = e.target as HTMLInputElement;\n const newName = input.value.trim();\n if (newName && newName !== item.name) {\n emit('rename', item, newName);\n } else {\n emit('renameCancel', item);\n }\n};\n\n/**\n * Enter 键保存\n */\nconst handleEnterKey = (e: KeyboardEvent) => {\n (e.target as HTMLInputElement).blur();\n};\n\n/**\n * Escape 键取消\n */\nconst handleEscapeKey = (e: KeyboardEvent) => {\n const input = e.target as HTMLInputElement;\n // 恢复原始值,这样 blur 时会触发 renameCancel\n const item = props.items.find(i => i.id === props.editingId);\n if (item) {\n input.value = item.name;\n }\n input.blur();\n};\n</script>\n\n<style scoped>\n/**\n * FileGrid - 网格视图样式\n * 参考 macOS Finder 和 Windows Explorer 的设计\n */\n\n.file-grid {\n display: grid;\n /* macOS Finder 默认约 90-100px */\n grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));\n gap: 6px;\n padding: 12px;\n align-content: start;\n grid-auto-rows: min-content;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\n/* 网格项 - 更紧凑的布局 */\n.file-grid-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 4px;\n border-radius: 6px;\n cursor: pointer;\n border: 1px solid transparent;\n transition: background-color 120ms ease, border-color 120ms ease;\n position: relative;\n overflow: hidden;\n min-width: 0;\n width: 100%;\n}\n\n/* 拖拽时的鼠标样式 */\n.file-grid-item[draggable=\"true\"] {\n cursor: grab;\n}\n\n.file-grid-item:active {\n cursor: grabbing;\n}\n\n/* 悬停效果 - 类似 macOS */\n.file-grid-item--normal:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n/* 选中状态 - macOS 风格的蓝色高亮 */\n.file-grid-item--selected {\n background: rgba(0, 122, 255, 0.12);\n border-color: rgba(0, 122, 255, 0.2);\n}\n\n.file-grid-item--selected:hover {\n background: rgba(0, 122, 255, 0.16);\n}\n\n/* 拖拽悬停 */\n.file-grid-item--drag-over {\n background: rgba(0, 122, 255, 0.2);\n border-color: rgba(0, 122, 255, 0.4);\n}\n\n/* 图标/缩略图容器 - 统一尺寸 */\n.file-grid-item-icon {\n position: relative;\n pointer-events: none;\n display: flex;\n align-items: center;\n justify-content: center;\n /* 统一 48x48 尺寸,更紧凑 */\n width: 48px;\n height: 48px;\n flex-shrink: 0;\n}\n\n/* 缩略图样式 - 统一尺寸和圆角 */\n/* 缩略图保持原图比例,使用 object-fit: cover 填充固定尺寸容器 */\n.file-grid-item-thumbnail {\n width: 48px;\n height: 48px;\n object-fit: cover;\n object-position: center;\n border-radius: 4px;\n /* 轻微阴影增加层次感 */\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08), 0 0 0 1px rgba(0, 0, 0, 0.04);\n background: #f5f5f5;\n /* 确保图片能作为加载占位符,平滑过渡到原图 */\n display: block;\n}\n\n/* 应用程序图标 - 无背景 */\n.file-grid-item-thumbnail--application {\n object-fit: contain;\n background: transparent;\n box-shadow: none;\n border-radius: 10px;\n}\n\n.file-grid-item-thumbnail--selected {\n box-shadow: 0 2px 6px rgba(0, 122, 255, 0.2), 0 0 0 2px rgba(0, 122, 255, 0.3);\n}\n\n/* 视频缩略图容器 */\n.file-grid-item-thumbnail--video {\n position: relative;\n border-radius: 4px;\n overflow: hidden;\n background: #000;\n width: 48px;\n height: 48px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* 视频缩略图内的图片 - 保持比例,填充容器 */\n.file-grid-item-thumbnail--video > img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n object-position: center;\n display: block;\n}\n\n/* 视频播放图标 */\n.file-grid-item-video-play {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n opacity: 0.9;\n transition: opacity 150ms;\n}\n\n.file-grid-item-thumbnail--video:hover .file-grid-item-video-play {\n opacity: 0;\n}\n\n.file-grid-item-video-play-icon {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.file-grid-item-video-play-icon::before {\n content: '';\n width: 0;\n height: 0;\n border-top: 4px solid transparent;\n border-left: 7px solid white;\n border-bottom: 4px solid transparent;\n margin-left: 2px;\n}\n\n/* 文件名容器 */\n.file-grid-item-name-wrapper {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n width: 100%;\n min-height: 0;\n}\n\n/* 文件名 - macOS 风格,最多2行,保留扩展名 */\n.file-grid-item-name {\n font-size: 12px;\n line-height: 1.3;\n text-align: center;\n padding: 2px;\n border-radius: 3px;\n user-select: none;\n cursor: default;\n transition: color 100ms;\n color: #1d1d1f;\n width: 100%;\n /* 使用 flexbox 布局,让扩展名始终显示 */\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-start;\n min-height: 0;\n}\n\n/* 文件名主体部分 - 可换行,最多1行 */\n.file-grid-item-name-base {\n display: -webkit-box;\n -webkit-line-clamp: 1;\n -webkit-box-orient: vertical;\n overflow: hidden;\n word-break: break-word;\n text-overflow: ellipsis;\n width: 100%;\n text-align: center;\n}\n\n/* 扩展名部分 - 始终显示,不换行 */\n.file-grid-item-name-ext {\n display: block;\n white-space: nowrap;\n flex-shrink: 0;\n text-align: center;\n}\n\n/* 选中后点击文件名可编辑 */\n.file-grid-item-name--selected {\n cursor: text;\n}\n\n/* 重命名输入框 */\n.file-grid-item-rename-input {\n width: 100%;\n font-size: 11px;\n line-height: 1.3;\n text-align: center;\n padding: 2px 4px;\n border: 1px solid #007aff;\n border-radius: 3px;\n outline: none;\n box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.2);\n background: white;\n cursor: text;\n}\n\n/* 深色模式支持 */\n@media (prefers-color-scheme: dark) {\n .file-grid-item--normal:hover {\n background: rgba(255, 255, 255, 0.06);\n }\n\n .file-grid-item--selected {\n background: rgba(10, 132, 255, 0.25);\n border-color: rgba(10, 132, 255, 0.3);\n }\n\n .file-grid-item--selected:hover {\n background: rgba(10, 132, 255, 0.3);\n }\n\n .file-grid-item--drag-over {\n background: rgba(10, 132, 255, 0.35);\n border-color: rgba(10, 132, 255, 0.5);\n }\n\n .file-grid-item-thumbnail {\n background: #2c2c2e;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(255, 255, 255, 0.05);\n }\n\n .file-grid-item-name {\n color: #f5f5f7;\n }\n\n .file-grid-item-rename-input {\n background: #1c1c1e;\n border-color: #0a84ff;\n color: #f5f5f7;\n }\n}\n</style>\n","<template>\n <span class=\"sort-indicator\">\n <Icon :icon=\"direction === 'asc' ? 'lucide:chevron-up' : 'lucide:chevron-down'\" :width=\"12\" :height=\"12\" />\n </span>\n</template>\n\n<script setup lang=\"ts\">\nimport { Icon } from '@iconify/vue';\n\ndefineProps<{\n direction: 'asc' | 'desc';\n}>();\n</script>\n\n<style scoped>\n.sort-indicator {\n margin-left: 4px;\n display: inline-flex;\n align-items: center;\n color: rgb(59, 130, 246);\n}\n</style>\n","<template>\n <div class=\"file-list\" @contextmenu.prevent=\"handleEmptyContextMenu\">\n <table class=\"file-list-table\">\n <thead class=\"file-list-header\">\n <tr>\n <th \n class=\"file-list-header-cell file-list-header-cell--name\"\n @click=\"$emit('sort', 'name')\"\n >\n 名称\n <SortIndicator v-if=\"sortConfig?.field === 'name'\" :direction=\"sortConfig.direction\" />\n </th>\n <th \n class=\"file-list-header-cell\"\n @click=\"$emit('sort', 'dateModified')\"\n >\n 修改日期\n <SortIndicator v-if=\"sortConfig?.field === 'dateModified'\" :direction=\"sortConfig.direction\" />\n </th>\n <th \n class=\"file-list-header-cell\"\n @click=\"$emit('sort', 'size')\"\n >\n 大小\n <SortIndicator v-if=\"sortConfig?.field === 'size'\" :direction=\"sortConfig.direction\" />\n </th>\n <th \n class=\"file-list-header-cell\"\n @click=\"$emit('sort', 'type')\"\n >\n 类型\n <SortIndicator v-if=\"sortConfig?.field === 'type'\" :direction=\"sortConfig.direction\" />\n </th>\n </tr>\n </thead>\n <tbody class=\"file-list-body\">\n <tr\n v-for=\"(item, index) in items\"\n :key=\"item.id\"\n :draggable=\"editingId !== item.id\"\n @dragstart=\"$emit('dragStart', $event, item)\"\n @dragover.prevent=\"$emit('dragOver', $event, item)\"\n @dragleave=\"$emit('dragLeave', $event)\"\n @drop.prevent=\"$emit('drop', $event, item)\"\n @click.stop=\"$emit('select', item, $event)\"\n @dblclick.stop=\"$emit('open', item)\"\n @contextmenu.prevent.stop=\"$emit('contextMenu', item, $event)\"\n :class=\"[\n 'file-list-row',\n selectedIds.has(item.id) \n ? 'file-list-row--selected' \n : dragOverId === item.id \n ? 'file-list-row--drag-over'\n : index % 2 === 0 \n ? 'file-list-row--even' \n : 'file-list-row--odd'\n ]\"\n >\n <td class=\"file-list-cell file-list-cell--name\">\n <FileIcon :type=\"item.type\" :name=\"item.name\" :size=\"16\" />\n <input\n v-if=\"editingId === item.id\"\n type=\"text\"\n class=\"file-list-rename-input\"\n :value=\"item.name\"\n @blur=\"handleRename(item, $event)\"\n @keydown.enter=\"handleEnterKey\"\n @keydown.escape=\"handleEscapeKey\"\n autofocus\n />\n <span \n v-else\n @click.stop=\"$emit('nameClick', item, $event)\"\n :class=\"[\n 'file-list-name',\n selectedIds.has(item.id) ? 'file-list-name--selected' : ''\n ]\"\n >\n {{ item.name }}\n </span>\n </td>\n <td :class=\"['file-list-cell', selectedIds.has(item.id) ? 'file-list-cell--selected' : '']\">\n {{ item.dateModified || '--' }}\n </td>\n <td :class=\"['file-list-cell file-list-cell--size', selectedIds.has(item.id) ? 'file-list-cell--selected' : '']\">\n {{ item.size || '--' }}\n </td>\n <td :class=\"['file-list-cell', selectedIds.has(item.id) ? 'file-list-cell--selected' : '']\">\n {{ getTypeLabel(item.type) }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { FileItem, SortConfig } from '../types';\nimport { FileType } from '../types';\nimport FileIcon from './FileIcon.vue';\nimport SortIndicator from './SortIndicator.vue';\n\ninterface Props {\n items: FileItem[];\n selectedIds: Set<string>;\n sortConfig?: SortConfig;\n editingId?: string | null;\n dragOverId?: string | null;\n}\n\nconst props = defineProps<Props>();\n\nconst emit = defineEmits<{\n select: [item: FileItem, e: MouseEvent];\n open: [item: FileItem];\n contextMenu: [item: FileItem, e: MouseEvent];\n contextMenuEmpty: [e: MouseEvent];\n nameClick: [item: FileItem, e: MouseEvent];\n rename: [item: FileItem, newName: string];\n renameCancel: [item: FileItem];\n sort: [field: string];\n dragStart: [e: DragEvent, item: FileItem];\n dragOver: [e: DragEvent, item: FileItem];\n dragLeave: [e: DragEvent];\n drop: [e: DragEvent, item: FileItem];\n}>();\n\n/**\n * 空白处右键菜单\n */\nconst handleEmptyContextMenu = (e: MouseEvent) => {\n // 只有点击容器本身(不是表格行)时才触发\n const target = e.target as HTMLElement;\n if (!target.closest('tr')) {\n emit('contextMenuEmpty', e);\n }\n};\n\n/**\n * 获取类型标签\n */\nconst getTypeLabel = (type: FileType): string => {\n const labels: Record<FileType, string> = {\n [FileType.FOLDER]: '文件夹',\n [FileType.FILE]: '文件',\n [FileType.IMAGE]: '图片',\n [FileType.VIDEO]: '视频',\n [FileType.MUSIC]: '音频',\n [FileType.DOCUMENT]: '文档',\n [FileType.CODE]: '代码',\n [FileType.TEXT]: '文本',\n [FileType.PDF]: 'PDF',\n [FileType.ARCHIVE]: '压缩包',\n [FileType.APPLICATION]: '应用程序',\n [FileType.UNKNOWN]: '未知'\n };\n return labels[type] || type;\n};\n\n/**\n * 处理重命名(blur 事件)\n */\nconst handleRename = (item: FileItem, e: Event) => {\n const input = e.target as HTMLInputElement;\n const newName = input.value.trim();\n if (newName && newName !== item.name) {\n emit('rename', item, newName);\n } else {\n emit('renameCancel', item);\n }\n};\n\n/**\n * Enter 键保存\n */\nconst handleEnterKey = (e: KeyboardEvent) => {\n (e.target as HTMLInputElement).blur();\n};\n\n/**\n * Escape 键取消\n */\nconst handleEscapeKey = (e: KeyboardEvent) => {\n const input = e.target as HTMLInputElement;\n // 恢复原始值,这样 blur 时会触发 renameCancel\n const item = props.items.find(i => i.id === props.editingId);\n if (item) {\n input.value = item.name;\n }\n input.blur();\n};\n</script>\n\n<style scoped>\n/**\n * FileList - 列表视图样式\n * 参考 macOS Finder 和 Windows Explorer 的设计\n */\n\n.file-list {\n width: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\n.file-list-table {\n width: 100%;\n font-size: 13px;\n text-align: left;\n border-collapse: collapse;\n}\n\n/* 表头 - 更紧凑 */\n.file-list-header {\n font-size: 11px;\n color: #86868b;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n position: sticky;\n top: 0;\n background: rgba(255, 255, 255, 0.92);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n z-index: 10;\n user-select: none;\n}\n\n.file-list-header-cell {\n padding: 6px 12px;\n border-bottom: 1px solid rgba(0, 0, 0, 0.08);\n cursor: pointer;\n text-align: left;\n font-weight: 500;\n transition: background-color 100ms;\n}\n\n.file-list-header-cell:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n.file-list-header-cell--name {\n padding-left: 12px;\n padding-right: 12px;\n width: 45%;\n}\n\n.file-list-body {\n /* 无需额外边框 */\n}\n\n/* 行样式 - 更紧凑 */\n.file-list-row {\n cursor: pointer;\n user-select: none;\n transition: background-color 80ms ease;\n border-bottom: 1px solid transparent;\n}\n\n/* 可拖拽时的鼠标样式 */\n.file-list-row[draggable=\"true\"] {\n cursor: grab;\n}\n\n.file-list-row:active {\n cursor: grabbing;\n}\n\n/* 偶数行 */\n.file-list-row--even {\n background: transparent;\n}\n\n/* 奇数行 - 轻微斑马纹 */\n.file-list-row--odd {\n background: rgba(0, 0, 0, 0.015);\n}\n\n/* 悬停效果 */\n.file-list-row--even:hover,\n.file-list-row--odd:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n/* 选中状态 - macOS 风格整行高亮 */\n.file-list-row--selected {\n background: #007aff;\n color: white;\n}\n\n.file-list-row--selected:hover {\n background: #0066d6;\n}\n\n/* 拖拽悬停 */\n.file-list-row--drag-over {\n background: rgba(0, 122, 255, 0.15);\n border-bottom-color: rgba(0, 122, 255, 0.3);\n}\n\n/* 单元格 - 更紧凑的行高 */\n.file-list-cell {\n padding: 4px 12px;\n white-space: nowrap;\n color: #6e6e73;\n vertical-align: middle;\n height: 28px;\n}\n\n/* 名称列 - 图标和文字对齐 */\n.file-list-cell--name {\n padding-left: 12px;\n padding-right: 12px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* 选中时单元格颜色 */\n.file-list-cell--selected {\n color: rgba(255, 255, 255, 0.75);\n}\n\n/* 大小列 - 等宽字体 */\n.file-list-cell--size {\n font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;\n font-size: 11px;\n color: #8e8e93;\n font-variant-numeric: tabular-nums;\n}\n\n/* 文件名 */\n.file-list-name {\n overflow: hidden;\n text-overflow: ellipsis;\n flex: 1;\n color: #1d1d1f;\n cursor: default;\n font-weight: 400;\n}\n\n/* 选中后点击文件名可编辑 */\n.file-list-name--selected {\n color: white;\n font-weight: 500;\n cursor: text;\n}\n\n/* 重命名输入框 */\n.file-list-rename-input {\n flex: 1;\n font-size: 13px;\n padding: 2px 6px;\n border: 1px solid #007aff;\n border-radius: 4px;\n outline: none;\n box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.2);\n background: white;\n cursor: text;\n}\n\n/* 深色模式支持 */\n@media (prefers-color-scheme: dark) {\n .file-list-header {\n background: rgba(28, 28, 30, 0.92);\n color: #98989d;\n }\n\n .file-list-header-cell {\n border-bottom-color: rgba(255, 255, 255, 0.08);\n }\n\n .file-list-header-cell:hover {\n background: rgba(255, 255, 255, 0.04);\n }\n\n .file-list-row--odd {\n background: rgba(255, 255, 255, 0.02);\n }\n\n .file-list-row--even:hover,\n .file-list-row--odd:hover {\n background: rgba(255, 255, 255, 0.06);\n }\n\n .file-list-row--selected {\n background: #0a84ff;\n }\n\n .file-list-row--selected:hover {\n background: #0077ed;\n }\n\n .file-list-row--drag-over {\n background: rgba(10, 132, 255, 0.2);\n border-bottom-color: rgba(10, 132, 255, 0.4);\n }\n\n .file-list-cell {\n color: #98989d;\n }\n\n .file-list-cell--size {\n color: #6e6e73;\n }\n\n .file-list-name {\n color: #f5f5f7;\n }\n\n .file-list-name--selected {\n color: white;\n }\n\n .file-list-rename-input {\n background: #1c1c1e;\n border-color: #0a84ff;\n color: #f5f5f7;\n }\n}\n</style>\n","<template>\n <div \n class=\"file-list-view\"\n @click=\"handleEmptyClick\"\n @contextmenu.prevent=\"handleEmptyContextMenu\"\n >\n <!-- 加载中 -->\n <div v-if=\"loading\" class=\"file-list-view-loading\">\n <div class=\"file-list-view-spinner\"></div>\n <p>加载中...</p>\n </div>\n\n <!-- 空文件夹 -->\n <div v-else-if=\"items.length === 0\" class=\"file-list-view-empty\">\n <Icon icon=\"lucide:folder-open\" width=\"64\" height=\"64\" class=\"file-list-view-empty-icon\" />\n <p>文件夹为空</p>\n </div>\n\n <!-- 网格视图 -->\n <FileGrid\n v-else-if=\"viewMode === 'grid'\"\n :items=\"items\"\n :selected-ids=\"selectedIds\"\n :editing-id=\"editingId\"\n :drag-over-id=\"dragOverId\"\n :get-app-icon-url=\"getAppIconUrl\"\n @select=\"handleSelect\"\n @open=\"handleOpen\"\n @context-menu=\"handleContextMenu\"\n @context-menu-empty=\"handleEmptyContextMenuFromChild\"\n @name-click=\"handleNameClick\"\n @rename=\"handleRename\"\n @rename-cancel=\"handleRenameCancel\"\n @drag-start=\"handleDragStart\"\n @drag-over=\"handleDragOver\"\n @drag-leave=\"handleDragLeave\"\n @drop=\"handleDrop\"\n />\n\n <!-- 列表视图 -->\n <FileList\n v-else\n :items=\"items\"\n :selected-ids=\"selectedIds\"\n :editing-id=\"editingId\"\n :drag-over-id=\"dragOverId\"\n :sort-config=\"sortConfig\"\n @select=\"handleSelect\"\n @open=\"handleOpen\"\n @context-menu=\"handleContextMenu\"\n @context-menu-empty=\"handleEmptyContextMenuFromChild\"\n @name-click=\"handleNameClick\"\n @rename=\"handleRename\"\n @rename-cancel=\"handleRenameCancel\"\n @sort=\"handleSort\"\n @drag-start=\"handleDragStart\"\n @drag-over=\"handleDragOver\"\n @drag-leave=\"handleDragLeave\"\n @drop=\"handleDrop\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch, computed } from 'vue';\nimport { Icon } from '@iconify/vue';\nimport FileGrid from './FileGrid.vue';\nimport FileList from './FileList.vue';\nimport { FileType, type FileItem, type SortConfig, type FileExplorerAdapter } from '../types';\n\n// Props\nconst props = withDefaults(defineProps<{\n /** 文件列表 */\n items: FileItem[];\n /** 视图模式 */\n viewMode?: 'grid' | 'list';\n /** 是否加载中 */\n loading?: boolean;\n /** 文件操作适配器(可选,用于内置操作) */\n adapter?: FileExplorerAdapter;\n /** 当前路径(用于内置操作) */\n currentPath?: string;\n /** 获取应用程序图标 URL 的函数 */\n getAppIconUrl?: (item: FileItem) => string | undefined;\n}>(), {\n viewMode: 'grid',\n loading: false,\n});\n\n// Events\nconst emit = defineEmits<{\n /** 打开文件/文件夹 */\n (e: 'open', item: FileItem): void;\n /** 选中项变化 */\n (e: 'selection-change', ids: Set<string>, items: FileItem[]): void;\n /** 右键菜单(文件项) */\n (e: 'context-menu', event: MouseEvent, item: FileItem): void;\n /** 右键菜单(空白处) */\n (e: 'context-menu-empty', event: MouseEvent): void;\n /** 重命名 */\n (e: 'rename', item: FileItem, newName: string): void;\n /** 排序变化 */\n (e: 'sort-change', config: SortConfig): void;\n /** 拖拽移动文件 */\n (e: 'move', sourceIds: string[], targetId: string): void;\n}>();\n\n// 内部状态\nconst selectedIds = ref<Set<string>>(new Set());\nconst editingId = ref<string | null>(null);\nconst dragOverId = ref<string | null>(null);\nconst sortConfig = ref<SortConfig>({ field: 'name', direction: 'asc' });\n\n// 获取选中的文件项\nconst selectedItems = computed(() => \n props.items.filter(item => selectedIds.value.has(item.id))\n);\n\n// 选择处理\nconst handleSelect = (item: FileItem, e: MouseEvent) => {\n if (e.metaKey || e.ctrlKey) {\n // 多选\n const newSet = new Set(selectedIds.value);\n if (newSet.has(item.id)) {\n newSet.delete(item.id);\n } else {\n newSet.add(item.id);\n }\n selectedIds.value = newSet;\n } else if (e.shiftKey && selectedIds.value.size > 0) {\n // 范围选择\n const lastId = Array.from(selectedIds.value).pop();\n const lastIndex = props.items.findIndex(i => i.id === lastId);\n const currentIndex = props.items.findIndex(i => i.id === item.id);\n const start = Math.min(lastIndex, currentIndex);\n const end = Math.max(lastIndex, currentIndex);\n const newSet = new Set<string>();\n for (let i = start; i <= end; i++) {\n newSet.add(props.items[i]!.id);\n }\n selectedIds.value = newSet;\n } else {\n // 单选\n selectedIds.value = new Set([item.id]);\n }\n \n emit('selection-change', selectedIds.value, selectedItems.value);\n};\n\nconst handleEmptyClick = (e: MouseEvent) => {\n // 只有点击空白处才清除选择\n if (e.target === e.currentTarget) {\n clearSelection();\n }\n};\n\n// 清除选择\nconst clearSelection = () => {\n selectedIds.value = new Set();\n emit('selection-change', selectedIds.value, []);\n};\n\n// 打开文件/文件夹\nconst handleOpen = (item: FileItem) => {\n emit('open', item);\n};\n\n// 右键菜单\nconst handleContextMenu = (item: FileItem, e: MouseEvent) => {\n if (!selectedIds.value.has(item.id)) {\n selectedIds.value = new Set([item.id]);\n emit('selection-change', selectedIds.value, [item]);\n }\n emit('context-menu', e, item);\n};\n\nconst handleEmptyContextMenu = (e: MouseEvent) => {\n // 检查是否点击了文件项\n const target = e.target as HTMLElement;\n if (!target.closest('.file-grid-item') && !target.closest('.file-list-row')) {\n clearSelection();\n emit('context-menu-empty', e);\n }\n};\n\n// 从子组件触发的空白处右键菜单\nconst handleEmptyContextMenuFromChild = (e: MouseEvent) => {\n clearSelection();\n emit('context-menu-empty', e);\n};\n\n// 名称点击(用于重命名)\nconst handleNameClick = (item: FileItem, e: MouseEvent) => {\n if (selectedIds.value.has(item.id) && selectedIds.value.size === 1) {\n setTimeout(() => {\n if (selectedIds.value.has(item.id)) {\n editingId.value = item.id;\n }\n }, 500);\n }\n};\n\n// 重命名\nconst handleRename = (item: FileItem, newName: string) => {\n if (newName && newName !== item.name) {\n emit('rename', item, newName);\n }\n editingId.value = null;\n};\n\nconst handleRenameCancel = () => {\n editingId.value = null;\n};\n\n// 排序\nconst handleSort = (field: string) => {\n if (sortConfig.value.field === field) {\n sortConfig.value.direction = sortConfig.value.direction === 'asc' ? 'desc' : 'asc';\n } else {\n sortConfig.value.field = field as SortConfig['field'];\n sortConfig.value.direction = 'asc';\n }\n emit('sort-change', { ...sortConfig.value });\n};\n\n// 拖拽\nconst handleDragStart = (e: DragEvent, item: FileItem) => {\n if (!selectedIds.value.has(item.id)) {\n selectedIds.value = new Set([item.id]);\n emit('selection-change', selectedIds.value, [item]);\n }\n e.dataTransfer?.setData('text/plain', JSON.stringify([...selectedIds.value]));\n};\n\nconst handleDragOver = (e: DragEvent, item: FileItem) => {\n if (item.type === FileType.FOLDER && !selectedIds.value.has(item.id)) {\n dragOverId.value = item.id;\n }\n};\n\nconst handleDragLeave = () => {\n dragOverId.value = null;\n};\n\nconst handleDrop = (e: DragEvent, targetItem: FileItem) => {\n dragOverId.value = null;\n \n if (targetItem.type !== FileType.FOLDER) return;\n \n const data = e.dataTransfer?.getData('text/plain');\n if (!data) return;\n \n try {\n const draggedIds: string[] = JSON.parse(data);\n if (draggedIds.includes(targetItem.id)) return;\n \n emit('move', draggedIds, targetItem.id);\n clearSelection();\n } catch (error) {\n console.error('拖拽解析失败:', error);\n }\n};\n\n// 开始重命名(供外部调用)\nconst startRename = (id: string) => {\n editingId.value = id;\n};\n\n// 全选\nconst selectAll = () => {\n selectedIds.value = new Set(props.items.map(i => i.id));\n emit('selection-change', selectedIds.value, props.items);\n};\n\n// 暴露方法\ndefineExpose({\n clearSelection,\n startRename,\n selectAll,\n selectedIds,\n selectedItems,\n});\n</script>\n\n<style scoped>\n.file-list-view {\n flex: 1;\n overflow: auto;\n padding: 12px;\n user-select: none;\n min-height: 0;\n}\n\n.file-list-view-loading,\n.file-list-view-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: rgb(156, 163, 175);\n gap: 16px;\n}\n\n.file-list-view-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid rgba(156, 163, 175, 0.2);\n border-top-color: rgb(59, 130, 246);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n}\n\n@keyframes spin {\n to { transform: rotate(360deg); }\n}\n\n.file-list-view-empty-icon {\n opacity: 0.3;\n}\n</style>\n","<template>\n <div class=\"file-sidebar\">\n <div v-for=\"section in sections\" :key=\"section.id\" class=\"file-sidebar-section\">\n <div class=\"file-sidebar-section-title\">{{ section.title }}</div>\n <ul class=\"file-sidebar-list\">\n <li\n v-for=\"item in section.items\"\n :key=\"item.id\"\n @click=\"handleNavigate(item)\"\n :class=\"[\n 'file-sidebar-item',\n activeId === item.id ? 'file-sidebar-item--active' : ''\n ]\"\n >\n <Icon \n :icon=\"getIconName(item.icon)\" \n :width=\"18\" \n :height=\"18\" \n :class=\"activeId === item.id ? 'file-sidebar-item-icon--active' : 'file-sidebar-item-icon'\"\n />\n <span>{{ item.label }}</span>\n </li>\n </ul>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Icon } from '@iconify/vue';\nimport type { SidebarItem } from '../types';\n\ninterface SidebarSection {\n id: string;\n title: string;\n items: SidebarItem[];\n}\n\ninterface Props {\n sections: SidebarSection[];\n activeId?: string;\n}\n\ndefineProps<Props>();\n\nconst emit = defineEmits<{\n navigate: [item: SidebarItem];\n}>();\n\n// 将 Lucide 图标名称转换为 Iconify 格式\nconst getIconName = (iconName?: string): string => {\n if (!iconName) return 'mdi:folder';\n // 如果已经是 Iconify 格式,直接返回\n if (iconName.includes(':')) return iconName;\n // 否则转换为 lucide: 格式\n return `lucide:${iconName.toLowerCase()}`;\n};\n\nconst handleNavigate = (item: SidebarItem) => {\n emit('navigate', item);\n};\n</script>\n\n<style scoped>\n.file-sidebar {\n width: 12rem;\n background: rgba(243, 244, 246, 0.5);\n backdrop-filter: blur(24px);\n border-right: 1px solid rgba(229, 231, 233, 0.5);\n display: flex;\n flex-direction: column;\n padding-top: 2rem;\n padding-bottom: 1rem;\n height: 100%;\n box-sizing: border-box;\n overflow-y: auto;\n overflow-x: hidden;\n user-select: none;\n -webkit-app-region: drag; /* 整个侧边栏可拖拽 */\n}\n\n/* 自定义滚动条样式 */\n.file-sidebar::-webkit-scrollbar {\n width: 6px;\n}\n\n.file-sidebar::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.file-sidebar::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.2);\n border-radius: 3px;\n}\n\n.file-sidebar::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.3);\n}\n\n.file-sidebar-section {\n margin-bottom: 0;\n -webkit-app-region: no-drag; /* section 内容区域不可拖拽 */\n}\n\n.file-sidebar-section-title {\n padding: 0 1rem;\n margin-bottom: 0.5rem;\n font-size: 0.75rem;\n font-weight: 600;\n color: rgb(107, 114, 128);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.file-sidebar-section + .file-sidebar-section .file-sidebar-section-title {\n margin-top: 1.5rem;\n}\n\n.file-sidebar-list {\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n padding: 0 0.5rem;\n margin: 0;\n}\n\n.file-sidebar-item {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.375rem 0.75rem;\n border-radius: 0.375rem;\n cursor: pointer;\n font-size: 0.875rem;\n font-weight: 500;\n color: rgb(75, 85, 99);\n transition: all 200ms;\n /* no-drag 已由 section 继承 */\n}\n\n.file-sidebar-item:hover {\n background: rgba(229, 231, 233, 0.5);\n color: black;\n}\n\n.file-sidebar-item--active {\n background: rgba(209, 213, 219, 0.6);\n color: black;\n}\n\n.file-sidebar-item-icon {\n color: rgb(107, 114, 128);\n}\n\n.file-sidebar-item-icon--active {\n color: rgb(37, 99, 235);\n}\n</style>\n","<template>\n <div class=\"file-breadcrumb\">\n <span \n v-for=\"(item, index) in items\" \n :key=\"item.id\"\n class=\"file-breadcrumb-item\"\n >\n <span \n @click=\"handleClick(item, index)\"\n :class=\"[\n 'file-breadcrumb-link',\n index === items.length - 1 ? 'file-breadcrumb-link--current' : ''\n ]\"\n >\n {{ item.name }}\n </span>\n <Icon \n v-if=\"index < items.length - 1\" \n icon=\"lucide:chevron-right\" \n :width=\"14\" \n :height=\"14\" \n class=\"file-breadcrumb-separator\" \n />\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Icon } from '@iconify/vue';\nimport type { BreadcrumbItem } from '../types';\n\n// Props\nconst props = defineProps<{\n items: BreadcrumbItem[];\n}>();\n\n// Events\nconst emit = defineEmits<{\n (e: 'navigate', item: BreadcrumbItem, index: number): void;\n}>();\n\nconst handleClick = (item: BreadcrumbItem, index: number) => {\n // 点击最后一项不触发导航\n if (index < props.items.length - 1) {\n emit('navigate', item, index);\n }\n};\n</script>\n\n<style scoped>\n.file-breadcrumb {\n display: inline-flex;\n align-items: center;\n gap: 0.125rem;\n overflow-x: auto;\n padding: 0 0.25rem;\n max-width: 100%;\n scrollbar-width: none;\n -ms-overflow-style: none;\n -webkit-app-region: no-drag; /* 面包屑内容不可拖拽,但空白区域可拖拽 */\n}\n\n.file-breadcrumb::-webkit-scrollbar {\n display: none;\n}\n\n.file-breadcrumb-item {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n}\n\n.file-breadcrumb-link {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem;\n border-radius: 0.375rem;\n font-size: 0.875rem;\n transition: all 200ms;\n border: none;\n background: transparent;\n cursor: pointer;\n color: rgb(75, 85, 99);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.file-breadcrumb-link:hover {\n background: rgba(229, 231, 233, 0.6);\n color: rgb(17, 24, 39);\n}\n\n.file-breadcrumb-link--current {\n font-weight: 600;\n color: rgb(17, 24, 39);\n background: rgba(229, 231, 233, 0.5);\n cursor: default;\n}\n\n.file-breadcrumb-link--current:hover {\n background: rgba(229, 231, 233, 0.5);\n}\n\n.file-breadcrumb-separator {\n color: rgb(156, 163, 175);\n margin: 0 0.25rem;\n flex-shrink: 0;\n}\n</style>\n","<template>\n <div class=\"file-toolbar\" :class=\"{ 'file-toolbar--draggable': draggable }\">\n <!-- 导航按钮 -->\n <div class=\"file-toolbar-nav\">\n <button \n class=\"file-toolbar-button\" \n @click=\"emit('back')\" \n :disabled=\"!canGoBack\"\n title=\"后退\"\n >\n <Icon icon=\"lucide:chevron-left\" :width=\"18\" :height=\"18\" />\n </button>\n <button \n class=\"file-toolbar-button\" \n @click=\"emit('forward')\" \n :disabled=\"!canGoForward\"\n title=\"前进\"\n >\n <Icon icon=\"lucide:chevron-right\" :width=\"18\" :height=\"18\" />\n </button>\n </div>\n\n <!-- 面包屑插槽 -->\n <div class=\"file-toolbar-breadcrumb\">\n <slot name=\"breadcrumb\">\n <Breadcrumb\n v-if=\"breadcrumbs.length > 0\"\n :items=\"breadcrumbs\"\n @navigate=\"(item) => emit('breadcrumb-navigate', item)\"\n />\n </slot>\n </div>\n\n <!-- 自定义内容插槽 -->\n <div v-if=\"$slots.default\" class=\"file-toolbar-custom\">\n <slot></slot>\n </div>\n\n <!-- 操作区 -->\n <div class=\"file-toolbar-actions\">\n <!-- 搜索框 -->\n <div v-if=\"showSearch\" class=\"file-toolbar-search\">\n <Icon icon=\"lucide:search\" :width=\"16\" :height=\"16\" class=\"file-toolbar-search-icon\" />\n <input\n type=\"text\"\n :value=\"searchQuery\"\n @input=\"emit('update:searchQuery', ($event.target as HTMLInputElement).value)\"\n placeholder=\"搜索\"\n class=\"file-toolbar-search-input\"\n />\n </div>\n\n <!-- 视图切换 -->\n <div v-if=\"showViewToggle\" class=\"file-toolbar-view-toggle\">\n <button \n @click=\"emit('update:viewMode', 'grid')\" \n :class=\"['file-toolbar-button', viewMode === 'grid' ? 'file-toolbar-button--active' : '']\"\n title=\"网格视图\"\n >\n <Icon icon=\"lucide:layout-grid\" :width=\"18\" :height=\"18\" />\n </button>\n <button \n @click=\"emit('update:viewMode', 'list')\" \n :class=\"['file-toolbar-button', viewMode === 'list' ? 'file-toolbar-button--active' : '']\"\n title=\"列表视图\"\n >\n <Icon icon=\"lucide:list\" :width=\"18\" :height=\"18\" />\n </button>\n </div>\n\n <!-- 额外操作插槽 -->\n <slot name=\"actions\"></slot>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Icon } from '@iconify/vue';\nimport Breadcrumb from './Breadcrumb.vue';\nimport type { BreadcrumbItem } from '../types';\n\n// Props\nwithDefaults(defineProps<{\n /** 是否可后退 */\n canGoBack?: boolean;\n /** 是否可前进 */\n canGoForward?: boolean;\n /** 面包屑数据 */\n breadcrumbs?: BreadcrumbItem[];\n /** 视图模式 */\n viewMode?: 'grid' | 'list';\n /** 搜索关键词 */\n searchQuery?: string;\n /** 是否显示搜索框 */\n showSearch?: boolean;\n /** 是否显示视图切换 */\n showViewToggle?: boolean;\n /** 是否可拖拽(用于窗口拖动) */\n draggable?: boolean;\n}>(), {\n canGoBack: false,\n canGoForward: false,\n breadcrumbs: () => [],\n viewMode: 'grid',\n searchQuery: '',\n showSearch: false,\n showViewToggle: true,\n draggable: false,\n});\n\n// Events\nconst emit = defineEmits<{\n (e: 'back'): void;\n (e: 'forward'): void;\n (e: 'breadcrumb-navigate', item: BreadcrumbItem): void;\n (e: 'update:viewMode', mode: 'grid' | 'list'): void;\n (e: 'update:searchQuery', query: string): void;\n}>();\n</script>\n\n<style scoped>\n.file-toolbar {\n height: 3rem;\n background: rgba(249, 250, 251, 0.9);\n backdrop-filter: blur(12px);\n border-bottom: 1px solid rgb(229, 231, 233);\n display: flex;\n align-items: center;\n padding: 0 1rem;\n user-select: none;\n flex-shrink: 0;\n z-index: 30;\n position: relative;\n}\n\n.file-toolbar--draggable {\n -webkit-app-region: drag;\n}\n\n.file-toolbar-nav {\n display: flex;\n align-items: center;\n color: rgb(75, 85, 99);\n background: rgba(229, 231, 233, 0.5);\n border-radius: 0.5rem;\n padding: 0.125rem;\n flex-shrink: 0;\n -webkit-app-region: no-drag;\n}\n\n.file-toolbar-button {\n padding: 0.25rem;\n border-radius: 0.375rem;\n transition: all 200ms;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: rgb(31, 41, 55);\n}\n\n.file-toolbar-button:hover:not(:disabled) {\n background: rgb(209, 213, 219);\n}\n\n.file-toolbar-button:disabled {\n color: rgb(156, 163, 175);\n cursor: default;\n}\n\n.file-toolbar-button--active {\n background: white;\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n color: rgb(31, 41, 55);\n}\n\n.file-toolbar-breadcrumb {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n margin-left: 1rem;\n /* 不设置 no-drag,让空白区域可拖拽 */\n}\n\n.file-toolbar-custom {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n -webkit-app-region: no-drag;\n}\n\n.file-toolbar-actions {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex-shrink: 0;\n margin-left: auto;\n -webkit-app-region: no-drag;\n}\n\n.file-toolbar-search {\n position: relative;\n display: none;\n}\n\n@media (min-width: 768px) {\n .file-toolbar-search {\n display: block;\n }\n}\n\n.file-toolbar-search-icon {\n position: absolute;\n left: 0.625rem;\n top: 50%;\n transform: translateY(-50%);\n color: rgb(156, 163, 175);\n transition: color 200ms;\n}\n\n.file-toolbar-search:focus-within .file-toolbar-search-icon {\n color: rgb(59, 130, 246);\n}\n\n.file-toolbar-search-input {\n background: rgb(243, 244, 246);\n border: 1px solid transparent;\n border-radius: 0.375rem;\n padding-left: 2rem;\n padding-right: 0.75rem;\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n font-size: 0.875rem;\n outline: none;\n transition: all 200ms;\n width: 8rem;\n color: rgb(55, 65, 81);\n}\n\n.file-toolbar-search-input::placeholder {\n color: rgb(156, 163, 175);\n}\n\n.file-toolbar-search-input:focus {\n background: white;\n border-color: rgb(96, 165, 250);\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\n width: 12rem;\n}\n\n.file-toolbar-view-toggle {\n display: flex;\n align-items: center;\n background: rgba(229, 231, 233, 0.5);\n border-radius: 0.5rem;\n padding: 0.125rem;\n color: rgb(75, 85, 99);\n}\n\n.file-toolbar-view-toggle .file-toolbar-button--active {\n background: white;\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n color: rgb(31, 41, 55);\n}\n\n.file-toolbar-view-toggle .file-toolbar-button:not(.file-toolbar-button--active):hover {\n background: rgba(209, 213, 219, 0.5);\n}\n</style>\n","<template>\n <div class=\"file-status-bar\">\n <slot>\n <span>{{ itemCount }} 个项目</span>\n <span v-if=\"selectedCount > 0\"> • 已选择 {{ selectedCount }} 个</span>\n </slot>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n// Props\nwithDefaults(defineProps<{\n /** 项目总数 */\n itemCount?: number;\n /** 选中数量 */\n selectedCount?: number;\n}>(), {\n itemCount: 0,\n selectedCount: 0,\n});\n</script>\n\n<style scoped>\n.file-status-bar {\n height: 1.5rem;\n background-color: rgb(249, 250, 251);\n border-top: 1px solid rgb(229, 231, 233);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 8px;\n font-size: 10px;\n color: rgb(107, 114, 128);\n user-select: none;\n flex-shrink: 0;\n z-index: 20;\n gap: 4px;\n}\n\n.file-status-bar > * {\n flex-shrink: 0;\n}\n</style>\n","<template>\n <Teleport to=\"body\">\n <div v-if=\"visible\" class=\"context-menu-container\">\n <!-- 主菜单 - 不使用 overlay,通过 document mousedown 事件来关闭菜单 -->\n <div \n ref=\"menuRef\"\n class=\"context-menu\"\n :style=\"menuStyle\"\n >\n <template v-for=\"(option, index) in options\" :key=\"option.id || index\">\n <div v-if=\"option.separator\" class=\"context-menu-separator\" />\n <div\n v-else\n :ref=\"(el) => setItemRef(option.id, el)\"\n :class=\"[\n 'context-menu-item',\n option.disabled ? 'context-menu-item--disabled' : '',\n option.danger ? 'context-menu-item--danger' : '',\n hasChildren(option) ? 'context-menu-item--has-children' : '',\n hoveredItemId === option.id ? 'context-menu-item--active' : ''\n ]\"\n @click=\"handleOptionClick(option)\"\n @mouseenter=\"handleItemMouseEnter(option)\"\n >\n <Icon \n v-if=\"option.icon\" \n :icon=\"option.icon\" \n width=\"16\" \n height=\"16\" \n class=\"context-menu-item-icon\" \n />\n <span class=\"context-menu-item-label\">{{ option.label }}</span>\n <Icon \n v-if=\"option.checked\" \n icon=\"lucide:check\" \n width=\"14\" \n height=\"14\" \n class=\"context-menu-item-check\" \n />\n <span v-if=\"option.shortcut && !hasChildren(option)\" class=\"context-menu-item-shortcut\">\n {{ option.shortcut }}\n </span>\n <Icon \n v-if=\"hasChildren(option)\"\n icon=\"lucide:chevron-right\" \n width=\"14\" \n height=\"14\" \n class=\"context-menu-item-arrow\" \n />\n </div>\n </template>\n </div>\n \n <!-- 二级菜单(独立渲染,避免定位问题) -->\n <div\n v-if=\"hoveredItem && submenuPosition\"\n class=\"context-menu context-menu-submenu\"\n :style=\"submenuStyle\"\n @mouseenter=\"keepSubmenuOpen\"\n @mouseleave=\"closeSubmenu\"\n >\n <template v-for=\"(child, childIndex) in hoveredItem.children\" :key=\"child.id || childIndex\">\n <div v-if=\"child.separator\" class=\"context-menu-separator\" />\n <div\n v-else\n :class=\"[\n 'context-menu-item',\n child.disabled ? 'context-menu-item--disabled' : '',\n child.danger ? 'context-menu-item--danger' : ''\n ]\"\n @click=\"handleOptionClick(child)\"\n >\n <Icon \n v-if=\"child.icon\" \n :icon=\"child.icon\" \n width=\"16\" \n height=\"16\" \n class=\"context-menu-item-icon\" \n />\n <span class=\"context-menu-item-label\">{{ child.label }}</span>\n <Icon \n v-if=\"child.checked\" \n icon=\"lucide:check\" \n width=\"14\" \n height=\"14\" \n class=\"context-menu-item-check\" \n />\n <span v-if=\"child.shortcut\" class=\"context-menu-item-shortcut\">\n {{ child.shortcut }}\n </span>\n </div>\n </template>\n </div>\n </div>\n </Teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch, nextTick, onMounted, onUnmounted } from 'vue';\nimport { Icon } from '@iconify/vue';\nimport type { ContextMenuItem } from '../types';\n\ninterface Props {\n visible: boolean;\n x: number;\n y: number;\n options: ContextMenuItem[];\n}\n\nconst props = defineProps<Props>();\n\nconst emit = defineEmits<{\n close: [];\n select: [option: ContextMenuItem];\n}>();\n\n/** 边距常量 */\nconst MARGIN = 8;\n/** 菜单固定宽度 */\nconst MENU_WIDTH = 220;\n/** 菜单项高度 */\nconst MENU_ITEM_HEIGHT = 32;\n/** 分隔线高度 */\nconst SEPARATOR_HEIGHT = 9;\n/** 菜单内边距 */\nconst MENU_PADDING = 8;\n/** 子菜单与父菜单的间距 */\nconst SUBMENU_GAP = 0;\n\n/**\n * 估算菜单高度(根据菜单项数量)\n */\nfunction estimateMenuHeight(items: ContextMenuItem[]): number {\n let height = MENU_PADDING;\n for (const item of items) {\n height += item.separator ? SEPARATOR_HEIGHT : MENU_ITEM_HEIGHT;\n }\n return height;\n}\n\n/**\n * 计算自适应菜单位置\n * 使用固定宽度,只需测量高度,简化计算逻辑\n */\nfunction calculateMenuPosition(\n clickX: number,\n clickY: number,\n menuHeight: number\n): { x: number; y: number } {\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n let adjustedX = clickX;\n let adjustedY = clickY;\n\n // 水平方向调整(使用固定宽度)\n const spaceRight = viewportWidth - clickX;\n const spaceLeft = clickX;\n\n // 如果右边空间不足,尝试在左边显示\n if (spaceRight < MENU_WIDTH + MARGIN) {\n // 左边空间足够,在左边显示\n if (spaceLeft >= MENU_WIDTH + MARGIN) {\n adjustedX = clickX - MENU_WIDTH;\n } else {\n // 左右空间都不足,选择空间更大的一边,并留出边距\n if (spaceRight > spaceLeft) {\n adjustedX = viewportWidth - MENU_WIDTH - MARGIN;\n } else {\n adjustedX = MARGIN;\n }\n }\n }\n\n // 垂直方向调整\n const spaceBottom = viewportHeight - clickY;\n const spaceTop = clickY;\n\n // 如果下边空间不足,尝试在上边显示\n if (spaceBottom < menuHeight + MARGIN) {\n // 上边空间足够,在上边显示\n if (spaceTop >= menuHeight + MARGIN) {\n adjustedY = clickY - menuHeight;\n } else {\n // 上下空间都不足,选择空间更大的一边,并留出边距\n if (spaceBottom > spaceTop) {\n adjustedY = viewportHeight - menuHeight - MARGIN;\n } else {\n adjustedY = MARGIN;\n }\n }\n }\n\n // 最终边界检查,确保不会超出视口\n adjustedX = Math.max(MARGIN, Math.min(adjustedX, viewportWidth - MENU_WIDTH - MARGIN));\n adjustedY = Math.max(MARGIN, Math.min(adjustedY, viewportHeight - menuHeight - MARGIN));\n\n return { x: adjustedX, y: adjustedY };\n}\n\n/**\n * 计算二级菜单位置(Windows/Mac 标准行为:优先右侧,空间不足时左侧)\n */\nfunction calculateSubmenuPosition(\n parentRect: DOMRect,\n submenuHeight: number\n): { x: number; y: number } {\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n // 计算可用空间\n const spaceRight = viewportWidth - parentRect.right;\n const spaceLeft = parentRect.left;\n\n let submenuX: number;\n let submenuY: number;\n\n // 水平方向:优先右侧,空间不足时左侧(Windows/Mac 标准行为)\n if (spaceRight >= MENU_WIDTH + SUBMENU_GAP + MARGIN) {\n // 右侧有足够空间,在右侧显示(紧贴父菜单右边缘)\n submenuX = parentRect.right + SUBMENU_GAP;\n } else if (spaceLeft >= MENU_WIDTH + SUBMENU_GAP + MARGIN) {\n // 右侧空间不足,左侧有足够空间,在左侧显示(紧贴父菜单左边缘)\n submenuX = parentRect.left - MENU_WIDTH - SUBMENU_GAP;\n } else {\n // 左右空间都不足,选择空间更大的一边\n if (spaceRight > spaceLeft) {\n submenuX = viewportWidth - MENU_WIDTH - MARGIN;\n } else {\n submenuX = MARGIN;\n }\n }\n\n // 垂直方向:与父菜单项顶部对齐(Windows/Mac 标准行为)\n submenuY = parentRect.top;\n\n // 如果子菜单底部超出视口,向上调整\n if (submenuY + submenuHeight > viewportHeight - MARGIN) {\n submenuY = viewportHeight - submenuHeight - MARGIN;\n }\n\n // 如果子菜单顶部超出视口,向下调整\n if (submenuY < MARGIN) {\n submenuY = MARGIN;\n }\n\n return { x: submenuX, y: submenuY };\n}\n\nconst menuRef = ref<HTMLDivElement | null>(null);\nconst hoveredItemId = ref<string | null>(null);\nconst submenuPosition = ref<{ x: number; y: number } | null>(null);\nconst itemRefs = ref<Map<string, HTMLElement>>(new Map());\n\n// 使用 computed 在渲染前计算位置(使用估算高度,避免位置调整动画)\nconst position = computed(() => {\n const estimatedHeight = estimateMenuHeight(props.options);\n return calculateMenuPosition(props.x, props.y, estimatedHeight);\n});\n\nconst menuStyle = computed(() => ({\n left: `${position.value.x}px`,\n top: `${position.value.y}px`\n}));\n\nconst submenuStyle = computed(() => {\n if (!submenuPosition.value) return {};\n return {\n left: `${submenuPosition.value.x}px`,\n top: `${submenuPosition.value.y}px`\n };\n});\n\n// 获取当前悬停项的子菜单\nconst hoveredItem = computed(() => {\n if (!hoveredItemId.value) return null;\n return props.options.find(opt => opt.id === hoveredItemId.value && opt.children && opt.children.length > 0);\n});\n\n// 设置菜单项 ref\nconst setItemRef = (id: string, el: unknown) => {\n if (el && el instanceof HTMLElement) {\n itemRefs.value.set(id, el);\n } else {\n itemRefs.value.delete(id);\n }\n};\n\n// 检查是否有子菜单\nconst hasChildren = (option: ContextMenuItem) => {\n return option.children && option.children.length > 0;\n};\n\n// 计算子菜单位置\nwatch(hoveredItemId, (newId) => {\n if (!newId || !hoveredItem.value) {\n submenuPosition.value = null;\n return;\n }\n\n nextTick(() => {\n const itemEl = itemRefs.value.get(newId);\n if (!itemEl || !hoveredItem.value?.children) {\n submenuPosition.value = null;\n return;\n }\n\n const rect = itemEl.getBoundingClientRect();\n const submenuHeight = estimateMenuHeight(hoveredItem.value.children);\n submenuPosition.value = calculateSubmenuPosition(rect, submenuHeight);\n });\n});\n\n// 重置状态当菜单关闭时\nwatch(() => props.visible, (visible) => {\n if (!visible) {\n hoveredItemId.value = null;\n submenuPosition.value = null;\n }\n});\n\n// 点击外部或按 ESC 键时关闭(事件处理函数定义在外部,确保引用一致)\nconst handleClickOutside = (e: MouseEvent) => {\n const target = e.target as Node;\n \n // 检查是否点击在菜单内(包括主菜单和子菜单)\n const menuContainer = document.querySelector('.context-menu-container');\n if (menuContainer && menuContainer.contains(target)) {\n return;\n }\n\n emit('close');\n};\n\nconst handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n emit('close');\n }\n};\n\n// 监听 visible 变化,添加/移除事件监听器\nwatch(() => props.visible, (visible) => {\n if (visible) {\n // 使用 mousedown 来更快响应(Windows/Mac 标准行为)\n document.addEventListener('mousedown', handleClickOutside);\n document.addEventListener('keydown', handleEscape);\n } else {\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('keydown', handleEscape);\n }\n}, { immediate: true });\n\n// 组件卸载时移除事件监听器\nonUnmounted(() => {\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('keydown', handleEscape);\n});\n\n\nconst handleOptionClick = (option: ContextMenuItem) => {\n if (option.disabled) return;\n \n // 如果有子菜单,不执行 action,只显示子菜单\n if (option.children && option.children.length > 0) {\n return;\n }\n \n if (option.action) {\n option.action();\n }\n emit('select', option);\n emit('close');\n};\n\n// 处理菜单项鼠标进入\nconst handleItemMouseEnter = (option: ContextMenuItem) => {\n if (option.children && option.children.length > 0) {\n hoveredItemId.value = option.id;\n } else {\n hoveredItemId.value = null;\n }\n};\n\n// 保持子菜单打开\nconst keepSubmenuOpen = () => {\n // 当鼠标在子菜单上时,保持 hoveredItemId 不变\n};\n\n// 关闭子菜单\nconst closeSubmenu = () => {\n hoveredItemId.value = null;\n};\n</script>\n\n<style scoped>\n/* container 不拦截事件,让右键事件可以穿透到下层文件列表 */\n.context-menu-container {\n position: fixed;\n inset: 0;\n z-index: 9999;\n pointer-events: none;\n}\n\n.context-menu {\n position: fixed;\n z-index: 10000;\n width: 220px; /* 固定宽度,与 calculateMenuPosition 中的 MENU_WIDTH 一致 */\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(24px);\n border: 1px solid rgba(229, 231, 233, 0.5);\n border-radius: 0.5rem;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.15), 0 4px 6px -2px rgba(0, 0, 0, 0.1);\n padding: 0.25rem 0;\n font-size: 0.875rem;\n user-select: none;\n animation: fade-in 100ms ease-out, zoom-in 100ms ease-out;\n pointer-events: auto;\n}\n\n@keyframes fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@keyframes zoom-in {\n from { transform: scale(0.95); }\n to { transform: scale(1); }\n}\n\n.context-menu-item {\n width: 100%;\n text-align: left;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.375rem 1rem;\n color: rgb(55, 65, 81);\n transition: all 200ms;\n border: none;\n background: transparent;\n cursor: pointer;\n}\n\n.context-menu-item:hover {\n background: rgb(59, 130, 246);\n color: white;\n}\n\n.context-menu-item:hover .context-menu-item-icon {\n color: white;\n}\n\n.context-menu-item:hover .context-menu-item-shortcut {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.context-menu-item--disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.context-menu-item--disabled:hover {\n background: transparent;\n color: rgb(55, 65, 81);\n}\n\n.context-menu-item--disabled:hover .context-menu-item-icon {\n color: rgb(107, 114, 128);\n}\n\n.context-menu-item--danger {\n color: rgb(220, 38, 38);\n}\n\n.context-menu-item--danger:hover {\n background: rgb(220, 38, 38);\n color: white;\n}\n\n.context-menu-item--danger .context-menu-item-icon {\n color: rgb(220, 38, 38);\n}\n\n.context-menu-item--danger:hover .context-menu-item-icon {\n color: white;\n}\n\n.context-menu-item--has-children {\n position: relative;\n}\n\n.context-menu-item--active {\n background: rgb(59, 130, 246);\n color: white;\n}\n\n.context-menu-item--active .context-menu-item-icon {\n color: white;\n}\n\n.context-menu-item--active .context-menu-item-shortcut {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.context-menu-item-icon {\n color: rgb(107, 114, 128);\n flex-shrink: 0;\n}\n\n.context-menu-item-label {\n flex: 1;\n}\n\n.context-menu-item-shortcut {\n color: rgb(156, 163, 175);\n font-size: 0.6875rem;\n}\n\n.context-menu-separator {\n height: 1px;\n background: rgb(229, 231, 233);\n margin: 0.25rem 0.5rem;\n}\n\n.context-menu-item-check {\n color: rgb(107, 114, 128);\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.context-menu-item:hover .context-menu-item-check,\n.context-menu-item--active .context-menu-item-check {\n color: white;\n}\n\n.context-menu-item-arrow {\n color: rgb(156, 163, 175);\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.context-menu-item:hover .context-menu-item-arrow,\n.context-menu-item--active .context-menu-item-arrow {\n color: white;\n}\n\n.context-menu-submenu {\n z-index: 10001;\n}\n</style>\n","import { ref, watch, onUnmounted } from 'vue';\n\n/**\n * 窗口拖拽功能管理\n */\nexport function useWindowDrag() {\n const position = ref({ x: 0, y: 0 });\n const isDragging = ref(false);\n\n /**\n * 鼠标移动处理\n */\n const handleMouseMove = (e: MouseEvent) => {\n if (!isDragging.value) return;\n position.value = {\n x: position.value.x + e.movementX,\n y: position.value.y + e.movementY\n };\n };\n\n /**\n * 鼠标释放处理\n */\n const handleMouseUp = () => {\n isDragging.value = false;\n };\n\n /**\n * 开始拖拽\n */\n const startDrag = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n // 检查是否点击在可拖拽区域,但排除按钮\n if (target.closest('.draggable-area') && !target.closest('button')) {\n e.preventDefault();\n isDragging.value = true;\n }\n };\n\n /**\n * 监听拖拽状态变化\n */\n watch(isDragging, (dragging) => {\n if (dragging) {\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n } else {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n }\n });\n\n /**\n * 清理事件监听\n */\n onUnmounted(() => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n });\n\n return {\n position,\n isDragging,\n startDrag\n };\n}\n","import { ref, watch, onUnmounted } from 'vue';\n\ntype ResizeDirection = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';\n\n/**\n * 窗口调整大小功能管理\n */\nexport function useWindowResize(\n initialWidth: number,\n initialHeight: number,\n minWidth: number,\n minHeight: number,\n maxWidth: number,\n maxHeight: number\n) {\n const width = ref(initialWidth);\n const height = ref(initialHeight);\n const isResizing = ref(false);\n const resizeDirection = ref<ResizeDirection | null>(null);\n const startX = ref(0);\n const startY = ref(0);\n const startWidth = ref(0);\n const startHeight = ref(0);\n\n /**\n * 鼠标移动处理\n */\n const handleMouseMove = (e: MouseEvent) => {\n if (!isResizing.value || !resizeDirection.value) return;\n\n const deltaX = e.clientX - startX.value;\n const deltaY = e.clientY - startY.value;\n\n let newWidth = startWidth.value;\n let newHeight = startHeight.value;\n\n const direction = resizeDirection.value;\n\n // 处理水平方向\n if (direction.includes('e')) {\n newWidth = Math.min(Math.max(startWidth.value + deltaX, minWidth), maxWidth);\n } else if (direction.includes('w')) {\n newWidth = Math.min(Math.max(startWidth.value - deltaX, minWidth), maxWidth);\n }\n\n // 处理垂直方向\n if (direction.includes('s')) {\n newHeight = Math.min(Math.max(startHeight.value + deltaY, minHeight), maxHeight);\n } else if (direction.includes('n')) {\n newHeight = Math.min(Math.max(startHeight.value - deltaY, minHeight), maxHeight);\n }\n\n width.value = newWidth;\n height.value = newHeight;\n };\n\n /**\n * 鼠标释放处理\n */\n const handleMouseUp = () => {\n isResizing.value = false;\n resizeDirection.value = null;\n };\n\n /**\n * 开始调整大小\n */\n const startResize = (\n e: MouseEvent,\n direction: ResizeDirection,\n currentWidth: number,\n currentHeight: number\n ) => {\n e.preventDefault();\n e.stopPropagation();\n isResizing.value = true;\n resizeDirection.value = direction;\n startX.value = e.clientX;\n startY.value = e.clientY;\n startWidth.value = currentWidth;\n startHeight.value = currentHeight;\n };\n\n /**\n * 获取对应方向的鼠标样式\n */\n const getCursorForDirection = (direction: ResizeDirection): string => {\n const cursors: Record<ResizeDirection, string> = {\n n: 'n-resize',\n s: 's-resize',\n e: 'e-resize',\n w: 'w-resize',\n ne: 'ne-resize',\n nw: 'nw-resize',\n se: 'se-resize',\n sw: 'sw-resize'\n };\n return cursors[direction];\n };\n\n /**\n * 监听调整大小状态变化\n */\n watch(isResizing, (resizing) => {\n if (resizing) {\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n document.body.style.cursor = getCursorForDirection(resizeDirection.value || 'se');\n document.body.style.userSelect = 'none';\n } else {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n }\n });\n\n /**\n * 清理事件监听\n */\n onUnmounted(() => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n });\n\n return {\n width,\n height,\n isResizing,\n startResize\n };\n}\n","<template>\n <Teleport to=\"body\">\n <div \n class=\"window-overlay\"\n @click=\"handleBackdropClick\"\n >\n <div \n ref=\"windowContainerRef\"\n class=\"window-container\"\n :style=\"windowStyle\"\n @click.stop\n >\n <!-- Title Bar -->\n <div \n v-if=\"showTitleBar\"\n class=\"window-title-bar draggable-area\"\n @mousedown=\"handleDragStart\"\n >\n <div class=\"window-controls\">\n <button \n @click.stop=\"handleClose\" \n class=\"window-control-button window-control-button--close\"\n >\n <Icon icon=\"lucide:x\" width=\"7\" height=\"7\" class=\"window-control-icon\" />\n </button>\n <button \n v-if=\"showMinimize\"\n @click.stop=\"handleMinimize\" \n class=\"window-control-button window-control-button--minimize\"\n >\n <Icon icon=\"lucide:minus\" width=\"7\" height=\"7\" class=\"window-control-icon\" />\n </button>\n <button \n v-if=\"showMaximize\"\n @click.stop=\"handleMaximize\" \n class=\"window-control-button window-control-button--maximize\"\n >\n <Icon icon=\"lucide:maximize-2\" width=\"7\" height=\"7\" class=\"window-control-icon\" />\n </button>\n </div>\n \n <div class=\"window-title-info\">\n <slot name=\"title\">\n <span class=\"window-title-text\">{{ title }}</span>\n </slot>\n </div>\n\n <div class=\"window-title-actions\">\n <slot name=\"actions\"></slot>\n </div>\n </div>\n\n <!-- Content -->\n <div class=\"window-content\">\n <slot></slot>\n </div>\n\n <!-- Resize Handles -->\n <template v-if=\"resizable\">\n <div \n class=\"window-resize-handle window-resize-handle--n\"\n @mousedown=\"(e) => handleResizeStart(e, 'n')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--s\"\n @mousedown=\"(e) => handleResizeStart(e, 's')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--e\"\n @mousedown=\"(e) => handleResizeStart(e, 'e')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--w\"\n @mousedown=\"(e) => handleResizeStart(e, 'w')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--ne\"\n @mousedown=\"(e) => handleResizeStart(e, 'ne')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--nw\"\n @mousedown=\"(e) => handleResizeStart(e, 'nw')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--se\"\n @mousedown=\"(e) => handleResizeStart(e, 'se')\"\n ></div>\n <div \n class=\"window-resize-handle window-resize-handle--sw\"\n @mousedown=\"(e) => handleResizeStart(e, 'sw')\"\n ></div>\n </template>\n </div>\n </div>\n </Teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, onMounted, onUnmounted } from 'vue';\nimport { Icon } from '@iconify/vue';\nimport { useWindowDrag } from '../composables/useWindowDrag';\nimport { useWindowResize } from '../composables/useWindowResize';\n\ninterface Props {\n title?: string;\n showTitleBar?: boolean;\n showMinimize?: boolean;\n showMaximize?: boolean;\n draggable?: boolean;\n resizable?: boolean;\n /** 窗口宽度,'auto' 表示自适应内容,'fit-content' 也表示自适应 */\n width?: string | number;\n /** 窗口高度,'auto' 表示自适应内容,'fit-content' 也表示自适应 */\n height?: string | number;\n minWidth?: string | number;\n minHeight?: string | number;\n maxWidth?: string | number;\n maxHeight?: string | number;\n closeOnBackdrop?: boolean;\n /** 是否自适应内容大小(不使用固定初始尺寸) */\n fitContent?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showTitleBar: true,\n showMinimize: false,\n showMaximize: false,\n draggable: true,\n resizable: true,\n closeOnBackdrop: true,\n width: 'auto',\n height: 'auto',\n minWidth: 300,\n minHeight: 200,\n maxWidth: '80vw',\n maxHeight: '80vh',\n fitContent: false\n});\n\nconst emit = defineEmits<{\n close: [];\n minimize: [];\n maximize: [];\n}>();\n\nconst windowContainerRef = ref<HTMLElement | null>(null);\nconst windowDrag = props.draggable ? useWindowDrag() : null;\n\n/**\n * 是否使用自适应内容模式\n */\nconst isAutoSize = computed(() => {\n return props.fitContent || \n props.width === 'auto' || \n props.width === 'fit-content' ||\n props.height === 'auto' ||\n props.height === 'fit-content';\n});\n\n/**\n * 计算初始尺寸\n */\nconst getInitialSize = () => {\n // 自适应模式不设置固定初始尺寸\n if (isAutoSize.value) {\n return { initialWidth: 0, initialHeight: 0 };\n }\n \n const defaultWidth = 600;\n const defaultHeight = 500;\n \n let initialWidth = defaultWidth;\n let initialHeight = defaultHeight;\n \n if (props.width !== 'auto' && props.width !== 'fit-content') {\n initialWidth = typeof props.width === 'number' ? props.width : parseInt(props.width);\n }\n if (props.height !== 'auto' && props.height !== 'fit-content') {\n initialHeight = typeof props.height === 'number' ? props.height : parseInt(props.height);\n }\n \n return { initialWidth, initialHeight };\n};\n\n/**\n * 解析尺寸限制\n */\nconst parseSize = (size: string | number, defaultPx: number): number => {\n if (typeof size === 'number') return size;\n if (size.endsWith('px')) return parseInt(size);\n if (size.endsWith('vw')) return (parseInt(size) / 100) * window.innerWidth;\n if (size.endsWith('vh')) return (parseInt(size) / 100) * window.innerHeight;\n return defaultPx;\n};\n\nconst { initialWidth, initialHeight } = getInitialSize();\nconst minW = parseSize(props.minWidth, 500);\nconst minH = parseSize(props.minHeight, 350);\nconst maxW = parseSize(props.maxWidth, window.innerWidth * 0.8);\nconst maxH = parseSize(props.maxHeight, window.innerHeight * 0.8);\n\nconst windowResize = props.resizable \n ? useWindowResize(initialWidth, initialHeight, minW, minH, maxW, maxH)\n : null;\n\nconst windowStyle = computed(() => {\n const baseStyle: Record<string, string> = {\n left: '50%',\n top: '50%',\n };\n\n // 计算位置和缩放(组合 transform)\n let translateX = '-50%';\n let translateY = '-50%';\n \n if (props.draggable && windowDrag) {\n translateX = `calc(-50% + ${windowDrag.position.value.x}px)`;\n translateY = `calc(-50% + ${windowDrag.position.value.y}px)`;\n }\n \n baseStyle.transform = `translate(${translateX}, ${translateY})`;\n baseStyle.transformOrigin = 'center center';\n\n // 自适应模式:不设置固定宽高,让内容决定\n if (isAutoSize.value) {\n // 只有在用户手动调整过大小时才应用\n if (props.resizable && windowResize && windowResize.width.value > 0) {\n baseStyle.width = `${windowResize.width.value}px`;\n baseStyle.height = `${windowResize.height.value}px`;\n }\n // 否则不设置 width/height,让 CSS fit-content 生效\n } else {\n // 固定尺寸模式\n if (props.resizable && windowResize) {\n baseStyle.width = `${windowResize.width.value}px`;\n baseStyle.height = `${windowResize.height.value}px`;\n } else {\n if (props.width !== 'auto' && props.width !== 'fit-content') {\n baseStyle.width = typeof props.width === 'number' ? `${props.width}px` : props.width;\n }\n if (props.height !== 'auto' && props.height !== 'fit-content') {\n baseStyle.height = typeof props.height === 'number' ? `${props.height}px` : props.height;\n }\n }\n }\n \n if (props.minWidth) {\n baseStyle.minWidth = typeof props.minWidth === 'number' ? `${props.minWidth}px` : props.minWidth;\n }\n if (props.minHeight) {\n baseStyle.minHeight = typeof props.minHeight === 'number' ? `${props.minHeight}px` : props.minHeight;\n }\n if (props.maxWidth) {\n baseStyle.maxWidth = typeof props.maxWidth === 'number' ? `${props.maxWidth}px` : props.maxWidth;\n }\n if (props.maxHeight) {\n baseStyle.maxHeight = typeof props.maxHeight === 'number' ? `${props.maxHeight}px` : props.maxHeight;\n }\n\n return baseStyle;\n});\n\nconst handleBackdropClick = (e: MouseEvent) => {\n if (props.closeOnBackdrop && e.target === e.currentTarget) {\n emit('close');\n }\n};\n\nconst handleDragStart = (e: MouseEvent) => {\n if (props.draggable && windowDrag) {\n windowDrag.startDrag(e);\n }\n};\n\nconst handleClose = () => {\n emit('close');\n};\n\nconst handleMinimize = () => {\n emit('minimize');\n};\n\nconst handleMaximize = () => {\n emit('maximize');\n};\n\nconst handleResizeStart = (e: MouseEvent, direction: 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw') => {\n if (!props.resizable || !windowResize || !windowContainerRef.value) return;\n \n const rect = windowContainerRef.value.getBoundingClientRect();\n const currentWidth = rect.width;\n const currentHeight = rect.height;\n \n windowResize.startResize(e, direction, currentWidth, currentHeight);\n};\n\n/**\n * ESC 键关闭\n */\nonMounted(() => {\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n emit('close');\n }\n };\n window.addEventListener('keydown', handleEsc);\n \n onUnmounted(() => {\n window.removeEventListener('keydown', handleEsc);\n });\n});\n</script>\n\n<style scoped>\n.window-overlay {\n position: fixed;\n inset: 0;\n z-index: 100;\n background: rgba(0, 0, 0, 0.3);\n animation: fade-in 200ms ease-out;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.window-container {\n position: absolute;\n display: flex;\n flex-direction: column;\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(24px);\n border: 1px solid rgb(229, 231, 233);\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n border-radius: 0.5rem;\n overflow: hidden;\n animation: window-fade-in 200ms ease-out;\n}\n\n.window-title-bar {\n height: 2.5rem;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0 0.75rem;\n border-bottom: 1px solid rgb(229, 231, 233);\n flex-shrink: 0;\n user-select: none;\n background: rgba(249, 250, 251, 0.8);\n z-index: 20;\n cursor: grab;\n}\n\n.window-title-bar:active {\n cursor: grabbing;\n}\n\n.window-controls {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.window-control-button {\n width: 0.75rem;\n height: 0.75rem;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid;\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n outline: none;\n cursor: pointer;\n padding: 0;\n background: transparent;\n flex-shrink: 0;\n position: relative;\n}\n\n.window-control-button svg {\n width: 7px !important;\n height: 7px !important;\n display: block;\n flex-shrink: 0;\n}\n\n.window-control-button .window-control-icon {\n width: 7px !important;\n height: 7px !important;\n min-width: 7px;\n min-height: 7px;\n}\n\n.window-control-button--close {\n background-color: rgb(255, 95, 87);\n border-color: rgb(224, 68, 62);\n}\n\n.window-control-button--minimize {\n background-color: rgb(254, 188, 46);\n border-color: rgb(216, 158, 36);\n}\n\n.window-control-button--maximize {\n background-color: rgb(40, 200, 64);\n border-color: rgb(26, 171, 41);\n}\n\n.window-control-icon {\n color: rgba(0, 0, 0, 0.5);\n opacity: 0;\n transition: opacity 200ms;\n width: 7px;\n height: 7px;\n flex-shrink: 0;\n}\n\n.window-controls:hover .window-control-icon {\n opacity: 1;\n}\n\n.window-control-button--close:hover {\n background-color: rgba(255, 95, 87, 0.8);\n}\n\n.window-control-button--minimize:hover {\n background-color: rgba(254, 188, 46, 0.8);\n}\n\n.window-control-button--maximize:hover {\n background-color: rgba(40, 200, 64, 0.8);\n}\n\n.window-title-info {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1;\n margin: 0 1rem;\n overflow: hidden;\n pointer-events: none;\n}\n\n.window-title-text {\n font-weight: 500;\n font-size: 0.75rem;\n color: rgb(75, 85, 99);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n width: 100%;\n text-align: center;\n}\n\n.window-title-actions {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n min-width: 4rem;\n flex-shrink: 0;\n}\n\n.window-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n/* Resize Handles */\n.window-resize-handle {\n position: absolute;\n background: transparent;\n z-index: 30;\n}\n\n.window-resize-handle--n {\n top: 0;\n left: 0;\n right: 0;\n height: 4px;\n cursor: n-resize;\n}\n\n.window-resize-handle--s {\n bottom: 0;\n left: 0;\n right: 0;\n height: 4px;\n cursor: s-resize;\n}\n\n.window-resize-handle--e {\n top: 0;\n right: 0;\n bottom: 0;\n width: 4px;\n cursor: e-resize;\n}\n\n.window-resize-handle--w {\n top: 0;\n left: 0;\n bottom: 0;\n width: 4px;\n cursor: w-resize;\n}\n\n.window-resize-handle--ne {\n top: 0;\n right: 0;\n width: 8px;\n height: 8px;\n cursor: ne-resize;\n}\n\n.window-resize-handle--nw {\n top: 0;\n left: 0;\n width: 8px;\n height: 8px;\n cursor: nw-resize;\n}\n\n.window-resize-handle--se {\n bottom: 0;\n right: 0;\n width: 8px;\n height: 8px;\n cursor: se-resize;\n}\n\n.window-resize-handle--sw {\n bottom: 0;\n left: 0;\n width: 8px;\n height: 8px;\n cursor: sw-resize;\n}\n\n@keyframes fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@keyframes window-fade-in {\n from {\n opacity: 0;\n transform: translate(-50%, -50%) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n}\n</style>\n","<template>\n <Teleport to=\"body\">\n <div v-if=\"visible\" class=\"compress-dialog-overlay\" @click=\"emit('cancel')\">\n <div class=\"compress-dialog\" @click.stop>\n <!-- 头部 -->\n <div class=\"compress-dialog-header\">\n <div class=\"compress-dialog-title\">\n <Icon icon=\"lucide:archive\" width=\"20\" height=\"20\" />\n <span>压缩文件</span>\n </div>\n <button class=\"compress-dialog-close\" @click=\"emit('cancel')\">\n <Icon icon=\"lucide:x\" width=\"18\" height=\"18\" />\n </button>\n </div>\n\n <!-- 内容 -->\n <div class=\"compress-dialog-content\">\n <!-- 文件信息 -->\n <div class=\"compress-dialog-info\">\n <Icon icon=\"lucide:file-archive\" width=\"16\" height=\"16\" />\n <span>{{ fileDisplayName }}</span>\n </div>\n\n <!-- 输出文件名 -->\n <div class=\"compress-dialog-field\">\n <label>文件名</label>\n <div class=\"compress-dialog-input-group\">\n <input\n type=\"text\"\n v-model=\"outputName\"\n placeholder=\"输入文件名\"\n />\n <span class=\"compress-dialog-ext\">{{ currentExt }}</span>\n </div>\n </div>\n\n <!-- 压缩格式 -->\n <div class=\"compress-dialog-field\">\n <label>压缩格式</label>\n <select v-model=\"format\">\n <option v-for=\"opt in FORMAT_OPTIONS\" :key=\"opt.value\" :value=\"opt.value\">\n {{ opt.label }}\n </option>\n </select>\n </div>\n\n <!-- 压缩级别 -->\n <div class=\"compress-dialog-field\">\n <label>压缩级别</label>\n <div class=\"compress-dialog-levels\">\n <label v-for=\"opt in LEVEL_OPTIONS\" :key=\"opt.value\" class=\"compress-dialog-level\">\n <input\n type=\"radio\"\n name=\"level\"\n :value=\"opt.value\"\n v-model=\"level\"\n />\n <span class=\"compress-dialog-level-label\">{{ opt.label }}</span>\n <span class=\"compress-dialog-level-desc\">{{ opt.desc }}</span>\n </label>\n </div>\n </div>\n\n <!-- 密码保护(仅 zip/7z) -->\n <div v-if=\"supportsPassword\" class=\"compress-dialog-field\">\n <label>密码保护(可选)</label>\n <div class=\"compress-dialog-input-group\">\n <input\n :type=\"showPassword ? 'text' : 'password'\"\n v-model=\"password\"\n placeholder=\"设置密码\"\n />\n <button\n type=\"button\"\n class=\"compress-dialog-toggle-password\"\n @click=\"showPassword = !showPassword\"\n >\n {{ showPassword ? '隐藏' : '显示' }}\n </button>\n </div>\n </div>\n\n <!-- 删除源文件选项 -->\n <div class=\"compress-dialog-field compress-dialog-checkbox\">\n <label>\n <input type=\"checkbox\" v-model=\"deleteSource\" />\n <span>压缩后删除源文件</span>\n </label>\n </div>\n\n <!-- 输出路径预览 -->\n <div class=\"compress-dialog-preview\">\n <span class=\"compress-dialog-preview-label\">输出位置:</span>\n <span class=\"compress-dialog-preview-path\">{{ fullOutputPath }}</span>\n </div>\n </div>\n\n <!-- 底部按钮 -->\n <div class=\"compress-dialog-footer\">\n <button class=\"compress-dialog-btn compress-dialog-btn-cancel\" @click=\"emit('cancel')\">\n 取消\n </button>\n <button \n class=\"compress-dialog-btn compress-dialog-btn-confirm\" \n @click=\"handleConfirm\"\n :disabled=\"!outputName.trim()\"\n >\n 压缩\n </button>\n </div>\n </div>\n </div>\n </Teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch } from 'vue';\nimport { Icon } from '@iconify/vue';\nimport type { CompressFormat, CompressLevel, CompressOptions } from '../types';\n\ntype CompressDialogOptions = Omit<CompressOptions, 'outputDir'>;\n\ninterface Props {\n visible: boolean;\n filePaths: string[];\n outputDir: string;\n}\n\nconst props = defineProps<Props>();\n\nconst emit = defineEmits<{\n confirm: [options: CompressDialogOptions];\n cancel: [];\n}>();\n\n/** 格式选项配置 */\nconst FORMAT_OPTIONS: { value: CompressFormat; label: string; ext: string }[] = [\n { value: 'zip', label: 'ZIP', ext: '.zip' },\n { value: 'tgz', label: 'TAR.GZ (gzip)', ext: '.tar.gz' },\n { value: 'tarbz2', label: 'TAR.BZ2 (bzip2)', ext: '.tar.bz2' },\n { value: 'tar', label: 'TAR (无压缩)', ext: '.tar' },\n];\n\n/** 压缩级别选项 */\nconst LEVEL_OPTIONS = [\n { value: 'fast', label: '快速', desc: '压缩速度快,文件较大' },\n { value: 'normal', label: '标准', desc: '平衡速度和大小' },\n { value: 'best', label: '最佳', desc: '文件最小,速度较慢' },\n] as const;\n\nconst format = ref<CompressFormat>('zip');\nconst level = ref<CompressLevel>('normal');\nconst outputName = ref('');\nconst deleteSource = ref(false);\nconst password = ref('');\nconst showPassword = ref(false);\n\n// 根据选中文件生成默认输出名称\nconst defaultOutputName = computed(() => {\n if (props.filePaths.length === 0) return 'archive';\n if (props.filePaths.length === 1) {\n const name = props.filePaths[0].split('/').pop() || 'archive';\n return name.replace(/\\.[^.]+$/, '');\n }\n return '压缩文件';\n});\n\n// 文件显示名称\nconst fileDisplayName = computed(() => {\n if (props.filePaths.length === 1) {\n return props.filePaths[0].split('/').pop();\n }\n return `${props.filePaths.length} 个项目`;\n});\n\n// 当前格式的扩展名\nconst currentExt = computed(() => {\n return FORMAT_OPTIONS.find(f => f.value === format.value)?.ext || '.zip';\n});\n\n// 完整输出路径预览\nconst fullOutputPath = computed(() => {\n return `${props.outputDir}/${outputName.value}${currentExt.value}`;\n});\n\n// 是否支持密码\nconst supportsPassword = computed(() => {\n // 当前后端未实现密码压缩,避免 UI 误导:直接关闭密码选项\n return false;\n});\n\n// 初始化\nwatch(() => props.visible, (visible) => {\n if (visible) {\n outputName.value = defaultOutputName.value;\n format.value = 'zip';\n level.value = 'normal';\n deleteSource.value = false;\n password.value = '';\n }\n});\n\nconst handleConfirm = () => {\n emit('confirm', {\n format: format.value,\n level: level.value,\n outputName: outputName.value + currentExt.value,\n deleteSource: deleteSource.value,\n });\n};\n</script>\n\n<style scoped>\n.compress-dialog-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n}\n\n.compress-dialog {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);\n width: 420px;\n max-width: 90vw;\n max-height: 90vh;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.compress-dialog-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid rgb(229, 231, 233);\n}\n\n.compress-dialog-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n font-size: 16px;\n color: rgb(17, 24, 39);\n}\n\n.compress-dialog-close {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: rgb(107, 114, 128);\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.compress-dialog-close:hover {\n background: rgb(243, 244, 246);\n color: rgb(55, 65, 81);\n}\n\n.compress-dialog-content {\n padding: 20px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.compress-dialog-info {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n background: rgb(249, 250, 251);\n border-radius: 8px;\n color: rgb(55, 65, 81);\n font-size: 14px;\n}\n\n.compress-dialog-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.compress-dialog-field > label {\n font-size: 13px;\n font-weight: 500;\n color: rgb(55, 65, 81);\n}\n\n.compress-dialog-input-group {\n display: flex;\n align-items: stretch;\n}\n\n.compress-dialog-input-group input {\n flex: 1;\n padding: 8px 12px;\n border: 1px solid rgb(209, 213, 219);\n border-radius: 6px 0 0 6px;\n font-size: 14px;\n outline: none;\n transition: border-color 0.2s;\n}\n\n.compress-dialog-input-group input:focus {\n border-color: rgb(59, 130, 246);\n}\n\n.compress-dialog-ext {\n padding: 8px 12px;\n background: rgb(243, 244, 246);\n border: 1px solid rgb(209, 213, 219);\n border-left: none;\n border-radius: 0 6px 6px 0;\n font-size: 14px;\n color: rgb(107, 114, 128);\n}\n\n.compress-dialog-toggle-password {\n padding: 8px 12px;\n background: rgb(243, 244, 246);\n border: 1px solid rgb(209, 213, 219);\n border-left: none;\n border-radius: 0 6px 6px 0;\n font-size: 12px;\n color: rgb(59, 130, 246);\n cursor: pointer;\n}\n\n.compress-dialog-toggle-password:hover {\n background: rgb(229, 231, 235);\n}\n\n.compress-dialog-field select {\n padding: 8px 12px;\n border: 1px solid rgb(209, 213, 219);\n border-radius: 6px;\n font-size: 14px;\n outline: none;\n background: white;\n cursor: pointer;\n}\n\n.compress-dialog-field select:focus {\n border-color: rgb(59, 130, 246);\n}\n\n.compress-dialog-levels {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.compress-dialog-level {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border: 1px solid rgb(229, 231, 233);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.compress-dialog-level:hover {\n background: rgb(249, 250, 251);\n}\n\n.compress-dialog-level:has(input:checked) {\n border-color: rgb(59, 130, 246);\n background: rgb(239, 246, 255);\n}\n\n.compress-dialog-level input {\n margin: 0;\n}\n\n.compress-dialog-level-label {\n font-size: 14px;\n font-weight: 500;\n color: rgb(17, 24, 39);\n}\n\n.compress-dialog-level-desc {\n font-size: 12px;\n color: rgb(107, 114, 128);\n margin-left: auto;\n}\n\n.compress-dialog-checkbox label {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n font-size: 14px;\n color: rgb(55, 65, 81);\n}\n\n.compress-dialog-checkbox input {\n margin: 0;\n width: 16px;\n height: 16px;\n}\n\n.compress-dialog-preview {\n padding: 10px 12px;\n background: rgb(249, 250, 251);\n border-radius: 6px;\n font-size: 12px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.compress-dialog-preview-label {\n color: rgb(107, 114, 128);\n}\n\n.compress-dialog-preview-path {\n color: rgb(55, 65, 81);\n word-break: break-all;\n}\n\n.compress-dialog-footer {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid rgb(229, 231, 233);\n}\n\n.compress-dialog-btn {\n padding: 8px 20px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.compress-dialog-btn-cancel {\n background: white;\n border: 1px solid rgb(209, 213, 219);\n color: rgb(55, 65, 81);\n}\n\n.compress-dialog-btn-cancel:hover {\n background: rgb(249, 250, 251);\n}\n\n.compress-dialog-btn-confirm {\n background: rgb(59, 130, 246);\n border: 1px solid rgb(59, 130, 246);\n color: white;\n}\n\n.compress-dialog-btn-confirm:hover {\n background: rgb(37, 99, 235);\n}\n\n.compress-dialog-btn-confirm:disabled {\n background: rgb(156, 163, 175);\n border-color: rgb(156, 163, 175);\n cursor: not-allowed;\n}\n</style>\n\n","<template>\n <Teleport to=\"body\">\n <div v-if=\"visible\" class=\"progress-dialog-overlay\">\n <div class=\"progress-dialog\">\n <!-- 头部 -->\n <div class=\"progress-dialog-header\">\n <div class=\"progress-dialog-title\">\n <Icon :icon=\"statusIconName\" width=\"24\" height=\"24\" :class=\"statusIconClass\" />\n <span>{{ title }}</span>\n </div>\n <button v-if=\"isCompleted\" class=\"progress-dialog-close\" @click=\"handleClose\">\n <Icon icon=\"lucide:x\" width=\"18\" height=\"18\" />\n </button>\n </div>\n\n <!-- 内容 -->\n <div class=\"progress-dialog-content\">\n <!-- 状态文本 -->\n <div class=\"progress-dialog-status\">{{ statusText }}</div>\n\n <!-- 进度条 -->\n <div v-if=\"progress.status === 'processing'\" class=\"progress-dialog-bar-container\">\n <div class=\"progress-dialog-bar\">\n <div \n class=\"progress-dialog-bar-fill\"\n :style=\"{ width: `${progress.percent}%` }\"\n />\n </div>\n <span class=\"progress-dialog-percent\">{{ progress.percent }}%</span>\n </div>\n\n <!-- 当前文件 -->\n <div v-if=\"progress.currentFile && progress.status === 'processing'\" class=\"progress-dialog-current-file\">\n {{ progress.currentFile }}\n </div>\n\n <!-- 文件计数 -->\n <div v-if=\"progress.totalCount && progress.totalCount > 0 && progress.status === 'processing'\" class=\"progress-dialog-count\">\n {{ progress.processedCount || 0 }} / {{ progress.totalCount }} 个文件\n </div>\n\n <!-- 错误信息 -->\n <div v-if=\"progress.error\" class=\"progress-dialog-error\">\n {{ progress.error }}\n </div>\n\n <!-- 成功后显示输出路径 -->\n <div v-if=\"progress.status === 'success' && progress.outputPath\" class=\"progress-dialog-output\">\n <span class=\"progress-dialog-output-label\">输出位置:</span>\n <span class=\"progress-dialog-output-path\">{{ progress.outputPath }}</span>\n </div>\n </div>\n\n <!-- 底部按钮 -->\n <div class=\"progress-dialog-footer\">\n <button \n v-if=\"progress.status === 'processing'\" \n class=\"progress-dialog-btn progress-dialog-btn-cancel\" \n @click=\"emit('cancel')\"\n >\n 取消\n </button>\n <button \n v-if=\"progress.status === 'success' && progress.outputPath\"\n class=\"progress-dialog-btn progress-dialog-btn-folder\" \n @click=\"emit('openFolder', progress.outputPath!)\"\n >\n <Icon icon=\"lucide:folder-open\" width=\"16\" height=\"16\" />\n 打开文件夹\n </button>\n <button \n v-if=\"isCompleted\"\n class=\"progress-dialog-btn progress-dialog-btn-close\" \n @click=\"handleClose\"\n >\n 关闭\n </button>\n </div>\n </div>\n </div>\n </Teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { Icon } from '@iconify/vue';\n\n/** 进度状态 */\nexport type ProgressStatus = 'pending' | 'processing' | 'success' | 'error';\n\n/** 进度信息 */\nexport interface ProgressInfo {\n type: 'compress' | 'extract';\n status: ProgressStatus;\n percent: number;\n currentFile?: string;\n processedCount?: number;\n totalCount?: number;\n error?: string;\n outputPath?: string;\n}\n\ninterface Props {\n visible: boolean;\n progress: ProgressInfo;\n}\n\nconst props = defineProps<Props>();\n\nconst emit = defineEmits<{\n cancel: [];\n close: [];\n openFolder: [path: string];\n}>();\n\nconst title = computed(() => props.progress.type === 'compress' ? '压缩文件' : '解压文件');\nconst isCompleted = computed(() => props.progress.status === 'success' || props.progress.status === 'error');\n\nconst statusIconName = computed(() => {\n switch (props.progress.status) {\n case 'processing': return 'lucide:loader-2';\n case 'success': return 'lucide:check-circle';\n case 'error': return 'lucide:x-circle';\n default: return 'lucide:archive';\n }\n});\n\nconst statusIconClass = computed(() => {\n switch (props.progress.status) {\n case 'processing': return 'progress-dialog-icon-spin';\n case 'success': return 'progress-dialog-icon-success';\n case 'error': return 'progress-dialog-icon-error';\n default: return '';\n }\n});\n\nconst statusText = computed(() => {\n switch (props.progress.status) {\n case 'pending': return '准备中...';\n case 'processing': return props.progress.type === 'compress' ? '正在压缩...' : '正在解压...';\n case 'success': return props.progress.type === 'compress' ? '压缩完成' : '解压完成';\n case 'error': return '操作失败';\n default: return '';\n }\n});\n\nconst handleClose = () => {\n if (isCompleted.value) {\n emit('close');\n } else {\n emit('cancel');\n }\n};\n</script>\n\n<style scoped>\n.progress-dialog-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10001;\n}\n\n.progress-dialog {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);\n width: 380px;\n max-width: 90vw;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.progress-dialog-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid rgb(229, 231, 233);\n}\n\n.progress-dialog-title {\n display: flex;\n align-items: center;\n gap: 10px;\n font-weight: 600;\n font-size: 16px;\n color: rgb(17, 24, 39);\n}\n\n.progress-dialog-close {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: rgb(107, 114, 128);\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.progress-dialog-close:hover {\n background: rgb(243, 244, 246);\n color: rgb(55, 65, 81);\n}\n\n.progress-dialog-content {\n padding: 24px 20px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.progress-dialog-status {\n font-size: 14px;\n color: rgb(55, 65, 81);\n text-align: center;\n}\n\n.progress-dialog-bar-container {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.progress-dialog-bar {\n flex: 1;\n height: 8px;\n background: rgb(229, 231, 233);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.progress-dialog-bar-fill {\n height: 100%;\n background: rgb(59, 130, 246);\n border-radius: 4px;\n transition: width 0.3s ease;\n}\n\n.progress-dialog-percent {\n font-size: 13px;\n font-weight: 500;\n color: rgb(55, 65, 81);\n min-width: 40px;\n text-align: right;\n}\n\n.progress-dialog-current-file {\n font-size: 12px;\n color: rgb(107, 114, 128);\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.progress-dialog-count {\n font-size: 12px;\n color: rgb(107, 114, 128);\n text-align: center;\n}\n\n.progress-dialog-error {\n padding: 12px;\n background: rgb(254, 242, 242);\n border: 1px solid rgb(254, 202, 202);\n border-radius: 6px;\n color: rgb(185, 28, 28);\n font-size: 13px;\n}\n\n.progress-dialog-output {\n padding: 12px;\n background: rgb(240, 253, 244);\n border: 1px solid rgb(187, 247, 208);\n border-radius: 6px;\n font-size: 12px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.progress-dialog-output-label {\n color: rgb(22, 101, 52);\n font-weight: 500;\n}\n\n.progress-dialog-output-path {\n color: rgb(21, 128, 61);\n word-break: break-all;\n}\n\n.progress-dialog-footer {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid rgb(229, 231, 233);\n}\n\n.progress-dialog-btn {\n padding: 8px 16px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.progress-dialog-btn-cancel {\n background: white;\n border: 1px solid rgb(209, 213, 219);\n color: rgb(55, 65, 81);\n}\n\n.progress-dialog-btn-cancel:hover {\n background: rgb(249, 250, 251);\n}\n\n.progress-dialog-btn-folder {\n background: rgb(240, 253, 244);\n border: 1px solid rgb(187, 247, 208);\n color: rgb(22, 101, 52);\n}\n\n.progress-dialog-btn-folder:hover {\n background: rgb(220, 252, 231);\n}\n\n.progress-dialog-btn-close {\n background: rgb(59, 130, 246);\n border: 1px solid rgb(59, 130, 246);\n color: white;\n}\n\n.progress-dialog-btn-close:hover {\n background: rgb(37, 99, 235);\n}\n\n/* 旋转动画 */\n.progress-dialog-icon-spin {\n animation: spin 1s linear infinite;\n color: rgb(59, 130, 246);\n}\n\n@keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n\n.progress-dialog-icon-success {\n color: rgb(34, 197, 94);\n}\n\n.progress-dialog-icon-error {\n color: rgb(239, 68, 68);\n}\n</style>\n\n","<!--\n FileInfoDialog - 文件信息弹窗组件\n 显示文件/文件夹的详细信息\n-->\n<template>\n <Teleport to=\"body\">\n <div v-if=\"visible && item\" class=\"file-info-dialog-overlay\" @click=\"handleBackdropClick\">\n <div class=\"file-info-dialog\">\n <!-- 头部 -->\n <div class=\"file-info-dialog-header\">\n <div class=\"file-info-dialog-title\">\n <Icon :icon=\"getFileIcon(item.type, item.name)\" width=\"48\" height=\"48\" class=\"file-info-icon\" :class=\"getIconClass(item.type)\" />\n <span class=\"file-info-dialog-name\" :title=\"item.name\">\n {{ item.name }}\n </span>\n </div>\n <button class=\"file-info-dialog-close\" @click=\"emit('close')\">\n <Icon icon=\"lucide:x\" width=\"18\" height=\"18\" />\n </button>\n </div>\n\n <!-- 内容 -->\n <div class=\"file-info-dialog-content\">\n <!-- 类型 -->\n <div class=\"file-info-row\">\n <div class=\"file-info-label\">\n <Icon icon=\"lucide:file\" width=\"14\" height=\"14\" />\n <span>类型</span>\n </div>\n <div class=\"file-info-value\">\n {{ getFileTypeName(item.type, extension) }}\n </div>\n </div>\n\n <!-- 大小 -->\n <div v-if=\"item.type !== FileType.FOLDER && item.size\" class=\"file-info-row\">\n <div class=\"file-info-label\">\n <Icon icon=\"lucide:hard-drive\" width=\"14\" height=\"14\" />\n <span>大小</span>\n </div>\n <div class=\"file-info-value\">\n {{ item.size }}\n </div>\n </div>\n\n <!-- 位置 -->\n <div class=\"file-info-row\">\n <div class=\"file-info-label\">\n <Icon icon=\"lucide:map-pin\" width=\"14\" height=\"14\" />\n <span>位置</span>\n </div>\n <div class=\"file-info-value file-info-value--path\" :title=\"directory\">\n {{ directory }}\n </div>\n </div>\n\n <!-- 完整路径 -->\n <div class=\"file-info-row\">\n <div class=\"file-info-label\">\n <Icon icon=\"lucide:map-pin\" width=\"14\" height=\"14\" />\n <span>完整路径</span>\n </div>\n <div class=\"file-info-value file-info-value--path\" :title=\"item.id\">\n {{ item.id }}\n </div>\n </div>\n\n <!-- 修改时间 -->\n <div v-if=\"item.dateModified\" class=\"file-info-row\">\n <div class=\"file-info-label\">\n <Icon icon=\"lucide:clock\" width=\"14\" height=\"14\" />\n <span>修改时间</span>\n </div>\n <div class=\"file-info-value\">\n {{ item.dateModified }}\n </div>\n </div>\n </div>\n\n <!-- 底部按钮 -->\n <div class=\"file-info-dialog-footer\">\n <button class=\"file-info-dialog-btn\" @click=\"emit('close')\">\n 关闭\n </button>\n </div>\n </div>\n </div>\n </Teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onMounted, onUnmounted } from 'vue';\nimport { Icon } from '@iconify/vue';\nimport { FileType, type FileItem } from '../types';\nimport { getFileTypeIcon } from '../utils/fileTypeIcon';\n\nconst props = defineProps<{\n /** 是否显示 */\n visible: boolean;\n /** 文件项 */\n item: FileItem | null;\n}>();\n\nconst emit = defineEmits<{\n close: [];\n}>();\n\n/** 获取文件类型图标 */\nfunction getFileIcon(type: FileType, name?: string): string {\n // 文件夹使用 material-icon-theme:folder\n if (type === FileType.FOLDER) {\n return 'flat-color-icons:folder';\n }\n \n // 如果有文件名,使用 material-icon-theme 图标映射(传递 type 作为兜底)\n if (name) {\n return getFileTypeIcon(name, type);\n }\n \n // 回退逻辑(没有文件名时)\n switch (type) {\n case FileType.IMAGE: return 'material-icon-theme:image';\n case FileType.VIDEO: return 'material-icon-theme:video';\n case FileType.MUSIC: return 'material-icon-theme:audio';\n case FileType.DOCUMENT: return 'material-icon-theme:word';\n case FileType.CODE: return 'material-icon-theme:javascript';\n case FileType.ARCHIVE: return 'material-icon-theme:zip';\n default: return 'material-icon-theme:document';\n }\n}\n\n/** 获取图标样式类 */\nfunction getIconClass(type: FileType): string {\n switch (type) {\n case FileType.FOLDER: return 'file-info-icon--folder';\n case FileType.IMAGE: return 'file-info-icon--image';\n case FileType.VIDEO: return 'file-info-icon--video';\n case FileType.MUSIC: return 'file-info-icon--music';\n case FileType.DOCUMENT: return 'file-info-icon--document';\n case FileType.CODE: return 'file-info-icon--code';\n case FileType.ARCHIVE: return 'file-info-icon--archive';\n default: return 'file-info-icon--file';\n }\n}\n\n/** 获取文件类型名称 */\nfunction getFileTypeName(type: FileType, ext?: string): string {\n switch (type) {\n case FileType.FOLDER: return '文件夹';\n case FileType.IMAGE: return `图片${ext ? ` (${ext.toUpperCase()})` : ''}`;\n case FileType.VIDEO: return `视频${ext ? ` (${ext.toUpperCase()})` : ''}`;\n case FileType.MUSIC: return `音频${ext ? ` (${ext.toUpperCase()})` : ''}`;\n case FileType.DOCUMENT: return `文档${ext ? ` (${ext.toUpperCase()})` : ''}`;\n case FileType.CODE: return `代码文件${ext ? ` (${ext.toUpperCase()})` : ''}`;\n case FileType.ARCHIVE: return `压缩包${ext ? ` (${ext.toUpperCase()})` : ''}`;\n default: return ext ? `${ext.toUpperCase()} 文件` : '文件';\n }\n}\n\n/** 获取文件扩展名 */\nconst extension = computed(() => {\n if (!props.item) return undefined;\n const lastDot = props.item.name.lastIndexOf('.');\n if (lastDot === -1 || lastDot === 0) return undefined;\n return props.item.name.substring(lastDot + 1).toLowerCase();\n});\n\n/** 获取文件所在目录 */\nconst directory = computed(() => {\n if (!props.item) return '';\n const lastSlash = props.item.id.lastIndexOf('/');\n if (lastSlash === -1) return props.item.id;\n return props.item.id.substring(0, lastSlash) || '/';\n});\n\n/** 点击背景关闭 */\nfunction handleBackdropClick(e: MouseEvent) {\n if (e.target === e.currentTarget) {\n emit('close');\n }\n}\n\n/** ESC 关闭 */\nfunction handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape' && props.visible) {\n emit('close');\n }\n}\n\nonMounted(() => {\n document.addEventListener('keydown', handleKeyDown);\n});\n\nonUnmounted(() => {\n document.removeEventListener('keydown', handleKeyDown);\n});\n</script>\n\n<style scoped>\n/* FileInfoDialog 样式 */\n\n.file-info-dialog-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n animation: file-info-fadeIn 0.15s ease-out;\n}\n\n@keyframes file-info-fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.file-info-dialog {\n background: #ffffff;\n border: 1px solid #e0e0e0;\n border-radius: 12px;\n width: 420px;\n max-width: 90vw;\n max-height: 80vh;\n display: flex;\n flex-direction: column;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15), 0 2px 8px rgba(0, 0, 0, 0.1);\n animation: file-info-slideIn 0.2s ease-out;\n}\n\n@keyframes file-info-slideIn {\n from {\n opacity: 0;\n transform: scale(0.95) translateY(-10px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n\n/* 深色模式 */\n@media (prefers-color-scheme: dark) {\n .file-info-dialog {\n background: #2d2d2d;\n border-color: #404040;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n }\n}\n\n/* 头部 */\n.file-info-dialog-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid #e0e0e0;\n gap: 12px;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-dialog-header {\n border-bottom-color: #404040;\n }\n}\n\n.file-info-dialog-title {\n display: flex;\n align-items: center;\n gap: 10px;\n min-width: 0;\n flex: 1;\n}\n\n.file-info-dialog-name {\n font-size: 16px;\n font-weight: 600;\n color: #1a1a1a;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-dialog-name {\n color: #e0e0e0;\n }\n}\n\n.file-info-dialog-close {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: #666;\n border-radius: 6px;\n cursor: pointer;\n flex-shrink: 0;\n transition: all 0.15s ease;\n}\n\n.file-info-dialog-close:hover {\n background: #f0f0f0;\n color: #333;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-dialog-close {\n color: #888;\n }\n .file-info-dialog-close:hover {\n background: #404040;\n color: #e0e0e0;\n }\n}\n\n/* 内容 */\n.file-info-dialog-content {\n padding: 16px 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n overflow-y: auto;\n}\n\n.file-info-row {\n display: flex;\n align-items: flex-start;\n gap: 16px;\n}\n\n.file-info-label {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 90px;\n flex-shrink: 0;\n color: #666;\n font-size: 13px;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-label {\n color: #888;\n }\n}\n\n.file-info-label svg {\n flex-shrink: 0;\n}\n\n.file-info-value {\n flex: 1;\n color: #1a1a1a;\n font-size: 13px;\n word-break: break-all;\n line-height: 1.4;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-value {\n color: #e0e0e0;\n }\n}\n\n.file-info-value--path {\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', monospace;\n font-size: 12px;\n background: #f5f5f5;\n padding: 4px 8px;\n border-radius: 4px;\n user-select: all;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-value--path {\n background: #383838;\n }\n}\n\n/* 图标样式 */\n.file-info-icon {\n width: 32px;\n height: 32px;\n flex-shrink: 0;\n}\n\n.file-info-icon--folder {\n color: #dcb67a;\n}\n\n.file-info-icon--image {\n color: #7ec699;\n}\n\n.file-info-icon--video {\n color: #c678dd;\n}\n\n.file-info-icon--music {\n color: #e06c75;\n}\n\n.file-info-icon--document {\n color: #61afef;\n}\n\n.file-info-icon--code {\n color: #98c379;\n}\n\n.file-info-icon--archive {\n color: #d19a66;\n}\n\n.file-info-icon--file {\n color: #abb2bf;\n}\n\n/* 底部 */\n.file-info-dialog-footer {\n display: flex;\n justify-content: flex-end;\n padding: 12px 20px;\n border-top: 1px solid #e0e0e0;\n}\n\n@media (prefers-color-scheme: dark) {\n .file-info-dialog-footer {\n border-top-color: #404040;\n }\n}\n\n.file-info-dialog-btn {\n padding: 6px 16px;\n border: none;\n border-radius: 6px;\n font-size: 13px;\n cursor: pointer;\n transition: all 0.15s ease;\n background: #007aff;\n color: white;\n}\n\n.file-info-dialog-btn:hover {\n background: #0066d6;\n}\n</style>\n\n","import { ref } from 'vue';\nimport type { FileItem } from '../types';\n\n/**\n * 文件选择状态管理\n */\nexport function useSelection() {\n const selectedIds = ref<Set<string>>(new Set());\n const lastSelectedId = ref<string | null>(null);\n const editingId = ref<string | null>(null);\n\n /**\n * 清除选择\n */\n const clearSelection = () => {\n selectedIds.value = new Set();\n lastSelectedId.value = null;\n };\n\n /**\n * 选择项目\n * @param id 项目 ID(null 表示清除选择)\n * @param items 当前显示的项目列表\n * @param multi 是否多选(Cmd/Ctrl)\n * @param range 是否范围选择(Shift)\n */\n const selectItem = (\n id: string | null, \n items: FileItem[],\n multi: boolean = false, \n range: boolean = false\n ) => {\n if (!id) {\n clearSelection();\n return;\n }\n\n // 范围选择\n if (range && lastSelectedId.value) {\n const indexA = items.findIndex(i => i.id === lastSelectedId.value);\n const indexB = items.findIndex(i => i.id === id);\n \n if (indexA !== -1 && indexB !== -1) {\n const start = Math.min(indexA, indexB);\n const end = Math.max(indexA, indexB);\n const newSet = new Set(multi ? selectedIds.value : []);\n for (let i = start; i <= end; i++) {\n const item = items[i];\n if (item) {\n newSet.add(item.id);\n }\n }\n selectedIds.value = newSet;\n return;\n }\n }\n\n // 多选切换\n if (multi) {\n const newSet = new Set(selectedIds.value);\n if (newSet.has(id)) {\n newSet.delete(id);\n } else {\n newSet.add(id);\n }\n lastSelectedId.value = id;\n selectedIds.value = newSet;\n return;\n }\n\n // 单选\n lastSelectedId.value = id;\n selectedIds.value = new Set([id]);\n };\n\n /**\n * 全选\n */\n const selectAll = (items: FileItem[]) => {\n selectedIds.value = new Set(items.map(i => i.id));\n };\n\n /**\n * 设置编辑状态\n */\n const setEditing = (id: string | null) => {\n editingId.value = id;\n };\n\n /**\n * 检查是否选中\n */\n const isSelected = (id: string): boolean => {\n return selectedIds.value.has(id);\n };\n\n return {\n selectedIds,\n lastSelectedId,\n editingId,\n clearSelection,\n selectItem,\n selectAll,\n setEditing,\n isSelected\n };\n}\n","import { ref } from 'vue';\nimport type { FileItem } from '../types';\nimport { FileType } from '../types';\n\n/**\n * 拖拽操作管理\n */\nexport function useDragAndDrop(\n getSelectedIds: () => Set<string>,\n onSelect: (id: string, multi: boolean, range: boolean) => void,\n onMove: (targetFolderId: string, itemIds: Set<string>) => void\n) {\n const dragOverId = ref<string | null>(null);\n const isDragging = ref(false);\n\n /**\n * 开始拖拽\n */\n const handleDragStart = (e: DragEvent, itemId: string) => {\n if (!e.dataTransfer) return;\n \n const selectedIds = getSelectedIds();\n \n // 如果拖拽的项目未被选中,先选中它\n if (!selectedIds.has(itemId)) {\n onSelect(itemId, false, false);\n }\n\n // 设置拖拽数据\n const draggedIds = selectedIds.has(itemId) ? selectedIds : new Set([itemId]);\n e.dataTransfer.setData('text/plain', JSON.stringify([...draggedIds]));\n e.dataTransfer.effectAllowed = 'move';\n \n isDragging.value = true;\n };\n\n /**\n * 拖拽经过\n */\n const handleDragOver = (e: DragEvent, item: FileItem) => {\n if (!isDragging.value) return;\n \n // 只有文件夹可以作为放置目标\n if (item.type === FileType.FOLDER) {\n const selectedIds = getSelectedIds();\n // 不能拖拽到自己身上\n if (!selectedIds.has(item.id)) {\n e.preventDefault();\n dragOverId.value = item.id;\n }\n }\n };\n\n /**\n * 拖拽离开\n */\n const handleDragLeave = () => {\n dragOverId.value = null;\n };\n\n /**\n * 放置\n */\n const handleDrop = (e: DragEvent, targetItem: FileItem) => {\n dragOverId.value = null;\n isDragging.value = false;\n\n if (!e.dataTransfer || targetItem.type !== FileType.FOLDER) return;\n\n const data = e.dataTransfer.getData('text/plain');\n if (!data) return;\n\n try {\n const draggedIds: string[] = JSON.parse(data);\n const itemIds = new Set(draggedIds);\n \n // 不能移动到自己\n if (itemIds.has(targetItem.id)) return;\n \n onMove(targetItem.id, itemIds);\n } catch {\n // 忽略解析错误\n }\n };\n\n /**\n * 拖拽结束\n */\n const handleDragEnd = () => {\n dragOverId.value = null;\n isDragging.value = false;\n };\n\n return {\n dragOverId,\n isDragging,\n handleDragStart,\n handleDragOver,\n handleDragLeave,\n handleDrop,\n handleDragEnd\n };\n}\n","import { ref, nextTick } from 'vue';\nimport { FileType } from '../types';\n\n/**\n * 媒体播放器功能管理\n */\nexport function useMediaPlayer(\n mediaType: FileType,\n mediaRef: () => HTMLVideoElement | HTMLAudioElement | null\n) {\n const isPlaying = ref(false);\n const progress = ref(0);\n const currentTime = ref(0);\n const duration = ref(0);\n const isMuted = ref(false);\n const volume = ref(1);\n const lastVolume = ref(1);\n const showControls = ref(false);\n\n const isAudio = mediaType === FileType.MUSIC;\n\n /**\n * 更新播放进度\n */\n const updateProgress = () => {\n const media = mediaRef();\n if (media) {\n const curr = media.currentTime;\n const dur = media.duration;\n currentTime.value = curr;\n if (dur && !isNaN(dur)) {\n duration.value = dur;\n progress.value = (curr / dur) * 100;\n }\n }\n };\n\n /**\n * 切换播放/暂停\n */\n const togglePlay = () => {\n const media = mediaRef();\n if (media) {\n if (isPlaying.value) {\n media.pause();\n isPlaying.value = false;\n } else {\n media.play();\n isPlaying.value = true;\n }\n }\n };\n\n /**\n * 切换静音\n */\n const toggleMute = () => {\n const media = mediaRef();\n if (media) {\n if (isMuted.value) {\n const volToRestore = lastVolume.value || 1;\n media.volume = volToRestore;\n media.muted = false;\n volume.value = volToRestore;\n isMuted.value = false;\n } else {\n lastVolume.value = volume.value;\n media.volume = 0;\n media.muted = true;\n volume.value = 0;\n isMuted.value = true;\n }\n }\n };\n\n /**\n * 音量变化\n */\n const handleVolumeChange = (val: number) => {\n volume.value = val;\n const media = mediaRef();\n if (media) {\n media.volume = val;\n if (val === 0) {\n isMuted.value = true;\n media.muted = true;\n } else {\n isMuted.value = false;\n media.muted = false;\n }\n }\n };\n\n /**\n * 跳转到指定时间\n */\n const seekTo = (time: number) => {\n const media = mediaRef();\n if (media && duration.value) {\n media.currentTime = time;\n currentTime.value = time;\n progress.value = (time / duration.value) * 100;\n }\n };\n\n /**\n * 格式化时间显示\n */\n const formatTime = (time: number) => {\n if (isNaN(time)) return '0:00';\n const minutes = Math.floor(time / 60);\n const seconds = Math.floor(time % 60);\n return `${minutes}:${seconds.toString().padStart(2, '0')}`;\n };\n\n /**\n * 自动播放\n */\n const autoPlay = () => {\n nextTick(() => {\n const media = mediaRef();\n if ((mediaType === FileType.VIDEO || isAudio) && media) {\n media.volume = volume.value;\n media.play().catch(() => {});\n isPlaying.value = true;\n }\n });\n };\n\n /**\n * 监听媒体事件\n */\n const setupMediaListeners = () => {\n const media = mediaRef();\n if (media) {\n media.addEventListener('timeupdate', updateProgress);\n media.addEventListener('loadedmetadata', updateProgress);\n media.addEventListener('ended', () => {\n isPlaying.value = false;\n });\n }\n };\n\n /**\n * 清理媒体事件监听\n */\n const cleanupMediaListeners = () => {\n const media = mediaRef();\n if (media) {\n media.removeEventListener('timeupdate', updateProgress);\n media.removeEventListener('loadedmetadata', updateProgress);\n }\n };\n\n return {\n isPlaying,\n progress,\n currentTime,\n duration,\n isMuted,\n volume,\n showControls,\n isAudio,\n togglePlay,\n toggleMute,\n handleVolumeChange,\n seekTo,\n formatTime,\n autoPlay,\n setupMediaListeners,\n cleanupMediaListeners,\n updateProgress\n };\n}\n","import { ref, watch } from 'vue';\nimport type { FileItem } from '../types';\nimport { FileType } from '../types';\n\n// 扩展 Window 类型\ndeclare global {\n interface Window {\n fileExplorerAPI?: {\n getApplicationIcon?: (appPath: string) => Promise<string | null>;\n };\n }\n}\n\n/**\n * 应用程序图标管理 composable\n */\nexport function useApplicationIcon(items: () => FileItem[]) {\n // 应用程序图标缓存(避免重复请求)\n const appIconCache = new Map<string, string>();\n\n // 使用响应式的图标 URL 映射\n const appIconUrls = ref<Map<string, string>>(new Map());\n\n /**\n * 为应用程序获取图标\n */\n const loadApplicationIcon = async (item: FileItem) => {\n if (item.type !== FileType.APPLICATION || !item.id) return;\n \n // 检查缓存\n if (appIconCache.has(item.id)) {\n const cachedUrl = appIconCache.get(item.id);\n if (cachedUrl) {\n appIconUrls.value.set(item.id, cachedUrl);\n }\n return;\n }\n \n // 检查响应式映射\n if (appIconUrls.value.has(item.id)) {\n return;\n }\n \n if (typeof window.fileExplorerAPI !== 'undefined' && window.fileExplorerAPI.getApplicationIcon) {\n try {\n const iconUrl = await window.fileExplorerAPI.getApplicationIcon(item.id);\n if (iconUrl) {\n appIconCache.set(item.id, iconUrl);\n appIconUrls.value.set(item.id, iconUrl);\n }\n } catch (error) {\n console.error(`Failed to load application icon for ${item.name}:`, error);\n }\n }\n };\n\n /**\n * 监听 items 变化,为应用程序加载图标\n */\n watch(items, (newItems) => {\n newItems.forEach(item => {\n if (item.type === FileType.APPLICATION && !appIconUrls.value.has(item.id)) {\n loadApplicationIcon(item);\n }\n });\n }, { immediate: true, deep: true });\n\n /**\n * 获取应用程序图标的响应式 URL\n */\n const getAppIconUrl = (item: FileItem): string | undefined => {\n return appIconUrls.value.get(item.id);\n };\n\n return {\n getAppIconUrl,\n loadApplicationIcon\n };\n}\n"],"names":["FileType","KNOWN_TYPES","EXT_MAP","SPECIAL_FILES","getFileTypeIcon","fileName","fallbackType","lowerName","type","lastDotIndex","ext","baseName","getFallbackIcon","ALIASES","getFolderTypeIcon","folderName","name","lower","standardName","props","__props","iconName","computed","iconClass","base","_createElementBlock","_createVNode","_unref","Icon","splitFileName","isFolder","lastDot","fileNameCache","getFileNameParts","item","key","emit","__emit","handleEmptyContextMenu","e","hasThumbnail","_a","handleRename","newName","handleEnterKey","handleEscapeKey","input","i","_Fragment","_renderList","$event","$emit","_withModifiers","_cache","_normalizeClass","_createElementVNode","_hoisted_2","_openBlock","_hoisted_4","_createBlock","FileIcon","_hoisted_7","_hoisted_10","_toDisplayString","_hoisted_11","_createTextVNode","_hoisted_1","getTypeLabel","SortIndicator","_b","_c","_d","_hoisted_3","index","_hoisted_5","selectedIds","ref","editingId","dragOverId","sortConfig","selectedItems","handleSelect","newSet","lastId","lastIndex","currentIndex","start","end","handleEmptyClick","clearSelection","handleOpen","handleContextMenu","target","handleEmptyContextMenuFromChild","handleNameClick","handleRenameCancel","handleSort","field","handleDragStart","handleDragOver","handleDragLeave","handleDrop","targetItem","data","draggedIds","error","__expose","id","FileGrid","FileList","getIconName","handleNavigate","section","handleClick","_renderSlot","_ctx","Breadcrumb","$slots","_hoisted_6","_hoisted_9","MARGIN","MENU_WIDTH","MENU_ITEM_HEIGHT","SEPARATOR_HEIGHT","MENU_PADDING","SUBMENU_GAP","estimateMenuHeight","items","height","calculateMenuPosition","clickX","clickY","menuHeight","viewportWidth","viewportHeight","adjustedX","adjustedY","spaceRight","spaceLeft","spaceBottom","spaceTop","calculateSubmenuPosition","parentRect","submenuHeight","submenuX","submenuY","menuRef","hoveredItemId","submenuPosition","itemRefs","position","estimatedHeight","menuStyle","submenuStyle","hoveredItem","opt","setItemRef","el","hasChildren","option","watch","newId","nextTick","itemEl","rect","visible","handleClickOutside","menuContainer","handleEscape","onUnmounted","handleOptionClick","handleItemMouseEnter","keepSubmenuOpen","closeSubmenu","_Teleport","child","childIndex","_hoisted_8","useWindowDrag","isDragging","handleMouseMove","handleMouseUp","startDrag","dragging","useWindowResize","initialWidth","initialHeight","minWidth","minHeight","maxWidth","maxHeight","width","isResizing","resizeDirection","startX","startY","startWidth","startHeight","deltaX","deltaY","newWidth","newHeight","direction","startResize","currentWidth","currentHeight","getCursorForDirection","resizing","windowContainerRef","windowDrag","isAutoSize","getInitialSize","defaultWidth","defaultHeight","parseSize","size","defaultPx","minW","minH","maxW","maxH","windowResize","windowStyle","baseStyle","translateX","translateY","handleBackdropClick","handleClose","handleMinimize","handleMaximize","handleResizeStart","onMounted","handleEsc","FORMAT_OPTIONS","LEVEL_OPTIONS","format","level","outputName","deleteSource","password","showPassword","defaultOutputName","fileDisplayName","currentExt","f","fullOutputPath","supportsPassword","handleConfirm","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","title","isCompleted","statusIconName","statusIconClass","statusText","_normalizeStyle","_hoisted_12","getFileIcon","getIconClass","getFileTypeName","extension","directory","lastSlash","handleKeyDown","_hoisted_17","useSelection","lastSelectedId","multi","range","indexA","indexB","useDragAndDrop","getSelectedIds","onSelect","onMove","itemId","itemIds","useMediaPlayer","mediaType","mediaRef","isPlaying","progress","currentTime","duration","isMuted","volume","lastVolume","showControls","isAudio","updateProgress","media","curr","dur","volToRestore","val","time","minutes","seconds","useApplicationIcon","appIconCache","appIconUrls","loadApplicationIcon","cachedUrl","iconUrl","newItems"],"mappings":";;AAGO,MAAMA,IAAW;AAAA,EACtB,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,UAAU;AAAA,EACV,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,SAAS;AAAA,EACT,aAAa;AAAA,EACb,SAAS;AACX,GCHMC,yBAAkB,IAAI;AAAA,EAC1B;AAAA,EAAM;AAAA,EAAgB;AAAA,EAAO;AAAA,EAAqB;AAAA,EAAmB;AAAA,EACrE;AAAA,EAAW;AAAA,EAAe;AAAA,EAAW;AAAA,EAAY;AAAA,EAAY;AAAA,EAAS;AAAA,EACtE;AAAA,EAAW;AAAA,EAAS;AAAA,EAAa;AAAA,EAAS;AAAA,EAAS;AAAA,EAAW;AAAA,EAAS;AAAA,EACvE;AAAA,EAAK;AAAA,EAAS;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAe;AAAA,EAAa;AAAA,EAAY;AAAA,EACvE;AAAA,EAAW;AAAA,EAAS;AAAA,EAAS;AAAA,EAAU;AAAA,EAAW;AAAA,EAAW;AAAA,EAC7D;AAAA,EAAc;AAAA,EAAW;AAAA,EAAO;AAAA,EAAW;AAAA,EAAU;AAAA,EAAO;AAAA,EAAW;AAAA,EACvE;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAW;AAAA,EAAK;AAAA,EAAQ;AAAA,EAAY;AAAA,EAAQ;AAAA,EAAc;AAAA,EAC5E;AAAA,EAAU;AAAA,EAAU;AAAA,EAAY;AAAA,EAAU;AAAA,EAAW;AAAA,EAAgB;AAAA,EACrE;AAAA,EAAU;AAAA,EAAO;AAAA,EAAS;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAW;AAAA,EAChE;AAAA,EAAc;AAAA,EAAO;AAAA,EAAW;AAAA,EAAS;AAAA,EAAY;AAAA,EAAS;AAAA,EAAQ;AAAA,EACtE;AAAA,EAAS;AAAA,EAAW;AAAA,EAAc;AAAA,EAAU;AAAA,EAAa;AAAA,EAAU;AAAA,EAAO;AAAA,EAC1E;AAAA,EAAU;AAAA,EAAO;AAAA,EAAU;AAAA,EAAS;AAAA,EAAM;AAAA,EAAU;AAAA,EAAS;AAAA,EAAU;AAAA,EACvE;AAAA,EAAU;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAK;AAAA,EAAQ;AAAA,EAAc;AAAA,EAAW;AAAA,EAAW;AAAA,EAC5E;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAS;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAQ;AAAA,EACzE;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAa;AAAA,EAAc;AAAA,EAC3D;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAY;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAW;AAAA,EACpE;AAAA,EAAS;AAAA,EAAO;AAAA,EAAU;AAAA,EAAc;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAY;AAAA,EACvE;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAW;AAAA,EAAc;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAc;AAAA,EACxE;AAAA,EAAO;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAY;AAAA,EAAY;AAAA,EAAgB;AAAA,EAAU;AAAA,EACxE;AAAA,EAAO;AAAA,EAAa;AAAA,EAAW;AAAA,EAAS;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAS;AAAA,EACtE;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAO;AAAA,EAAO;AAAA,EAAU;AAAA,EAAW;AAAA,EACvE;AAAA,EAAS;AAAA,EAAY;AAAA,EAAQ;AAAA,EAAM;AAAA,EAAe;AAAA,EAAiB;AAAA,EAAS;AAAA,EAC5E;AAAA,EAAW;AAAA,EAAY;AAAA,EAAU;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAW;AAAA,EAClE;AAAA,EAAY;AAAA,EAAc;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAc;AAAA,EAAc;AAAA,EACzE;AAAA,EAAU;AAAA,EAAc;AAAA,EAAU;AAAA,EAAS;AAAA,EAAO;AAAA,EAAU;AAAA,EAAc;AAAA,EAC1E;AAAA,EAAW;AAAA,EAAU;AAAA,EAAK;AAAA,EAAU;AAAA,EAAS;AAAA,EAAS;AAAA,EAAY;AAAA,EAAU;AAAA,EAC5E;AAAA,EAAU;AAAA,EAAS;AAAA,EAAY;AAAA,EAAU;AAAA,EAAY;AAAA,EAAQ;AAAA,EAAW;AAAA,EACxE;AAAA,EAAU;AAAA,EAAU;AAAA,EAAW;AAAA,EAAS;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAC3E;AAAA,EAAO;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAS;AAAA,EAAU;AAAA,EAAU;AAAA,EAAU;AAAA,EACpE;AAAA,EAAc;AAAA,EAAY;AAAA,EAAU;AAAA,EAAc;AAAA,EAAU;AAAA,EAAQ;AAAA,EACpE;AAAA,EAAU;AAAA,EAAa;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAY;AAAA,EAAQ;AAAA,EAChE;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAa;AAAA,EAAW;AAAA,EAAa;AAAA,EAAU;AAAA,EAClE;AAAA,EAAa;AAAA,EAAY;AAAA,EAAU;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAO;AAAA,EACpE;AAAA,EAAe;AAAA,EAAY;AAAA,EAAS;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAY;AAAA,EACxE;AAAA,EAAW;AAAA,EAAY;AAAA,EAAW;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAQ;AAAA,EAC3E;AAAA,EAAS;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAc;AAAA,EAAkB;AAAA,EAAS;AAAA,EACvE;AAAA,EAAW;AAAA,EAAmB;AAAA,EAAU;AAAA,EAAW;AAAA,EAAS;AAAA,EAAO;AAAA,EAAQ;AAAA,EAC3E;AAAA,EAAS;AAAA,EAAU;AAAA,EAAO;AAAA,EAAc;AAAA,EAAY;AAAA,EAAW;AAAA,EAC/D;AAAA,EAAW;AAAA,EAAW;AAAA,EAAY;AAAA,EAAQ;AAAA,EAAY;AAAA,EAAO;AAAA,EAAQ;AAAA,EACrE;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAO;AAChC,CAAC,GAGKC,KAAkC;AAAA;AAAA,EAEtC,IAAM;AAAA,EAAc,KAAO;AAAA,EAAc,KAAO;AAAA,EAChD,KAAO;AAAA,EACP,IAAM;AAAA,EAAc,KAAO;AAAA,EAAc,KAAO;AAAA,EAChD,KAAO;AAAA;AAAA,EAEP,KAAO;AAAA,EACP,QAAU;AAAA,EACV,OAAS;AAAA;AAAA,EAET,IAAM;AAAA,EAAU,KAAO;AAAA,EAAU,KAAO;AAAA,EAAU,KAAO;AAAA,EACzD,MAAQ;AAAA,EAAQ,OAAS;AAAA,EAAa,KAAO;AAAA,EAC7C,GAAK;AAAA,EAAK,GAAK;AAAA,EACf,KAAO;AAAA,EAAO,IAAM;AAAA,EAAO,KAAO;AAAA,EAAO,KAAO;AAAA,EAAO,IAAM;AAAA,EAAO,KAAO;AAAA,EAC3E,IAAM;AAAA,EAAU,KAAO;AAAA,EACvB,IAAM;AAAA,EACN,IAAM;AAAA,EACN,KAAO;AAAA,EAAO,OAAS;AAAA,EACvB,IAAM;AAAA,EAAQ,MAAQ;AAAA,EACtB,OAAS;AAAA,EACT,IAAM;AAAA,EAAU,KAAO;AAAA,EACvB,OAAS;AAAA,EACT,MAAQ;AAAA,EACR,KAAO;AAAA,EAAO,MAAQ;AAAA,EACtB,GAAK;AAAA,EAAK,OAAS;AAAA,EAAK,KAAO;AAAA,EAC/B,IAAM;AAAA,EAAQ,IAAM;AAAA,EACpB,IAAM;AAAA,EAAW,MAAQ;AAAA,EAAW,KAAO;AAAA,EAAW,MAAQ;AAAA,EAC9D,KAAO;AAAA,EAAc,MAAQ;AAAA,EAAc,MAAQ;AAAA,EACnD,KAAO;AAAA,EAAW,KAAO;AAAA;AAAA,EAEzB,KAAO;AAAA,EACP,MAAQ;AAAA,EAAQ,MAAQ;AAAA,EACxB,MAAQ;AAAA,EACR,MAAQ;AAAA;AAAA,EAER,MAAQ;AAAA,EAAQ,KAAO;AAAA,EAAQ,OAAS;AAAA,EACxC,KAAO;AAAA,EAAO,KAAO;AAAA,EAAO,MAAQ;AAAA,EACpC,MAAQ;AAAA,EAAQ,OAAS;AAAA,EAAQ,OAAS;AAAA,EAC1C,MAAQ;AAAA,EAAQ,KAAO;AAAA,EACvB,MAAQ;AAAA,EACR,KAAO;AAAA,EACP,MAAQ;AAAA,EAAY,QAAU;AAAA;AAAA,EAE9B,IAAM;AAAA,EAAY,UAAY;AAAA,EAAY,KAAO;AAAA,EACjD,KAAO;AAAA,EACP,KAAO;AAAA,EACP,KAAO;AAAA,EAAQ,MAAQ;AAAA,EAAQ,KAAO;AAAA,EAAQ,MAAQ;AAAA,EAAQ,KAAO;AAAA,EACrE,KAAO;AAAA,EAAS,MAAQ;AAAA,EAAS,MAAQ;AAAA,EAAS,KAAO;AAAA,EAAS,KAAO;AAAA,EACzE,KAAO;AAAA,EAAc,MAAQ;AAAA,EAAc,KAAO;AAAA;AAAA,EAElD,KAAO;AAAA,EAAS,MAAQ;AAAA,EAAS,KAAO;AAAA,EAAS,KAAO;AAAA,EAAS,MAAQ;AAAA,EACzE,KAAO;AAAA,EAAS,KAAO;AAAA,EAAS,MAAQ;AAAA,EAAS,KAAO;AAAA,EAAS,MAAQ;AAAA,EAAS,MAAQ;AAAA,EAC1F,KAAO;AAAA,EACP,KAAO;AAAA,EACP,IAAM;AAAA,EACN,QAAU;AAAA,EACV,KAAO;AAAA,EAAS,OAAS;AAAA;AAAA,EAEzB,KAAO;AAAA,EAAS,KAAO;AAAA,EAAS,KAAO;AAAA,EAAS,KAAO;AAAA,EAAS,MAAQ;AAAA,EACxE,KAAO;AAAA,EAAS,KAAO;AAAA,EAAS,KAAO;AAAA,EAAS,OAAO;AAAA,EAAS,MAAQ;AAAA,EAAS,KAAO;AAAA,EACxF,KAAO;AAAA,EAAS,KAAO;AAAA,EAAS,MAAQ;AAAA,EAAS,KAAO;AAAA,EAAS,KAAO;AAAA,EACxE,KAAO;AAAA,EAAS,KAAO;AAAA,EAAS,MAAQ;AAAA;AAAA,EAExC,KAAO;AAAA,EAAO,KAAO;AAAA,EAAO,MAAM;AAAA,EAAO,KAAO;AAAA,EAAO,IAAM;AAAA,EAAO,KAAO;AAAA,EAC3E,IAAM;AAAA,EAAO,KAAO;AAAA,EAAO,MAAQ;AAAA;AAAA,EAEnC,KAAO;AAAA,EACP,IAAM;AAAA,EAAY,QAAU;AAAA,EAAY,SAAW;AAAA,EACnD,QAAU;AAAA;AAAA,EAEV,KAAO;AAAA,EACP,MAAQ;AAAA,EACR,KAAO;AAAA,EACP,SAAW;AAAA,EAAW,KAAO;AAAA,EAC7B,OAAS;AAAA,EACT,MAAQ;AAAA,EACR,KAAO;AAAA,EACP,KAAO;AAAA,EACP,KAAO;AAAA,EACP,KAAO;AAAA,EAAO,IAAM;AAAA,EACpB,KAAO;AAAA,EACP,IAAM;AAAA,EAAU,KAAO;AAAA,EACvB,KAAO;AAAA,EAAU,KAAO;AAAA,EACxB,IAAM;AAAA,EAAW,KAAO;AAAA,EACxB,IAAM;AAAA,EAAS,KAAO;AAAA,EACtB,KAAO;AAAA,EAAW,MAAQ;AAAA,EAAW,MAAQ;AAAA,EAC7C,MAAQ;AAAA,EAAQ,KAAO;AAAA,EAAQ,IAAM;AAAA,EACrC,KAAO;AAAA,EACP,YAAc;AAChB,GAGMC,KAAwC;AAAA;AAAA,EAE5C,cAAc;AAAA,EAAO,kBAAkB;AAAA,EAAO,eAAe;AAAA,EAAO,YAAY;AAAA;AAAA,EAEhF,QAAQ;AAAA,EAAY,cAAc;AAAA,EAAY,oBAAoB;AAAA,EAClE,mBAAmB;AAAA,EAAY,aAAa;AAAA,EAAY,gBAAgB;AAAA;AAAA,EAExE,gBAAgB;AAAA,EAAU,qBAAqB;AAAA,EAC/C,aAAa;AAAA,EAAQ,WAAW;AAAA,EAAQ,eAAe;AAAA,EACvD,kBAAkB;AAAA,EAAQ,iBAAiB;AAAA,EAC3C,aAAa;AAAA,EAAO,eAAe;AAAA;AAAA,EAEnC,oBAAoB;AAAA,EAAU,SAAW;AAAA,EAAU,gBAAgB;AAAA,EACnE,kBAAkB;AAAA,EAAU,eAAe;AAAA,EAAU,YAAY;AAAA;AAAA,EAEjE,cAAc;AAAA,EAAQ,cAAc;AAAA;AAAA,EAEpC,UAAU;AAAA,EAAU,UAAU;AAAA,EAAU,WAAW;AAAA;AAAA,EAEnD,iBAAiB;AAAA,EAAO,iBAAiB;AAAA;AAAA,EAEzC,SAAW;AAAA,EAAW,gBAAgB;AAAA,EAAW,UAAY;AAAA;AAAA,EAE7D,YAAc;AAAA,EAAU,sBAAsB;AAAA,EAAU,uBAAuB;AAAA,EAC/E,iBAAiB;AAAA;AAAA,EAEjB,UAAY;AAAA,EAAY,aAAe;AAAA,EACvC,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAAU,oBAAoB;AAAA,EAAU,mBAAmB;AAAA,EAC3E,WAAW;AAAA;AAAA,EAEX,iBAAiB;AAAA,EAAY,iBAAiB;AAAA,EAC9C,eAAe;AAAA,EAAY,oBAAoB;AAAA,EAAY,kBAAkB;AAAA,EAC7E,mBAAmB;AAAA,EAAY,sBAAsB;AAAA,EACrD,aAAa;AAAA,EAAU,kBAAkB;AAAA,EAAU,gBAAgB;AAAA,EACnE,iBAAiB;AAAA,EAAU,oBAAoB;AAAA,EAAU,qBAAqB;AAAA,EAC9E,iBAAiB;AAAA,EACjB,kBAAkB;AAAA,EAAQ,kBAAkB;AAAA,EAC5C,qBAAqB;AAAA,EAAW,qBAAqB;AAAA,EACrD,oBAAoB;AAAA,EAAU,oBAAoB;AAAA,EAClD,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EAAe,sBAAsB;AAAA,EAC3D,qBAAqB;AAAA,EAAW,sBAAsB;AAAA,EACtD,mBAAmB;AAAA,EAAS,YAAY;AAAA,EACxC,kBAAkB;AAAA,EAAQ,kBAAkB;AAAA,EAC5C,oBAAoB;AAAA,EAAU,oBAAoB;AAAA,EAClD,wBAAwB;AAAA,EAAc,wBAAwB;AAAA,EAC9D,qBAAqB;AAAA,EAAW,qBAAqB;AAAA,EACrD,UAAU;AAAA,EAAO,iBAAiB;AAAA,EAClC,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,UAAU;AAAA,EAAU,iBAAiB;AAAA;AAAA,EAErC,kBAAkB;AAAA,EAAQ,kBAAkB;AAAA,EAC5C,kBAAkB;AAAA,EAAQ,mBAAmB;AAAA,EAAQ,kBAAkB;AAAA,EACvE,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EAAS,mBAAmB;AAAA,EAChD,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,mBAAmB;AAAA;AAAA,EAEnB,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,gBAAgB;AAAA;AAAA,EAEhB,SAAW;AAAA,EAAW,cAAc;AAAA,EAAW,eAAe;AAAA,EAC9D,QAAU;AAAA,EAAU,aAAa;AAAA,EAAU,cAAc;AAAA,EACzD,WAAa;AAAA,EAAa,gBAAgB;AAAA,EAC1C,UAAU;AAAA,EAAO,cAAc;AAAA,EAC/B,cAAc;AAAA,EACd,aAAa;AAAA,EACb,aAAe;AAAA,EACf,gBAAgB;AAAA,EAAa,qBAAqB;AAAA,EAClD,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,SAAS;AAAA,EACT,aAAa;AAAA,EAAQ,cAAc;AACrC;AAKO,SAASC,GAAgBC,GAAkBC,GAAiC;AACjF,QAAMC,IAAYF,EAAS,YAAA;AAG3B,MAAIF,GAAcI,CAAS,GAAG;AAC5B,UAAMC,IAAOL,GAAcI,CAAS;AACpC,QAAIN,GAAY,IAAIO,CAAI;AACtB,aAAO,uBAAuBA,CAAI;AAAA,EAEtC;AAGA,MAAID,MAAc,gBAAgBA,EAAU,WAAW,aAAa;AAClE,WAAO;AAIT,MAAIA,MAAc,UAAUA,EAAU,WAAW,OAAO;AACtD,WAAO;AAIT,QAAME,IAAeJ,EAAS,YAAY,GAAG,GACvCK,IAAMD,IAAe,IAAIJ,EAAS,UAAUI,IAAe,CAAC,EAAE,YAAA,IAAgB;AAGpF,MAAIC,MAAQ,QAAQA,MAAQ,MAAM;AAChC,UAAMC,IAAWN,EAAS,UAAU,GAAGI,CAAY,EAAE,YAAA;AACrD,QAAIE,EAAS,SAAS,IAAI;AACxB,aAAO;AAET,QAAIA,EAAS,SAAS,OAAO,KAAKA,EAAS,SAAS,OAAO;AACzD,aAAOD,MAAQ,OAAO,gCAAgC;AAAA,EAE1D;AACA,MAAIA,MAAQ,SAASA,MAAQ,OAAO;AAClC,UAAMC,IAAWN,EAAS,UAAU,GAAGI,CAAY,EAAE,YAAA;AACrD,QAAIE,EAAS,SAAS,OAAO,KAAKA,EAAS,SAAS,OAAO;AACzD,aAAOD,MAAQ,QAAQ,gCAAgC;AAAA,EAE3D;AAEA,MAAIA,KAAOR,GAAQQ,CAAG,GAAG;AACvB,UAAMF,IAAON,GAAQQ,CAAG;AACxB,QAAIT,GAAY,IAAIO,CAAI;AACtB,aAAO,uBAAuBA,CAAI;AAAA,EAEtC;AAGA,SAAIF,IACKM,GAAgBN,CAAY,IAI9B;AACT;AAEA,SAASM,GAAgBJ,GAAwB;AAC/C,UAAQA,GAAA;AAAA,IACN,KAAKR,EAAS;AAAO,aAAO;AAAA,IAC5B,KAAKA,EAAS;AAAO,aAAO;AAAA,IAC5B,KAAKA,EAAS;AAAO,aAAO;AAAA,IAC5B,KAAKA,EAAS;AAAM,aAAO;AAAA,IAC3B,KAAKA,EAAS;AAAM,aAAO;AAAA,IAC3B,KAAKA,EAAS;AAAU,aAAO;AAAA,IAC/B,KAAKA,EAAS;AAAK,aAAO;AAAA,IAC1B,KAAKA,EAAS;AAAS,aAAO;AAAA,IAC9B,KAAKA,EAAS;AAAa,aAAO;AAAA,IAClC;AAAS,aAAO;AAAA,EAAA;AAEpB;ACzSA,MAAMC,yBAAkB,IAAI;AAAA,EAC1B;AAAA,EAAS;AAAA,EAAW;AAAA,EAAW;AAAA,EAAa;AAAA,EAAW;AAAA,EAAO;AAAA,EAAU;AAAA,EACxE;AAAA,EAAW;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAc;AAAA,EAAS;AAAA,EAAW;AAAA,EAC9D;AAAA,EAAmB;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAa;AAAA,EAC3D;AAAA,EAAS;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAc;AAAA,EACxE;AAAA,EAAY;AAAA,EAAS;AAAA,EAAU;AAAA,EAAU;AAAA,EAAS;AAAA,EAAmB;AAAA,EACrE;AAAA,EAAW;AAAA,EAAS;AAAA,EAAW;AAAA,EAAc;AAAA,EAAU;AAAA,EAAc;AAAA,EACrE;AAAA,EAAY;AAAA,EAAa;AAAA,EAAW;AAAA,EAAW;AAAA,EAAY;AAAA,EAAc;AAAA,EACzE;AAAA,EAAY;AAAA,EAAO;AAAA,EAAO;AAAA,EAAU;AAAA,EAAU;AAAA,EAAW;AAAA,EAAO;AAAA,EAAQ;AAAA,EACxE;AAAA,EAAS;AAAA,EAAc;AAAA,EAAS;AAAA,EAAW;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAU;AAAA,EAC1E;AAAA,EAAY;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAe;AAAA,EAAS;AAAA,EAC1E;AAAA,EAAS;AAAA,EAAY;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAY;AAAA,EAAW;AAAA,EAAY;AAAA,EAC1E;AAAA,EAAY;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAW;AAAA,EAC/D;AAAA,EAAa;AAAA,EAAa;AAAA,EAAgB;AAAA,EAAO;AAAA,EAAS;AAAA,EAAU;AAAA,EACpE;AAAA,EAAU;AAAA,EAAS;AAAA,EAAU;AAAA,EAAW;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAU;AAAA,EAC3E;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAU;AAAA,EAAW;AAAA,EAAS;AAAA,EACjE;AAAA,EAAe;AAAA,EAAa;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAc;AAAA,EAAS;AAAA,EAAO;AAAA,EACzE;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAc;AAAA,EAAS;AAAA,EAAU;AAAA,EAAY;AAAA,EAAQ;AAAA,EACxE;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAa;AAAA,EAAO;AAAA,EAAU;AAAA,EAAO;AAAA,EAAQ;AAAA,EACzE;AAAA,EAAQ;AAAA,EAAY;AAAA,EAAY;AAAA,EAAa;AAAA,EAAY;AAAA,EAAQ;AAAA,EACjE;AAAA,EAAc;AAAA,EAAc;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAY;AAAA,EAC1E;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAc;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAY;AAAA,EAAY;AAAA,EACzE;AAAA,EAAY;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAU;AAAA,EAC3E;AAAA,EAAc;AAAA,EAAU;AAAA,EAAW;AAAA,EAAW;AAAA,EAAW;AAAA,EAAS;AAAA,EAAU;AAAA,EAC5E;AAAA,EAAW;AAAA,EAAU;AAAA,EAAS;AAAA,EAAoB;AAAA,EAAiB;AAAA,EACnE;AAAA,EAAY;AAAA,EAAY;AAAA,EAAU;AAAA,EAAS;AAAA,EAAU;AAAA,EAAS;AAAA,EAAQ;AAAA,EACtE;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAS;AAAA,EAAW;AAAA,EAAU;AAAA,EAAW;AAAA,EACrE;AAAA,EAAc;AAAA,EAAU;AAAA,EAAU;AAAA,EAAe;AAAA,EAAa;AAAA,EAAW;AAAA,EACzE;AAAA,EAAa;AAAA,EAAS;AAAA,EAAW;AAAA,EAAS;AAAA,EAAa;AAAA,EAAU;AAAA,EACjE;AAAA,EAAY;AAAA,EAAU;AAAA,EAAO;AAAA,EAAU;AAAA,EAAU;AAAA,EAAY;AAAA,EAAS;AAAA,EACtE;AAAA,EAAQ;AAAA,EAAY;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAO;AAAA,EAAS;AAAA,EAAS;AAAA,EAC3E;AAAA,EAAa;AAAA,EAAc;AAAA,EAAM;AAAA,EAAS;AAAA,EAAU;AAAA,EAAU;AAAA,EAAS;AAAA,EACvE;AAAA,EAAa;AAAA,EAAS;AAAA,EAAS;AAAA,EAAM;AAAA,EAAU;AAAA,EAAO;AAAA,EAAkB;AAAA,EACxE;AAAA,EAAc;AAAA,EAAY;AAAA,EAAW;AAAA,EAAW;AAAA,EAAa;AAAA,EAAQ;AACvE,CAAC,GAGKY,KAAkC;AAAA;AAAA,EAEtC,OAAS;AAAA,EAAQ,WAAa;AAAA,EAAQ,UAAY;AAAA,EAAQ,MAAQ;AAAA,EAAQ,OAAS;AAAA,EACnF,QAAU;AAAA,EACV,SAAW;AAAA,EAAU,eAAiB;AAAA,EAAU,gBAAkB;AAAA,EAClE,OAAS;AAAA,EAAU,SAAW;AAAA,EAC9B,SAAW;AAAA,EAAa,OAAS;AAAA,EACjC,WAAa;AAAA,EACb,QAAU;AAAA,EACV,QAAU;AAAA,EACV,MAAQ;AAAA,EAAU,KAAO;AAAA,EAAU,OAAS;AAAA,EAC5C,OAAS;AAAA,EACT,QAAU;AAAA,EAAO,OAAS;AAAA,EAAO,SAAW;AAAA,EAAO,aAAe;AAAA,EAClE,MAAQ;AAAA,EAAS,OAAS;AAAA,EAAS,MAAQ;AAAA,EAC3C,SAAW;AAAA,EACX,QAAU;AAAA,EAAY,OAAS;AAAA,EAC/B,SAAW;AAAA,EAAO,QAAU;AAAA,EAAO,MAAQ;AAAA,EAC3C,SAAW;AAAA,EAAU,QAAU;AAAA,EAAU,YAAc;AAAA,EACvD,aAAe;AAAA,EACf,SAAW;AAAA,EAAU,WAAa;AAAA,EAAS,MAAQ;AAAA,EACnD,MAAQ;AAAA,EAAS,SAAW;AAAA,EAC5B,WAAa;AAAA,EAAY,KAAO;AAAA,EAAY,QAAU;AAAA,EAAY,OAAS;AAAA,EAC3E,OAAS;AAAA,EAAQ,aAAe;AAAA,EAChC,OAAS;AAAA,EAAQ,WAAa;AAAA,EAAQ,UAAY;AAAA,EAAQ,cAAgB;AAAA,EAC1E,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,UAAY;AAAA,EAAa,MAAQ;AAAA,EAAa,KAAO;AAAA,EACrD,UAAY;AAAA,EAAU,SAAW;AAAA,EACjC,WAAa;AAAA,EAAc,MAAQ;AAAA,EAAc,OAAS;AAAA,EAC1D,aAAe;AAAA;AAAA,EAEf,QAAU;AAAA,EAAO,SAAW;AAAA,EAC5B,cAAgB;AAAA,EAAQ,OAAS;AAAA,EAAQ,QAAU;AAAA,EAAQ,KAAO;AAAA,EAAQ,QAAU;AAAA,EACpF,eAAiB;AAAA,EAAQ,KAAO;AAAA,EAAQ,UAAY;AAAA,EAAQ,WAAa;AAAA,EACzE,QAAU;AAAA,EAAU,SAAW;AAAA,EAAU,SAAW;AAAA,EACpD,MAAQ;AAAA,EAAO,SAAW;AAAA,EAAO,QAAU;AAAA,EAAO,SAAW;AAAA,EAC7D,KAAO;AAAA,EAAW,UAAY;AAAA,EAC9B,KAAO;AAAA,EAAQ,WAAa;AAAA,EAAQ,OAAS;AAAA,EAAQ,QAAU;AAAA,EAAQ,UAAU;AAAA,EAAQ,UAAU;AAAA,EACnG,OAAS;AAAA,EAAc,UAAU;AAAA,EAAc,SAAW;AAAA,EAAc,KAAO;AAAA,EAC/E,SAAW;AAAA,EAAQ,QAAU;AAAA,EAAQ,MAAQ;AAAA,EAAQ,WAAa;AAAA,EAAQ,cAAgB;AAAA,EAC1F,IAAM;AAAA,EAAY,WAAa;AAAA,EAAY,KAAO;AAAA,EAAY,SAAW;AAAA,EACzE,WAAa;AAAA,EAAc,OAAS;AAAA,EAAW,MAAQ;AAAA;AAAA,EAEvD,WAAW;AAAA,EACX,WAAW;AAAA,EACX,WAAW;AAAA,EACX,aAAa;AAAA,EACb,UAAU;AAAA,EACV,WAAW;AAAA,EACX,cAAgB;AAAA,EAChB,MAAQ;AAAA,EACR,UAAY;AAAA,EAAU,UAAY;AAAA,EAAU,KAAO;AAAA,EAAU,QAAU;AAAA,EAAU,SAAW;AAAA,EAC5F,SAAW;AAAA,EAAU,MAAQ;AAAA,EAC7B,SAAW;AAAA,EACX,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,KAAO;AAAA,EAAc,MAAQ;AAAA,EAC7B,OAAS;AAAA,EAAY,SAAW;AAAA,EAAY,OAAS;AAAA,EAAY,UAAY;AAAA,EAC7E,KAAO;AAAA,EAAO,MAAQ;AAAA,EACtB,YAAc;AAAA,EACd,UAAY;AAAA,EAAW,WAAa;AAAA,EAAW,OAAS;AAAA,EACxD,cAAgB;AAAA,EAAY,eAAiB;AAAA,EAC7C,KAAO;AAAA,EAAe,MAAQ;AAAA,EAC9B,OAAS;AAAA,EAAiB,OAAS;AAAA,EAAS,QAAU;AAAA,EACtD,UAAY;AAAA,EACZ,OAAS;AACX;AAMO,SAASC,GAAkBC,GAAwC;AACxE,QAAMC,KAAQD,KAAc,IAAI,KAAA;AAChC,MAAI,CAACC,EAAM;AAEX,QAAMC,IAAQD,EAAK,QAAQ,WAAW,EAAE,EAAE,YAAA,GACpCE,IAAeL,GAAQI,CAAK,KAAKA;AAEvC,MAAIhB,GAAY,IAAIiB,CAAY;AAC9B,WAAO,8BAA8BA,CAAY;AAIrD;;;;;;;;;;AC/GA,UAAMC,IAAQC,GAKRC,IAAWC,EAAS,MAAM;AAC9B,UAAIH,EAAM,SAASnB,EAAS;AAG1B,gBADmBmB,EAAM,OAAOL,GAAkBK,EAAM,IAAI,IAAI,WAC3C;AAIvB,UAAIA,EAAM;AACR,eAAOf,GAAgBe,EAAM,MAAMA,EAAM,IAAI;AAI/C,cAAQA,EAAM,MAAA;AAAA,QACZ,KAAKnB,EAAS;AACZ,iBAAO;AAAA,QACT,KAAKA,EAAS;AACZ,iBAAO;AAAA,QACT,KAAKA,EAAS;AACZ,iBAAO;AAAA,QACT,KAAKA,EAAS;AACZ,iBAAO;AAAA,QACT,KAAKA,EAAS;AACZ,iBAAO;AAAA,QACT,KAAKA,EAAS;AACZ,iBAAO;AAAA,QACT,KAAKA,EAAS;AACZ,iBAAO;AAAA,QACT,KAAKA,EAAS;AACZ,iBAAO;AAAA,QACT,KAAKA,EAAS;AACZ,iBAAO;AAAA,QACT;AACE,iBAAO;AAAA,MAAA;AAAA,IAEb,CAAC,GAEKuB,IAAYD,EAAS,MAAM;AAC/B,YAAME,IAAO;AACb,cAAQL,EAAM,MAAA;AAAA,QACZ,KAAKnB,EAAS;AACZ,iBAAO,GAAGwB,CAAI;AAAA,QAChB,KAAKxB,EAAS;AACZ,iBAAO,GAAGwB,CAAI;AAAA,QAChB,KAAKxB,EAAS;AACZ,iBAAO,GAAGwB,CAAI;AAAA,QAChB,KAAKxB,EAAS;AACZ,iBAAO,GAAGwB,CAAI;AAAA,QAChB,KAAKxB,EAAS;AACZ,iBAAO,GAAGwB,CAAI;AAAA,QAChB,KAAKxB,EAAS;AACZ,iBAAO,GAAGwB,CAAI;AAAA,QAChB,KAAKxB,EAAS;AAAA,QACd,KAAKA,EAAS;AACZ,iBAAO,GAAGwB,CAAI;AAAA,QAChB,KAAKxB,EAAS;AACZ,iBAAO,GAAGwB,CAAI;AAAA,QAChB,KAAKxB,EAAS;AACZ,iBAAO,GAAGwB,CAAI;AAAA,QAChB;AACE,iBAAO,GAAGA,CAAI;AAAA,MAAA;AAAA,IAEpB,CAAC;2BAtFCC,EAEM,OAAA;AAAA,MAFA,SAAOL,EAAA,SAAS;AAAA,IAAA;MACpBM,EAAyEC,EAAAC,CAAA,GAAA;AAAA,QAAlE,MAAMP,EAAA;AAAA,QAAW,OAAOD,EAAA;AAAA,QAAO,QAAQA,EAAA;AAAA,QAAO,SAAOG,EAAA,KAAS;AAAA,MAAA;;;;;;;;;;;;;;;;;;;;;;ACuGzE,aAASM,EAAcb,GAAcc,GAAsD;AACzF,UAAIA;AACF,eAAO,EAAE,UAAUd,GAAM,KAAK,GAAA;AAEhC,YAAMe,IAAUf,EAAK,YAAY,GAAG;AACpC,aAAIe,KAAW,IACN,EAAE,UAAUf,GAAM,KAAK,GAAA,IAEzB;AAAA,QACL,UAAUA,EAAK,UAAU,GAAGe,CAAO;AAAA,QACnC,KAAKf,EAAK,UAAUe,CAAO;AAAA,MAAA;AAAA,IAE/B;AAKA,UAAMC,wBAAoB,IAAA;AAC1B,aAASC,EAAiBC,GAAgB;AACxC,YAAMC,IAAM,GAAGD,EAAK,EAAE,IAAIA,EAAK,IAAI;AACnC,aAAKF,EAAc,IAAIG,CAAG,KACxBH,EAAc,IAAIG,GAAKN,EAAcK,EAAK,MAAMA,EAAK,SAASlC,EAAS,MAAM,CAAC,GAEzEgC,EAAc,IAAIG,CAAG;AAAA,IAC9B;AAWA,UAAMhB,IAAQC,GAERgB,IAAOC,GAkBPC,IAAyB,CAACC,MAAkB;AAIhD,MAFeA,EAAE,OAEL,QAAQ,iBAAiB,KACnCH,EAAK,oBAAoBG,CAAC;AAAA,IAE9B,GAKMC,IAAe,CAACN,MAA4B;;AAEhD,aAAIA,EAAK,SAASlC,EAAS,iBAAeyC,IAAAtB,EAAM,kBAAN,QAAAsB,EAAA,KAAAtB,GAAsBe,MACvD,KAGLA,EAAK,SAASlC,EAAS,SAIvBkC,EAAK,SAASlC,EAAS,QAClB,CAAC,CAACkC,EAAK,eAET;AAAA,IACT,GAkBMQ,IAAe,CAACR,GAAgBK,MAAa;AAEjD,YAAMI,IADQJ,EAAE,OACM,MAAM,KAAA;AAC5B,MAAII,KAAWA,MAAYT,EAAK,OAC9BE,EAAK,UAAUF,GAAMS,CAAO,IAE5BP,EAAK,gBAAgBF,CAAI;AAAA,IAE7B,GAKMU,IAAiB,CAACL,MAAqB;AAC1C,MAAAA,EAAE,OAA4B,KAAA;AAAA,IACjC,GAKMM,IAAkB,CAACN,MAAqB;AAC5C,YAAMO,IAAQP,EAAE,QAEVL,IAAOf,EAAM,MAAM,KAAK,OAAK4B,EAAE,OAAO5B,EAAM,SAAS;AAC3D,MAAIe,MACFY,EAAM,QAAQZ,EAAK,OAErBY,EAAM,KAAA;AAAA,IACR;2BAvOErB,EA4FM,OAAA;AAAA,MA5FD,OAAM;AAAA,MAAa,iBAAqBa,GAAsB,CAAA,SAAA,CAAA;AAAA,IAAA;cACjEb,EA0FMuB,GAAA,MAAAC,EAzFW7B,EAAA,OAAK,CAAbc,MAAI;;oBADbT,EA0FM,OAAA;AAAA,UAxFH,KAAKS,EAAK;AAAA,UACV,WAAWd,EAAA,cAAcc,EAAK;AAAA,UAC9B,aAAS,CAAAgB,MAAEC,EAAAA,MAAK,aAAcD,GAAQhB,CAAI;AAAA,UAC1C,YAAQkB,EAAA,CAAAF,MAAUC,EAAAA,MAAK,YAAaD,GAAQhB,CAAI,GAAA,CAAA,SAAA,CAAA;AAAA,UAChD,aAASmB,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAH,MAAEC,EAAAA,MAAK,aAAcD,CAAM;AAAA,UACpC,QAAIE,EAAA,CAAAF,MAAUC,EAAAA,MAAK,QAASD,GAAQhB,CAAI,GAAA,CAAA,SAAA,CAAA;AAAA,UACxC,SAAKkB,EAAA,CAAAF,MAAOC,EAAAA,MAAK,UAAWjB,GAAMgB,CAAM,GAAA,CAAA,MAAA,CAAA;AAAA,UACxC,YAAQE,EAAA,CAAAF,MAAOC,EAAAA,MAAK,QAASjB,CAAI,GAAA,CAAA,MAAA,CAAA;AAAA,UACjC,eAAWkB,EAAA,CAAAF,MAAeC,EAAAA,MAAK,eAAgBjB,GAAMgB,CAAM,GAAA,CAAA,WAAA,MAAA,CAAA;AAAA,UAC3D,OAAKI,EAAA;AAAA;YAAsClC,EAAA,YAAY,IAAIc,EAAK,EAAE,KAAKd,EAAA,cAAcc,EAAK,kCAAuDd,EAAA,eAAec,EAAK;;;UAStKqB,EAwCM,OAxCNC,IAwCM;AAAA,YArCItB,EAAK,SAASP,EAAA3B,CAAA,EAAS,iBAAeyC,IAAArB,EAAA,kBAAA,QAAAqB,EAAA,KAAArB,GAAgBc,YAD9DT,EAQE,OAAA;AAAA;cANC,KAAKL,EAAA,cAAcc,CAAI;AAAA,cACvB,KAAKA,EAAK;AAAA,cACV,OAAKoB,EAAA;AAAA;gBAA8FlC,EAAA,YAAY,IAAIc,EAAK,EAAE,KAAKd,EAAA,cAAcc,EAAK,KAAE,uCAAA;AAAA,cAAA;gCAMlIM,EAAaN,CAAI,UAAtCT,EAqBWuB,GAAA,EAAA,KAAA,KAAA;AAAA,cAnBEd,EAAK,SAASP,EAAA3B,CAAA,EAAS,SAASkC,EAAK,gBAAhDuB,EAAA,GAAAhC,EAUM,OAVNiC,IAUM;AAAA,gBATJH,EAKE,OAAA;AAAA,kBAJC,KAAKrB,EAAK;AAAA,kBACX,OAAM;AAAA,kBACL,KAAKA,EAAK;AAAA,kBACV,SAAK,CAAAgB,MAAEC,EAAAA,MAAK,kBAAmBjB,GAAMgB,CAAM;AAAA,gBAAA;gCAE9CK,EAEM,OAAA,EAFD,OAAM,+BAA2B;AAAA,kBACpCA,EAA8C,OAAA,EAAzC,OAAM,kCAAgC;AAAA,gBAAA;oBAKlCrB,EAAK,qBADlBT,EAME,OAAA;AAAA;gBAJC,KAAKS,EAAK;AAAA,gBACV,KAAKA,EAAK;AAAA,gBACX,OAAM;AAAA,gBACL,SAAK,CAAAgB,MAAEC,EAAAA,MAAK,kBAAmBjB,GAAMgB,CAAM;AAAA,cAAA;4BAGhDS,EAKEC,IAAA;AAAA;cAHC,MAAM1B,EAAK;AAAA,cACX,MAAMA,EAAK;AAAA,cACX,MAAM;AAAA,YAAA;;UAIXqB,EA2BM,OA3BNM,IA2BM;AAAA,YAzBIzC,EAAA,cAAcc,EAAK,WAD3BT,EAUE,SAAA;AAAA;cARA,MAAK;AAAA,cACL,OAAM;AAAA,cACL,OAAOS,EAAK;AAAA,cACZ,QAAI,CAAAgB,MAAER,EAAaR,GAAMgB,CAAM;AAAA,cAC/B,WAAO;AAAA,mBAAQN,GAAc,CAAA,OAAA,CAAA;AAAA,mBACbC,GAAe,CAAA,QAAA,CAAA;AAAA,cAAA;AAAA;cAChC,KAAI;AAAA,cACJ,WAAA;AAAA,YAAA,0BAEFpB,EAcO,QAAA;AAAA;cAZJ,SAAK2B,EAAA,CAAAF,MAAOC,EAAAA,MAAK,aAAcjB,GAAMgB,CAAM,GAAA,CAAA,MAAA,CAAA;AAAA,cAC3C,OAAKI,EAAA;AAAA;gBAAmDlC,EAAA,YAAY,IAAIc,EAAK,EAAE,IAAA,kCAAA;AAAA,cAAA;cAI/E,OAAOA,EAAK;AAAA,YAAA;cAEGD,EAAiBC,CAAI,EAAE,YAAvCT,EAGWuB,GAAA,EAAA,KAAA,KAAA;AAAA,gBAFTO,EAAmF,QAAnFO,IAAmFC,EAAzC9B,EAAiBC,CAAI,EAAE,QAAQ,GAAA,CAAA;AAAA,gBACzEqB,EAA6E,QAA7ES,IAA6ED,EAApC9B,EAAiBC,CAAI,EAAE,GAAG,GAAA,CAAA;AAAA,cAAA,gBAErET,EAA2CuB,GAAA,EAAA,KAAA,KAAA;AAAA,gBAAvBiB,GAAAF,EAAA7B,EAAK,IAAI,GAAA,CAAA;AAAA,cAAA;;;;;;;;;;;;;sBCxFrCuB,EAAA,GAAAhC,EAEO,QAFPyC,IAEO;AAAA,MADLxC,EAA2GC,EAAAC,CAAA,GAAA;AAAA,QAApG,MAAMR,EAAA,cAAS,QAAA,sBAAA;AAAA,QAA2D,OAAO;AAAA,QAAK,QAAQ;AAAA,MAAA;;;;;;;;;;;;;;AC4GzG,UAAMD,IAAQC,GAERgB,IAAOC,GAkBPC,IAAyB,CAACC,MAAkB;AAGhD,MADeA,EAAE,OACL,QAAQ,IAAI,KACtBH,EAAK,oBAAoBG,CAAC;AAAA,IAE9B,GAKM4B,IAAe,CAAC3D,OACqB;AAAA,MACvC,CAACR,EAAS,MAAM,GAAG;AAAA,MACnB,CAACA,EAAS,IAAI,GAAG;AAAA,MACjB,CAACA,EAAS,KAAK,GAAG;AAAA,MAClB,CAACA,EAAS,KAAK,GAAG;AAAA,MAClB,CAACA,EAAS,KAAK,GAAG;AAAA,MAClB,CAACA,EAAS,QAAQ,GAAG;AAAA,MACrB,CAACA,EAAS,IAAI,GAAG;AAAA,MACjB,CAACA,EAAS,IAAI,GAAG;AAAA,MACjB,CAACA,EAAS,GAAG,GAAG;AAAA,MAChB,CAACA,EAAS,OAAO,GAAG;AAAA,MACpB,CAACA,EAAS,WAAW,GAAG;AAAA,MACxB,CAACA,EAAS,OAAO,GAAG;AAAA,IAAA,GAERQ,CAAI,KAAKA,GAMnBkC,IAAe,CAACR,GAAgBK,MAAa;AAEjD,YAAMI,IADQJ,EAAE,OACM,MAAM,KAAA;AAC5B,MAAII,KAAWA,MAAYT,EAAK,OAC9BE,EAAK,UAAUF,GAAMS,CAAO,IAE5BP,EAAK,gBAAgBF,CAAI;AAAA,IAE7B,GAKMU,IAAiB,CAACL,MAAqB;AAC1C,MAAAA,EAAE,OAA4B,KAAA;AAAA,IACjC,GAKMM,IAAkB,CAACN,MAAqB;AAC5C,YAAMO,IAAQP,EAAE,QAEVL,IAAOf,EAAM,MAAM,KAAK,OAAK4B,EAAE,OAAO5B,EAAM,SAAS;AAC3D,MAAIe,MACFY,EAAM,QAAQZ,EAAK,OAErBY,EAAM,KAAA;AAAA,IACR;;;kBA7LErB,EA4FM,OAAA;AAAA,QA5FD,OAAM;AAAA,QAAa,iBAAqBa,GAAsB,CAAA,SAAA,CAAA;AAAA,MAAA;QACjEiB,EA0FQ,SA1FRW,IA0FQ;AAAA,UAzFNX,EA+BQ,SA/BRC,IA+BQ;AAAA,YA9BND,EA6BK,MAAA,MAAA;AAAA,cA5BHA,EAMK,MAAA;AAAA,gBALH,OAAM;AAAA,gBACL,gCAAOJ,EAAAA,MAAK,QAAA,MAAA;AAAA,cAAA;mCACd,QAEC,EAAA;AAAA,kBAAqBV,IAAArB,EAAA,eAAA,gBAAAqB,EAAY,WAAK,eAAtCkB,EAAuFS,IAAA;AAAA;kBAAnC,WAAWhD,EAAA,WAAW;AAAA,gBAAA;;cAE5EmC,EAMK,MAAA;AAAA,gBALH,OAAM;AAAA,gBACL,gCAAOJ,EAAAA,MAAK,QAAA,cAAA;AAAA,cAAA;mCACd,UAEC,EAAA;AAAA,kBAAqBkB,IAAAjD,EAAA,eAAA,gBAAAiD,EAAY,WAAK,uBAAtCV,EAA+FS,IAAA;AAAA;kBAAnC,WAAWhD,EAAA,WAAW;AAAA,gBAAA;;cAEpFmC,EAMK,MAAA;AAAA,gBALH,OAAM;AAAA,gBACL,gCAAOJ,EAAAA,MAAK,QAAA,MAAA;AAAA,cAAA;mCACd,QAEC,EAAA;AAAA,kBAAqBmB,IAAAlD,EAAA,eAAA,gBAAAkD,EAAY,WAAK,eAAtCX,EAAuFS,IAAA;AAAA;kBAAnC,WAAWhD,EAAA,WAAW;AAAA,gBAAA;;cAE5EmC,EAMK,MAAA;AAAA,gBALH,OAAM;AAAA,gBACL,gCAAOJ,EAAAA,MAAK,QAAA,MAAA;AAAA,cAAA;mCACd,QAEC,EAAA;AAAA,kBAAqBoB,IAAAnD,EAAA,eAAA,gBAAAmD,EAAY,WAAK,eAAtCZ,EAAuFS,IAAA;AAAA;kBAAnC,WAAWhD,EAAA,WAAW;AAAA,gBAAA;;;;UAIhFmC,EAwDQ,SAxDRiB,IAwDQ;AAAA,aAvDNf,EAAA,EAAA,GAAAhC,EAsDKuB,GAAA,MAAAC,EArDqB7B,EAAA,OAAK,CAArBc,GAAMuC,YADhBhD,EAsDK,MAAA;AAAA,cApDF,KAAKS,EAAK;AAAA,cACV,WAAWd,EAAA,cAAcc,EAAK;AAAA,cAC9B,aAAS,CAAAgB,MAAEC,EAAAA,MAAK,aAAcD,GAAQhB,CAAI;AAAA,cAC1C,YAAQkB,EAAA,CAAAF,MAAUC,EAAAA,MAAK,YAAaD,GAAQhB,CAAI,GAAA,CAAA,SAAA,CAAA;AAAA,cAChD,aAASmB,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAH,MAAEC,EAAAA,MAAK,aAAcD,CAAM;AAAA,cACpC,QAAIE,EAAA,CAAAF,MAAUC,EAAAA,MAAK,QAASD,GAAQhB,CAAI,GAAA,CAAA,SAAA,CAAA;AAAA,cACxC,SAAKkB,EAAA,CAAAF,MAAOC,EAAAA,MAAK,UAAWjB,GAAMgB,CAAM,GAAA,CAAA,MAAA,CAAA;AAAA,cACxC,YAAQE,EAAA,CAAAF,MAAOC,EAAAA,MAAK,QAASjB,CAAI,GAAA,CAAA,MAAA,CAAA;AAAA,cACjC,eAAWkB,EAAA,CAAAF,MAAeC,EAAAA,MAAK,eAAgBjB,GAAMgB,CAAM,GAAA,CAAA,WAAA,MAAA,CAAA;AAAA,cAC3D,OAAKI,EAAA;AAAA;gBAA6ClC,EAAA,YAAY,IAAIc,EAAK,EAAE,gCAA8Dd,EAAA,eAAec,EAAK,kCAAmEuC,IAAK,MAAA;;;cAWpOlB,EAsBK,MAtBLmB,IAsBK;AAAA,gBArBHhD,EAA2DkC,IAAA;AAAA,kBAAhD,MAAM1B,EAAK;AAAA,kBAAO,MAAMA,EAAK;AAAA,kBAAO,MAAM;AAAA,gBAAA;gBAE7Cd,EAAA,cAAcc,EAAK,WAD3BT,EASE,SAAA;AAAA;kBAPA,MAAK;AAAA,kBACL,OAAM;AAAA,kBACL,OAAOS,EAAK;AAAA,kBACZ,QAAI,CAAAgB,MAAER,EAAaR,GAAMgB,CAAM;AAAA,kBAC/B,WAAO;AAAA,uBAAQN,GAAc,CAAA,OAAA,CAAA;AAAA,uBACbC,GAAe,CAAA,QAAA,CAAA;AAAA,kBAAA;AAAA,kBAChC,WAAA;AAAA,gBAAA,0BAEFpB,EASO,QAAA;AAAA;kBAPJ,SAAK2B,EAAA,CAAAF,MAAOC,EAAAA,MAAK,aAAcjB,GAAMgB,CAAM,GAAA,CAAA,MAAA,CAAA;AAAA,kBAC3C,OAAKI,EAAA;AAAA;oBAAsDlC,EAAA,YAAY,IAAIc,EAAK,EAAE,IAAA,6BAAA;AAAA,kBAAA;mBAKhF6B,EAAA7B,EAAK,IAAI,GAAA,IAAA2B,EAAA;AAAA,cAAA;cAGhBN,EAEK,MAAA;AAAA,gBAFA,4BAA0BnC,EAAA,YAAY,IAAIc,EAAK,EAAE,IAAA,6BAAA,EAAA,CAAA;AAAA,cAAA,GACjD6B,EAAA7B,EAAK,gBAAY,IAAA,GAAA,CAAA;AAAA,cAEtBqB,EAEK,MAAA;AAAA,gBAFA,iDAA+CnC,EAAA,YAAY,IAAIc,EAAK,EAAE,IAAA,6BAAA,EAAA,CAAA;AAAA,cAAA,GACtE6B,EAAA7B,EAAK,QAAI,IAAA,GAAA,CAAA;AAAA,cAEdqB,EAEK,MAAA;AAAA,gBAFA,4BAA0BnC,EAAA,YAAY,IAAIc,EAAK,EAAE,IAAA,6BAAA,EAAA,CAAA;AAAA,cAAA,KACjDiC,EAAajC,EAAK,IAAI,CAAA,GAAA,CAAA;AAAA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;ACjBrC,UAAMf,IAAQC,GAmBRgB,IAAOC,GAkBPsC,IAAcC,EAAiB,oBAAI,KAAK,GACxCC,IAAYD,EAAmB,IAAI,GACnCE,IAAaF,EAAmB,IAAI,GACpCG,IAAaH,EAAgB,EAAE,OAAO,QAAQ,WAAW,OAAO,GAGhEI,IAAgB1D;AAAA,MAAS,MAC7BH,EAAM,MAAM,OAAO,CAAAe,MAAQyC,EAAY,MAAM,IAAIzC,EAAK,EAAE,CAAC;AAAA,IAAA,GAIrD+C,IAAe,CAAC/C,GAAgBK,MAAkB;AACtD,UAAIA,EAAE,WAAWA,EAAE,SAAS;AAE1B,cAAM2C,IAAS,IAAI,IAAIP,EAAY,KAAK;AACxC,QAAIO,EAAO,IAAIhD,EAAK,EAAE,IACpBgD,EAAO,OAAOhD,EAAK,EAAE,IAErBgD,EAAO,IAAIhD,EAAK,EAAE,GAEpByC,EAAY,QAAQO;AAAA,MACtB,WAAW3C,EAAE,YAAYoC,EAAY,MAAM,OAAO,GAAG;AAEnD,cAAMQ,IAAS,MAAM,KAAKR,EAAY,KAAK,EAAE,IAAA,GACvCS,IAAYjE,EAAM,MAAM,UAAU,CAAA4B,MAAKA,EAAE,OAAOoC,CAAM,GACtDE,IAAelE,EAAM,MAAM,UAAU,OAAK4B,EAAE,OAAOb,EAAK,EAAE,GAC1DoD,KAAQ,KAAK,IAAIF,GAAWC,CAAY,GACxCE,KAAM,KAAK,IAAIH,GAAWC,CAAY,GACtCH,yBAAa,IAAA;AACnB,iBAASnC,IAAIuC,IAAOvC,KAAKwC,IAAKxC;AAC5B,UAAAmC,GAAO,IAAI/D,EAAM,MAAM4B,CAAC,EAAG,EAAE;AAE/B,QAAA4B,EAAY,QAAQO;AAAA,MACtB;AAEE,QAAAP,EAAY,QAAQ,oBAAI,IAAI,CAACzC,EAAK,EAAE,CAAC;AAGvC,MAAAE,EAAK,oBAAoBuC,EAAY,OAAOK,EAAc,KAAK;AAAA,IACjE,GAEMQ,IAAmB,CAACjD,MAAkB;AAE1C,MAAIA,EAAE,WAAWA,EAAE,iBACjBkD,EAAA;AAAA,IAEJ,GAGMA,IAAiB,MAAM;AAC3B,MAAAd,EAAY,4BAAY,IAAA,GACxBvC,EAAK,oBAAoBuC,EAAY,OAAO,CAAA,CAAE;AAAA,IAChD,GAGMe,IAAa,CAACxD,MAAmB;AACrC,MAAAE,EAAK,QAAQF,CAAI;AAAA,IACnB,GAGMyD,IAAoB,CAACzD,GAAgBK,MAAkB;AAC3D,MAAKoC,EAAY,MAAM,IAAIzC,EAAK,EAAE,MAChCyC,EAAY,QAAQ,oBAAI,IAAI,CAACzC,EAAK,EAAE,CAAC,GACrCE,EAAK,oBAAoBuC,EAAY,OAAO,CAACzC,CAAI,CAAC,IAEpDE,EAAK,gBAAgBG,GAAGL,CAAI;AAAA,IAC9B,GAEMI,IAAyB,CAACC,MAAkB;AAEhD,YAAMqD,IAASrD,EAAE;AACjB,MAAI,CAACqD,EAAO,QAAQ,iBAAiB,KAAK,CAACA,EAAO,QAAQ,gBAAgB,MACxEH,EAAA,GACArD,EAAK,sBAAsBG,CAAC;AAAA,IAEhC,GAGMsD,IAAkC,CAACtD,MAAkB;AACzD,MAAAkD,EAAA,GACArD,EAAK,sBAAsBG,CAAC;AAAA,IAC9B,GAGMuD,IAAkB,CAAC5D,GAAgBK,MAAkB;AACzD,MAAIoC,EAAY,MAAM,IAAIzC,EAAK,EAAE,KAAKyC,EAAY,MAAM,SAAS,KAC/D,WAAW,MAAM;AACf,QAAIA,EAAY,MAAM,IAAIzC,EAAK,EAAE,MAC/B2C,EAAU,QAAQ3C,EAAK;AAAA,MAE3B,GAAG,GAAG;AAAA,IAEV,GAGMQ,IAAe,CAACR,GAAgBS,MAAoB;AACxD,MAAIA,KAAWA,MAAYT,EAAK,QAC9BE,EAAK,UAAUF,GAAMS,CAAO,GAE9BkC,EAAU,QAAQ;AAAA,IACpB,GAEMkB,IAAqB,MAAM;AAC/B,MAAAlB,EAAU,QAAQ;AAAA,IACpB,GAGMmB,IAAa,CAACC,MAAkB;AACpC,MAAIlB,EAAW,MAAM,UAAUkB,IAC7BlB,EAAW,MAAM,YAAYA,EAAW,MAAM,cAAc,QAAQ,SAAS,SAE7EA,EAAW,MAAM,QAAQkB,GACzBlB,EAAW,MAAM,YAAY,QAE/B3C,EAAK,eAAe,EAAE,GAAG2C,EAAW,OAAO;AAAA,IAC7C,GAGMmB,IAAkB,CAAC3D,GAAcL,MAAmB;;AACxD,MAAKyC,EAAY,MAAM,IAAIzC,EAAK,EAAE,MAChCyC,EAAY,QAAQ,oBAAI,IAAI,CAACzC,EAAK,EAAE,CAAC,GACrCE,EAAK,oBAAoBuC,EAAY,OAAO,CAACzC,CAAI,CAAC,KAEpDO,IAAAF,EAAE,iBAAF,QAAAE,EAAgB,QAAQ,cAAc,KAAK,UAAU,CAAC,GAAGkC,EAAY,KAAK,CAAC;AAAA,IAC7E,GAEMwB,IAAiB,CAAC5D,GAAcL,MAAmB;AACvD,MAAIA,EAAK,SAASlC,EAAS,UAAU,CAAC2E,EAAY,MAAM,IAAIzC,EAAK,EAAE,MACjE4C,EAAW,QAAQ5C,EAAK;AAAA,IAE5B,GAEMkE,IAAkB,MAAM;AAC5B,MAAAtB,EAAW,QAAQ;AAAA,IACrB,GAEMuB,IAAa,CAAC9D,GAAc+D,MAAyB;;AAGzD,UAFAxB,EAAW,QAAQ,MAEfwB,EAAW,SAAStG,EAAS,OAAQ;AAEzC,YAAMuG,KAAO9D,IAAAF,EAAE,iBAAF,gBAAAE,EAAgB,QAAQ;AACrC,UAAK8D;AAEL,YAAI;AACF,gBAAMC,IAAuB,KAAK,MAAMD,CAAI;AAC5C,cAAIC,EAAW,SAASF,EAAW,EAAE,EAAG;AAExC,UAAAlE,EAAK,QAAQoE,GAAYF,EAAW,EAAE,GACtCb,EAAA;AAAA,QACF,SAASgB,GAAO;AACd,kBAAQ,MAAM,WAAWA,CAAK;AAAA,QAChC;AAAA,IACF;AAcA,WAAAC,EAAa;AAAA,MACX,gBAAAjB;AAAA,MACA,aAbkB,CAACkB,MAAe;AAClC,QAAA9B,EAAU,QAAQ8B;AAAA,MACpB;AAAA,MAYE,WATgB,MAAM;AACtB,QAAAhC,EAAY,QAAQ,IAAI,IAAIxD,EAAM,MAAM,IAAI,CAAA4B,MAAKA,EAAE,EAAE,CAAC,GACtDX,EAAK,oBAAoBuC,EAAY,OAAOxD,EAAM,KAAK;AAAA,MACzD;AAAA,MAOE,aAAAwD;AAAA,MACA,eAAAK;AAAA,IAAA,CACD,mBAxRCvD,EA2DM,OAAA;AAAA,MA1DJ,OAAM;AAAA,MACL,SAAO+D;AAAA,MACP,iBAAqBlD,GAAsB,CAAA,SAAA,CAAA;AAAA,IAAA;MAGjClB,EAAA,WAAXqC,KAAAhC,EAGM,OAHNyC,IAGM,CAAA,GAAAb,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA;AAAA,QAFJE,EAA0C,OAAA,EAArC,OAAM,yBAAA,GAAwB,MAAA,EAAA;AAAA,QACnCA,EAAa,WAAV,UAAM,EAAA;AAAA,MAAA,QAIKnC,EAAA,MAAM,WAAM,KAA5BqC,KAAAhC,EAGM,OAHN+B,IAGM;AAAA,QAFJ9B,EAA2FC,EAAAC,CAAA,GAAA;AAAA,UAArF,MAAK;AAAA,UAAqB,OAAM;AAAA,UAAK,QAAO;AAAA,UAAK,OAAM;AAAA,QAAA;QAC7DyB,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAE,EAAY,WAAT,SAAK,EAAA;AAAA,MAAA,MAKGnC,EAAA,aAAQ,eADrBuC,EAkBEiD,IAAA;AAAA;QAhBC,OAAOxF,EAAA;AAAA,QACP,gBAAcuD,EAAA;AAAA,QACd,cAAYE,EAAA;AAAA,QACZ,gBAAcC,EAAA;AAAA,QACd,oBAAkB1D,EAAA;AAAA,QAClB,UAAQ6D;AAAA,QACR,QAAMS;AAAA,QACN,eAAcC;AAAA,QACd,oBAAoBE;AAAA,QACpB,aAAYC;AAAA,QACZ,UAAQpD;AAAA,QACR,gBAAeqD;AAAA,QACf,aAAYG;AAAA,QACZ,YAAWC;AAAA,QACX,aAAYC;AAAA,QACZ,QAAMC;AAAA,MAAA,kGAIT1C,EAmBEkD,IAAA;AAAA;QAjBC,OAAOzF,EAAA;AAAA,QACP,gBAAcuD,EAAA;AAAA,QACd,cAAYE,EAAA;AAAA,QACZ,gBAAcC,EAAA;AAAA,QACd,eAAaC,EAAA;AAAA,QACb,UAAQE;AAAA,QACR,QAAMS;AAAA,QACN,eAAcC;AAAA,QACd,oBAAoBE;AAAA,QACpB,aAAYC;AAAA,QACZ,UAAQpD;AAAA,QACR,gBAAeqD;AAAA,QACf,QAAMC;AAAA,QACN,aAAYE;AAAA,QACZ,YAAWC;AAAA,QACX,aAAYC;AAAA,QACZ,QAAMC;AAAA,MAAA;;;;;;;;;;;ACdb,UAAMjE,IAAOC,GAKPyE,IAAc,CAACzF,MACdA,IAEDA,EAAS,SAAS,GAAG,IAAUA,IAE5B,UAAUA,EAAS,YAAA,CAAa,KAJjB,cAOlB0F,IAAiB,CAAC7E,MAAsB;AAC5C,MAAAE,EAAK,YAAYF,CAAI;AAAA,IACvB;sBA1DEuB,EAAA,GAAAhC,EAuBM,OAvBNyC,IAuBM;AAAA,cAtBJzC,EAqBMuB,GAAA,MAAAC,EArBiB7B,EAAA,UAAQ,CAAnB4F,YAAZvF,EAqBM,OAAA;AAAA,QArB4B,KAAKuF,EAAQ;AAAA,QAAI,OAAM;AAAA,MAAA;QACvDzD,EAAiE,OAAjEC,IAAiEO,EAAtBiD,EAAQ,KAAK,GAAA,CAAA;AAAA,QACxDzD,EAkBK,MAlBLiB,IAkBK;AAAA,WAjBHf,EAAA,EAAA,GAAAhC,EAgBKuB,GAAA,MAAAC,EAfY+D,EAAQ,QAAhB9E,YADTT,EAgBK,MAAA;AAAA,YAdF,KAAKS,EAAK;AAAA,YACV,SAAK,CAAAgB,MAAE6D,EAAe7E,CAAI;AAAA,YAC1B,OAAKoB,EAAA;AAAA;cAAiDlC,EAAA,aAAac,EAAK,KAAE,8BAAA;AAAA,YAAA;;YAK3ER,EAKEC,EAAAC,CAAA,GAAA;AAAA,cAJC,MAAMkF,EAAY5E,EAAK,IAAI;AAAA,cAC3B,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,OAAKoB,EAAElC,EAAA,aAAac,EAAK,KAAE,mCAAA,wBAAA;AAAA,YAAA;YAE9BqB,EAA6B,QAAA,MAAAQ,EAApB7B,EAAK,KAAK,GAAA,CAAA;AAAA,UAAA;;;;;;;;;;;;ACY7B,UAAMf,IAAQC,GAKRgB,IAAOC,GAIP4E,IAAc,CAAC/E,GAAsBuC,MAAkB;AAE3D,MAAIA,IAAQtD,EAAM,MAAM,SAAS,KAC/BiB,EAAK,YAAYF,GAAMuC,CAAK;AAAA,IAEhC;sBA7CEhB,EAAA,GAAAhC,EAuBM,OAvBNyC,IAuBM;AAAA,OAtBJT,EAAA,EAAA,GAAAhC,EAqBOuB,GAAA,MAAAC,EApBmB7B,EAAA,OAAK,CAArBc,GAAMuC,YADhBhD,EAqBO,QAAA;AAAA,QAnBJ,KAAKS,EAAK;AAAA,QACX,OAAM;AAAA,MAAA;QAENqB,EAQO,QAAA;AAAA,UAPJ,SAAK,CAAAL,MAAE+D,EAAY/E,GAAMuC,CAAK;AAAA,UAC9B,OAAKnB,EAAA;AAAA;YAAgDmB,MAAUrD,EAAA,MAAM,SAAM,IAAA,kCAAA;AAAA,UAAA;WAKzE2C,EAAA7B,EAAK,IAAI,GAAA,IAAAsB,EAAA;AAAA,QAGNiB,IAAQrD,EAAA,MAAM,SAAM,UAD5BuC,EAMEhC,EAAAC,CAAA,GAAA;AAAA;UAJA,MAAK;AAAA,UACJ,OAAO;AAAA,UACP,QAAQ;AAAA,UACT,OAAM;AAAA,QAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;AC0Fd,UAAMQ,IAAOC;2BA9GXZ,EAwEM,OAAA;AAAA,MAxED,OAAK6B,EAAA,CAAC,gBAAc,EAAA,2BAAsClC,EAAA,WAAS,CAAA;AAAA,IAAA;MAEtEmC,EAiBM,OAjBNW,IAiBM;AAAA,QAhBJX,EAOS,UAAA;AAAA,UANP,OAAM;AAAA,UACL,gCAAOnB,EAAI,MAAA;AAAA,UACX,WAAWhB,EAAA;AAAA,UACZ,OAAM;AAAA,QAAA;UAENM,EAA4DC,EAAAC,CAAA,GAAA;AAAA,YAAtD,MAAK;AAAA,YAAuB,OAAO;AAAA,YAAK,QAAQ;AAAA,UAAA;;QAExD2B,EAOS,UAAA;AAAA,UANP,OAAM;AAAA,UACL,gCAAOnB,EAAI,SAAA;AAAA,UACX,WAAWhB,EAAA;AAAA,UACZ,OAAM;AAAA,QAAA;UAENM,EAA6DC,EAAAC,CAAA,GAAA;AAAA,YAAvD,MAAK;AAAA,YAAwB,OAAO;AAAA,YAAK,QAAQ;AAAA,UAAA;;;MAK3D2B,EAQM,OARNG,IAQM;AAAA,QAPJwD,EAMOC,4BANP,MAMO;AAAA,UAJG/F,EAAA,YAAY,SAAM,UAD1BuC,EAIEyD,IAAA;AAAA;YAFC,OAAOhG,EAAA;AAAA,YACP,YAAQiC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAGnB,MAASE,yBAA4BF,CAAI;AAAA,UAAA;;;MAMhDmF,EAAAA,OAAO,WAAlB5D,KAAAhC,EAEM,OAFNiD,IAEM;AAAA,QADJwC,EAAaC,EAAA,QAAA,WAAA,CAAA,GAAA,QAAA,EAAA;AAAA,MAAA;MAIf5D,EAiCM,OAjCN+D,IAiCM;AAAA,QA/BOlG,EAAA,cAAXqC,EAAA,GAAAhC,EASM,OATNoC,IASM;AAAA,UARJnC,EAAuFC,EAAAC,CAAA,GAAA;AAAA,YAAjF,MAAK;AAAA,YAAiB,OAAO;AAAA,YAAK,QAAQ;AAAA,YAAI,OAAM;AAAA,UAAA;UAC1D2B,EAME,SAAA;AAAA,YALA,MAAK;AAAA,YACJ,OAAOnC,EAAA;AAAA,YACP,gCAAOgB,EAAI,sBAAwBc,EAAO,OAA4B,KAAK;AAAA,YAC5E,aAAY;AAAA,YACZ,OAAM;AAAA,UAAA;;QAKC9B,EAAA,kBAAXqC,EAAA,GAAAhC,EAeM,OAfN8F,IAeM;AAAA,UAdJhE,EAMS,UAAA;AAAA,YALN,gCAAOnB,EAAI,mBAAA,MAAA;AAAA,YACX,iCAA+BhB,EAAA,aAAQ,SAAA,gCAAA,EAAA,CAAA;AAAA,YACxC,OAAM;AAAA,UAAA;YAENM,EAA2DC,EAAAC,CAAA,GAAA;AAAA,cAArD,MAAK;AAAA,cAAsB,OAAO;AAAA,cAAK,QAAQ;AAAA,YAAA;;UAEvD2B,EAMS,UAAA;AAAA,YALN,gCAAOnB,EAAI,mBAAA,MAAA;AAAA,YACX,iCAA+BhB,EAAA,aAAQ,SAAA,gCAAA,EAAA,CAAA;AAAA,YACxC,OAAM;AAAA,UAAA;YAENM,EAAoDC,EAAAC,CAAA,GAAA;AAAA,cAA9C,MAAK;AAAA,cAAe,OAAO;AAAA,cAAK,QAAQ;AAAA,YAAA;;;QAKlDsF,EAA4BC,EAAA,QAAA,WAAA,CAAA,GAAA,QAAA,EAAA;AAAA,MAAA;;;;;;;;;;sBCtEhC1D,EAAA,GAAAhC,EAKM,OALNyC,IAKM;AAAA,MAJJgD,EAGOC,yBAHP,MAGO;AAAA,QAFL5D,EAAgC,QAAA,MAAAQ,EAAvB3C,EAAA,SAAS,IAAG,QAAI,CAAA;AAAA,QACbA,EAAA,gBAAa,KAAzBqC,KAAAhC,EAAkE,QAAA+B,IAAnC,YAAOO,EAAG3C,EAAA,aAAa,IAAG,MAAE,CAAA;;;;;;;;;;;;;;;;;;;GCiH3DoG,IAAS,GAETC,IAAa,KAEbC,KAAmB,IAEnBC,KAAmB,GAEnBC,KAAe,GAEfC,KAAc;;;;;;;;;;AAlBpB,UAAM1G,IAAQC,GAERgB,IAAOC;AAqBb,aAASyF,EAAmBC,GAAkC;AAC5D,UAAIC,IAASJ;AACb,iBAAW1F,KAAQ6F;AACjB,QAAAC,KAAU9F,EAAK,YAAYyF,KAAmBD;AAEhD,aAAOM;AAAA,IACT;AAMA,aAASC,EACPC,GACAC,GACAC,GAC0B;AAC1B,YAAMC,IAAgB,OAAO,YACvBC,IAAiB,OAAO;AAE9B,UAAIC,IAAYL,GACZM,IAAYL;AAGhB,YAAMM,IAAaJ,IAAgBH,GAC7BQ,IAAYR;AAGlB,MAAIO,IAAahB,IAAaD,MAExBkB,KAAajB,IAAaD,IAC5Be,IAAYL,IAAST,IAGjBgB,IAAaC,IACfH,IAAYF,IAAgBZ,IAAaD,IAEzCe,IAAYf;AAMlB,YAAMmB,KAAcL,IAAiBH,GAC/BS,KAAWT;AAGjB,aAAIQ,KAAcP,IAAaZ,MAEzBoB,MAAYR,IAAaZ,IAC3BgB,IAAYL,IAASC,IAGjBO,KAAcC,KAChBJ,IAAYF,IAAiBF,IAAaZ,IAE1CgB,IAAYhB,IAMlBe,IAAY,KAAK,IAAIf,GAAQ,KAAK,IAAIe,GAAWF,IAAgBZ,IAAaD,CAAM,CAAC,GACrFgB,IAAY,KAAK,IAAIhB,GAAQ,KAAK,IAAIgB,GAAWF,IAAiBF,IAAaZ,CAAM,CAAC,GAE/E,EAAE,GAAGe,GAAW,GAAGC,EAAA;AAAA,IAC5B;AAKA,aAASK,EACPC,GACAC,GAC0B;AAC1B,YAAMV,IAAgB,OAAO,YACvBC,IAAiB,OAAO,aAGxBG,IAAaJ,IAAgBS,EAAW,OACxCJ,IAAYI,EAAW;AAE7B,UAAIE,GACAC;AAGJ,aAAIR,KAAchB,IAAaI,KAAcL,IAE3CwB,IAAWF,EAAW,QAAQjB,KACrBa,KAAajB,IAAaI,KAAcL,IAEjDwB,IAAWF,EAAW,OAAOrB,IAAaI,KAGtCY,IAAaC,IACfM,IAAWX,IAAgBZ,IAAaD,IAExCwB,IAAWxB,GAKfyB,IAAWH,EAAW,KAGlBG,IAAWF,IAAgBT,IAAiBd,MAC9CyB,IAAWX,IAAiBS,IAAgBvB,IAI1CyB,IAAWzB,MACbyB,IAAWzB,IAGN,EAAE,GAAGwB,GAAU,GAAGC,EAAA;AAAA,IAC3B;AAEA,UAAMC,IAAUtE,EAA2B,IAAI,GACzCuE,IAAgBvE,EAAmB,IAAI,GACvCwE,IAAkBxE,EAAqC,IAAI,GAC3DyE,IAAWzE,EAA8B,oBAAI,KAAK,GAGlD0E,IAAWhI,EAAS,MAAM;AAC9B,YAAMiI,IAAkBzB,EAAmB3G,EAAM,OAAO;AACxD,aAAO8G,EAAsB9G,EAAM,GAAGA,EAAM,GAAGoI,CAAe;AAAA,IAChE,CAAC,GAEKC,IAAYlI,EAAS,OAAO;AAAA,MAChC,MAAM,GAAGgI,EAAS,MAAM,CAAC;AAAA,MACzB,KAAK,GAAGA,EAAS,MAAM,CAAC;AAAA,IAAA,EACxB,GAEIG,IAAenI,EAAS,MACvB8H,EAAgB,QACd;AAAA,MACL,MAAM,GAAGA,EAAgB,MAAM,CAAC;AAAA,MAChC,KAAK,GAAGA,EAAgB,MAAM,CAAC;AAAA,IAAA,IAHE,CAAA,CAKpC,GAGKM,IAAcpI,EAAS,MACtB6H,EAAc,QACZhI,EAAM,QAAQ,KAAK,CAAAwI,MAAOA,EAAI,OAAOR,EAAc,SAASQ,EAAI,YAAYA,EAAI,SAAS,SAAS,CAAC,IADzE,IAElC,GAGKC,IAAa,CAACjD,GAAYkD,MAAgB;AAC9C,MAAIA,KAAMA,aAAc,cACtBR,EAAS,MAAM,IAAI1C,GAAIkD,CAAE,IAEzBR,EAAS,MAAM,OAAO1C,CAAE;AAAA,IAE5B,GAGMmD,IAAc,CAACC,MACZA,EAAO,YAAYA,EAAO,SAAS,SAAS;AAIrD,IAAAC,GAAMb,GAAe,CAACc,MAAU;AAC9B,UAAI,CAACA,KAAS,CAACP,EAAY,OAAO;AAChC,QAAAN,EAAgB,QAAQ;AACxB;AAAA,MACF;AAEA,MAAAc,GAAS,MAAM;;AACb,cAAMC,IAASd,EAAS,MAAM,IAAIY,CAAK;AACvC,YAAI,CAACE,KAAU,GAAC1H,IAAAiH,EAAY,UAAZ,QAAAjH,EAAmB,WAAU;AAC3C,UAAA2G,EAAgB,QAAQ;AACxB;AAAA,QACF;AAEA,cAAMgB,IAAOD,EAAO,sBAAA,GACdpB,IAAgBjB,EAAmB4B,EAAY,MAAM,QAAQ;AACnE,QAAAN,EAAgB,QAAQP,EAAyBuB,GAAMrB,CAAa;AAAA,MACtE,CAAC;AAAA,IACH,CAAC,GAGDiB,GAAM,MAAM7I,EAAM,SAAS,CAACkJ,MAAY;AACtC,MAAKA,MACHlB,EAAc,QAAQ,MACtBC,EAAgB,QAAQ;AAAA,IAE5B,CAAC;AAGD,UAAMkB,IAAqB,CAAC/H,MAAkB;AAC5C,YAAMqD,IAASrD,EAAE,QAGXgI,IAAgB,SAAS,cAAc,yBAAyB;AACtE,MAAIA,KAAiBA,EAAc,SAAS3E,CAAM,KAIlDxD,EAAK,OAAO;AAAA,IACd,GAEMoI,IAAe,CAACjI,MAAqB;AACzC,MAAIA,EAAE,QAAQ,YACZH,EAAK,OAAO;AAAA,IAEhB;AAGA,IAAA4H,GAAM,MAAM7I,EAAM,SAAS,CAACkJ,MAAY;AACtC,MAAIA,KAEF,SAAS,iBAAiB,aAAaC,CAAkB,GACzD,SAAS,iBAAiB,WAAWE,CAAY,MAEjD,SAAS,oBAAoB,aAAaF,CAAkB,GAC5D,SAAS,oBAAoB,WAAWE,CAAY;AAAA,IAExD,GAAG,EAAE,WAAW,IAAM,GAGtBC,GAAY,MAAM;AAChB,eAAS,oBAAoB,aAAaH,CAAkB,GAC5D,SAAS,oBAAoB,WAAWE,CAAY;AAAA,IACtD,CAAC;AAGD,UAAME,IAAoB,CAACX,MAA4B;AACrD,MAAIA,EAAO,YAGPA,EAAO,YAAYA,EAAO,SAAS,SAAS,MAI5CA,EAAO,UACTA,EAAO,OAAA,GAET3H,EAAK,UAAU2H,CAAM,GACrB3H,EAAK,OAAO;AAAA,IACd,GAGMuI,IAAuB,CAACZ,MAA4B;AACxD,MAAIA,EAAO,YAAYA,EAAO,SAAS,SAAS,IAC9CZ,EAAc,QAAQY,EAAO,KAE7BZ,EAAc,QAAQ;AAAA,IAE1B,GAGMyB,IAAkB,MAAM;AAAA,IAE9B,GAGMC,IAAe,MAAM;AACzB,MAAA1B,EAAc,QAAQ;AAAA,IACxB;2BAtYExF,EA6FWmH,IAAA,EA7FD,IAAG,UAAM;AAAA,MACN1J,EAAA,WAAXqC,EAAA,GAAAhC,EA2FM,OA3FNyC,IA2FM;AAAA,QAzFJX,EA+CM,OAAA;AAAA,mBA9CA;AAAA,UAAJ,KAAI2F;AAAA,UACJ,OAAM;AAAA,UACL,UAAOM,EAAA,KAAS;AAAA,QAAA;WAEjB/F,EAAA,EAAA,GAAAhC,EAyCWuB,GAAA,MAAAC,EAzCyB7B,EAAA,SAAO,CAAzB2I,GAAQtF;iBAAyBsF,EAAO,MAAMtF;AAAA,UAAA;YACnDsF,EAAO,aAAlBtG,EAAA,GAAAhC,EAA8D,OAA9D+B,EAA8D,WAC9D/B,EAsCM,OAAA;AAAA;;cApCH,KAAG,CAAGoI,MAAOD,EAAWG,EAAO,IAAIF,CAAE;AAAA,cACrC,OAAKvG,EAAA;AAAA;gBAAqDyG,EAAO,WAAQ,gCAAA;AAAA,gBAAqDA,EAAO,SAAM,8BAAA;AAAA,gBAAmDD,EAAYC,CAAM,IAAA,oCAAA;AAAA,gBAA0DZ,EAAA,UAAkBY,EAAO,KAAE,8BAAA;AAAA,cAAA;cAOrS,SAAK,CAAA7G,MAAEwH,EAAkBX,CAAM;AAAA,cAC/B,cAAU,CAAA7G,MAAEyH,EAAqBZ,CAAM;AAAA,YAAA;cAGhCA,EAAO,aADfpG,EAMEhC,EAAAC,CAAA,GAAA;AAAA;gBAJC,MAAMmI,EAAO;AAAA,gBACd,OAAM;AAAA,gBACN,QAAO;AAAA,gBACP,OAAM;AAAA,cAAA;cAERxG,EAA+D,QAA/DG,IAA+DK,EAAtBgG,EAAO,KAAK,GAAA,CAAA;AAAA,cAE7CA,EAAO,gBADfpG,EAMEhC,EAAAC,CAAA,GAAA;AAAA;gBAJA,MAAK;AAAA,gBACL,OAAM;AAAA,gBACN,QAAO;AAAA,gBACP,OAAM;AAAA,cAAA;cAEImI,EAAO,YAAQ,CAAKD,EAAYC,CAAM,KAAlDtG,KAAAhC,EAEO,QAFPiD,IAEOX,EADFgG,EAAO,QAAQ,GAAA,CAAA;cAGZD,EAAYC,CAAM,UAD1BpG,EAMEhC,EAAAC,CAAA,GAAA;AAAA;gBAJA,MAAK;AAAA,gBACL,OAAM;AAAA,gBACN,QAAO;AAAA,gBACP,OAAM;AAAA,cAAA;;;;QAQN8H,EAAA,SAAeN,EAAA,cADvB3H,EAsCM,OAAA;AAAA;UApCJ,OAAM;AAAA,UACL,UAAOgI,EAAA,KAAY;AAAA,UACnB,cAAYmB;AAAA,UACZ,cAAYC;AAAA,QAAA;WAEbpH,EAAA,EAAA,GAAAhC,EA8BWuB,WA9B6B0G,EAAA,MAAY,UAAQ,CAA1CqB,GAAOC;iBAA2CD,EAAM,MAAMC;AAAA,UAAA;YACnED,EAAM,aAAjBtH,EAAA,GAAAhC,EAA6D,OAA7D6F,EAA6D,WAC7D7F,EA2BM,OAAA;AAAA;cAzBH,OAAK6B,EAAA;AAAA;gBAAqDyH,EAAM,WAAQ,gCAAA;AAAA,gBAAqDA,EAAM,SAAM,8BAAA;AAAA,cAAA;cAKzI,SAAK,CAAA7H,MAAEwH,EAAkBK,CAAK;AAAA,YAAA;cAGvBA,EAAM,aADdpH,EAMEhC,EAAAC,CAAA,GAAA;AAAA;gBAJC,MAAMmJ,EAAM;AAAA,gBACb,OAAM;AAAA,gBACN,QAAO;AAAA,gBACP,OAAM;AAAA,cAAA;cAERxH,EAA8D,QAA9D0H,IAA8DlH,EAArBgH,EAAM,KAAK,GAAA,CAAA;AAAA,cAE5CA,EAAM,gBADdpH,EAMEhC,EAAAC,CAAA,GAAA;AAAA;gBAJA,MAAK;AAAA,gBACL,OAAM;AAAA,gBACN,QAAO;AAAA,gBACP,OAAM;AAAA,cAAA;cAEImJ,EAAM,YAAlBtH,EAAA,GAAAhC,EAEO,QAFP8F,IAEOxD,EADFgH,EAAM,QAAQ,GAAA,CAAA;;;;;;;;ACnFxB,SAASG,KAAgB;AAC9B,QAAM5B,IAAW1E,EAAI,EAAE,GAAG,GAAG,GAAG,GAAG,GAC7BuG,IAAavG,EAAI,EAAK,GAKtBwG,IAAkB,CAAC7I,MAAkB;AACzC,IAAK4I,EAAW,UAChB7B,EAAS,QAAQ;AAAA,MACf,GAAGA,EAAS,MAAM,IAAI/G,EAAE;AAAA,MACxB,GAAG+G,EAAS,MAAM,IAAI/G,EAAE;AAAA,IAAA;AAAA,EAE5B,GAKM8I,IAAgB,MAAM;AAC1B,IAAAF,EAAW,QAAQ;AAAA,EACrB,GAKMG,IAAY,CAAC/I,MAAkB;AACnC,UAAMqD,IAASrD,EAAE;AAEjB,IAAIqD,EAAO,QAAQ,iBAAiB,KAAK,CAACA,EAAO,QAAQ,QAAQ,MAC/DrD,EAAE,eAAA,GACF4I,EAAW,QAAQ;AAAA,EAEvB;AAKA,SAAAnB,GAAMmB,GAAY,CAACI,MAAa;AAC9B,IAAIA,KACF,OAAO,iBAAiB,aAAaH,CAAe,GACpD,OAAO,iBAAiB,WAAWC,CAAa,MAEhD,OAAO,oBAAoB,aAAaD,CAAe,GACvD,OAAO,oBAAoB,WAAWC,CAAa;AAAA,EAEvD,CAAC,GAKDZ,GAAY,MAAM;AAChB,WAAO,oBAAoB,aAAaW,CAAe,GACvD,OAAO,oBAAoB,WAAWC,CAAa;AAAA,EACrD,CAAC,GAEM;AAAA,IACL,UAAA/B;AAAA,IACA,YAAA6B;AAAA,IACA,WAAAG;AAAA,EAAA;AAEJ;AC1DO,SAASE,GACdC,GACAC,GACAC,GACAC,GACAC,GACAC,GACA;AACA,QAAMC,IAAQnH,EAAI6G,CAAY,GACxBzD,IAASpD,EAAI8G,CAAa,GAC1BM,IAAapH,EAAI,EAAK,GACtBqH,IAAkBrH,EAA4B,IAAI,GAClDsH,IAAStH,EAAI,CAAC,GACduH,IAASvH,EAAI,CAAC,GACdwH,IAAaxH,EAAI,CAAC,GAClByH,IAAczH,EAAI,CAAC,GAKnBwG,IAAkB,CAAC7I,MAAkB;AACzC,QAAI,CAACyJ,EAAW,SAAS,CAACC,EAAgB,MAAO;AAEjD,UAAMK,IAAS/J,EAAE,UAAU2J,EAAO,OAC5BK,IAAShK,EAAE,UAAU4J,EAAO;AAElC,QAAIK,IAAWJ,EAAW,OACtBK,IAAYJ,EAAY;AAE5B,UAAMK,IAAYT,EAAgB;AAGlC,IAAIS,EAAU,SAAS,GAAG,IACxBF,IAAW,KAAK,IAAI,KAAK,IAAIJ,EAAW,QAAQE,GAAQX,CAAQ,GAAGE,CAAQ,IAClEa,EAAU,SAAS,GAAG,MAC/BF,IAAW,KAAK,IAAI,KAAK,IAAIJ,EAAW,QAAQE,GAAQX,CAAQ,GAAGE,CAAQ,IAIzEa,EAAU,SAAS,GAAG,IACxBD,IAAY,KAAK,IAAI,KAAK,IAAIJ,EAAY,QAAQE,GAAQX,CAAS,GAAGE,CAAS,IACtEY,EAAU,SAAS,GAAG,MAC/BD,IAAY,KAAK,IAAI,KAAK,IAAIJ,EAAY,QAAQE,GAAQX,CAAS,GAAGE,CAAS,IAGjFC,EAAM,QAAQS,GACdxE,EAAO,QAAQyE;AAAA,EACjB,GAKMpB,IAAgB,MAAM;AAC1B,IAAAW,EAAW,QAAQ,IACnBC,EAAgB,QAAQ;AAAA,EAC1B,GAKMU,IAAc,CAClBpK,GACAmK,GACAE,GACAC,MACG;AACH,IAAAtK,EAAE,eAAA,GACFA,EAAE,gBAAA,GACFyJ,EAAW,QAAQ,IACnBC,EAAgB,QAAQS,GACxBR,EAAO,QAAQ3J,EAAE,SACjB4J,EAAO,QAAQ5J,EAAE,SACjB6J,EAAW,QAAQQ,GACnBP,EAAY,QAAQQ;AAAA,EACtB,GAKMC,IAAwB,CAACJ,OACoB;AAAA,IAC/C,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EAAA,GAESA,CAAS;AAM1B,SAAA1C,GAAMgC,GAAY,CAACe,MAAa;AAC9B,IAAIA,KACF,OAAO,iBAAiB,aAAa3B,CAAe,GACpD,OAAO,iBAAiB,WAAWC,CAAa,GAChD,SAAS,KAAK,MAAM,SAASyB,EAAsBb,EAAgB,SAAS,IAAI,GAChF,SAAS,KAAK,MAAM,aAAa,WAEjC,OAAO,oBAAoB,aAAab,CAAe,GACvD,OAAO,oBAAoB,WAAWC,CAAa,GACnD,SAAS,KAAK,MAAM,SAAS,IAC7B,SAAS,KAAK,MAAM,aAAa;AAAA,EAErC,CAAC,GAKDZ,GAAY,MAAM;AAChB,WAAO,oBAAoB,aAAaW,CAAe,GACvD,OAAO,oBAAoB,WAAWC,CAAa,GACnD,SAAS,KAAK,MAAM,SAAS,IAC7B,SAAS,KAAK,MAAM,aAAa;AAAA,EACnC,CAAC,GAEM;AAAA,IACL,OAAAU;AAAA,IACA,QAAA/D;AAAA,IACA,YAAAgE;AAAA,IACA,aAAAW;AAAA,EAAA;AAEJ;;;;;;;;;;;;;;;;;;;;;ACVA,UAAMxL,IAAQC,GAgBRgB,IAAOC,GAMP2K,IAAqBpI,EAAwB,IAAI,GACjDqI,IAAa9L,EAAM,YAAY+J,GAAA,IAAkB,MAKjDgC,IAAa5L,EAAS,MACnBH,EAAM,cACNA,EAAM,UAAU,UAChBA,EAAM,UAAU,iBAChBA,EAAM,WAAW,UACjBA,EAAM,WAAW,aACzB,GAKKgM,IAAiB,MAAM;AAE3B,UAAID,EAAW;AACb,eAAO,EAAE,cAAc,GAAG,eAAe,EAAA;AAG3C,YAAME,IAAe,KACfC,IAAgB;AAEtB,UAAI5B,IAAe2B,GACf1B,IAAgB2B;AAEpB,aAAIlM,EAAM,UAAU,UAAUA,EAAM,UAAU,kBAC5CsK,IAAe,OAAOtK,EAAM,SAAU,WAAWA,EAAM,QAAQ,SAASA,EAAM,KAAK,IAEjFA,EAAM,WAAW,UAAUA,EAAM,WAAW,kBAC9CuK,IAAgB,OAAOvK,EAAM,UAAW,WAAWA,EAAM,SAAS,SAASA,EAAM,MAAM,IAGlF,EAAE,cAAAsK,GAAc,eAAAC,EAAAA;AAAAA,IACzB,GAKM4B,IAAY,CAACC,GAAuBC,MACpC,OAAOD,KAAS,WAAiBA,IACjCA,EAAK,SAAS,IAAI,IAAU,SAASA,CAAI,IACzCA,EAAK,SAAS,IAAI,IAAW,SAASA,CAAI,IAAI,MAAO,OAAO,aAC5DA,EAAK,SAAS,IAAI,IAAW,SAASA,CAAI,IAAI,MAAO,OAAO,cACzDC,GAGH,EAAE,cAAA/B,GAAc,eAAAC,EAAA,IAAkByB,EAAA,GAClCM,IAAOH,EAAUnM,EAAM,UAAU,GAAG,GACpCuM,IAAOJ,EAAUnM,EAAM,WAAW,GAAG,GACrCwM,IAAOL,EAAUnM,EAAM,UAAU,OAAO,aAAa,GAAG,GACxDyM,IAAON,EAAUnM,EAAM,WAAW,OAAO,cAAc,GAAG,GAE1D0M,IAAe1M,EAAM,YACvBqK,GAAgBC,GAAcC,GAAe+B,GAAMC,GAAMC,GAAMC,CAAI,IACnE,MAEEE,IAAcxM,EAAS,MAAM;AACjC,YAAMyM,IAAoC;AAAA,QACxC,MAAM;AAAA,QACN,KAAK;AAAA,MAAA;AAIP,UAAIC,IAAa,QACbC,IAAa;AAEjB,aAAI9M,EAAM,aAAa8L,MACrBe,IAAa,eAAef,EAAW,SAAS,MAAM,CAAC,OACvDgB,IAAa,eAAehB,EAAW,SAAS,MAAM,CAAC,QAGzDc,EAAU,YAAY,aAAaC,CAAU,KAAKC,CAAU,KAC5DF,EAAU,kBAAkB,iBAGxBb,EAAW,QAET/L,EAAM,aAAa0M,KAAgBA,EAAa,MAAM,QAAQ,MAChEE,EAAU,QAAQ,GAAGF,EAAa,MAAM,KAAK,MAC7CE,EAAU,SAAS,GAAGF,EAAa,OAAO,KAAK,QAK7C1M,EAAM,aAAa0M,KACrBE,EAAU,QAAQ,GAAGF,EAAa,MAAM,KAAK,MAC7CE,EAAU,SAAS,GAAGF,EAAa,OAAO,KAAK,SAE3C1M,EAAM,UAAU,UAAUA,EAAM,UAAU,kBAC5C4M,EAAU,QAAQ,OAAO5M,EAAM,SAAU,WAAW,GAAGA,EAAM,KAAK,OAAOA,EAAM,QAE7EA,EAAM,WAAW,UAAUA,EAAM,WAAW,kBAC9C4M,EAAU,SAAS,OAAO5M,EAAM,UAAW,WAAW,GAAGA,EAAM,MAAM,OAAOA,EAAM,UAKpFA,EAAM,aACR4M,EAAU,WAAW,OAAO5M,EAAM,YAAa,WAAW,GAAGA,EAAM,QAAQ,OAAOA,EAAM,WAEtFA,EAAM,cACR4M,EAAU,YAAY,OAAO5M,EAAM,aAAc,WAAW,GAAGA,EAAM,SAAS,OAAOA,EAAM,YAEzFA,EAAM,aACR4M,EAAU,WAAW,OAAO5M,EAAM,YAAa,WAAW,GAAGA,EAAM,QAAQ,OAAOA,EAAM,WAEtFA,EAAM,cACR4M,EAAU,YAAY,OAAO5M,EAAM,aAAc,WAAW,GAAGA,EAAM,SAAS,OAAOA,EAAM,YAGtF4M;AAAA,IACT,CAAC,GAEKG,IAAsB,CAAC3L,MAAkB;AAC7C,MAAIpB,EAAM,mBAAmBoB,EAAE,WAAWA,EAAE,iBAC1CH,EAAK,OAAO;AAAA,IAEhB,GAEM8D,IAAkB,CAAC3D,MAAkB;AACzC,MAAIpB,EAAM,aAAa8L,KACrBA,EAAW,UAAU1K,CAAC;AAAA,IAE1B,GAEM4L,IAAc,MAAM;AACxB,MAAA/L,EAAK,OAAO;AAAA,IACd,GAEMgM,IAAiB,MAAM;AAC3B,MAAAhM,EAAK,UAAU;AAAA,IACjB,GAEMiM,IAAiB,MAAM;AAC3B,MAAAjM,EAAK,UAAU;AAAA,IACjB,GAEMkM,IAAoB,CAAC/L,GAAemK,MAAiE;AACzG,UAAI,CAACvL,EAAM,aAAa,CAAC0M,KAAgB,CAACb,EAAmB,MAAO;AAEpE,YAAM5C,IAAO4C,EAAmB,MAAM,sBAAA,GAChCJ,IAAexC,EAAK,OACpByC,IAAgBzC,EAAK;AAE3B,MAAAyD,EAAa,YAAYtL,GAAGmK,GAAWE,GAAcC,CAAa;AAAA,IACpE;AAKA,WAAA0B,GAAU,MAAM;AACd,YAAMC,IAAY,CAACjM,MAAqB;AACtC,QAAIA,EAAE,QAAQ,aACZA,EAAE,eAAA,GACFH,EAAK,OAAO;AAAA,MAEhB;AACA,aAAO,iBAAiB,WAAWoM,CAAS,GAE5C/D,GAAY,MAAM;AAChB,eAAO,oBAAoB,WAAW+D,CAAS;AAAA,MACjD,CAAC;AAAA,IACH,CAAC,mBAtTC7K,EA6FWmH,IAAA,EA7FD,IAAG,UAAM;AAAA,MACjBvH,EA2FM,OAAA;AAAA,QA1FJ,OAAM;AAAA,QACL,SAAO2K;AAAA,MAAA;QAER3K,EAsFM,OAAA;AAAA,mBArFA;AAAA,UAAJ,KAAIyJ;AAAA,UACJ,OAAM;AAAA,UACL,UAAOc,EAAA,KAAW;AAAA,UAClB,2BAAD,MAAA;AAAA,UAAA,GAAW,CAAA,MAAA,CAAA;AAAA,QAAA;UAIH1M,EAAA,qBADRK,EAqCM,OAAA;AAAA;YAnCJ,OAAM;AAAA,YACL,aAAWyE;AAAA,UAAA;YAEZ3C,EAqBM,OArBNW,IAqBM;AAAA,cApBJX,EAKS,UAAA;AAAA,gBAJN,WAAY4K,GAAW,CAAA,MAAA,CAAA;AAAA,gBACxB,OAAM;AAAA,cAAA;gBAENzM,EAAyEC,EAAAC,CAAA,GAAA;AAAA,kBAAnE,MAAK;AAAA,kBAAW,OAAM;AAAA,kBAAI,QAAO;AAAA,kBAAI,OAAM;AAAA,gBAAA;;cAG3CR,EAAA,qBADRK,EAMS,UAAA;AAAA;gBAJN,WAAY2M,GAAc,CAAA,MAAA,CAAA;AAAA,gBAC3B,OAAM;AAAA,cAAA;gBAEN1M,EAA6EC,EAAAC,CAAA,GAAA;AAAA,kBAAvE,MAAK;AAAA,kBAAe,OAAM;AAAA,kBAAI,QAAO;AAAA,kBAAI,OAAM;AAAA,gBAAA;;cAG/CR,EAAA,qBADRK,EAMS,UAAA;AAAA;gBAJN,WAAY4M,GAAc,CAAA,MAAA,CAAA;AAAA,gBAC3B,OAAM;AAAA,cAAA;gBAEN3M,EAAkFC,EAAAC,CAAA,GAAA;AAAA,kBAA5E,MAAK;AAAA,kBAAoB,OAAM;AAAA,kBAAI,QAAO;AAAA,kBAAI,OAAM;AAAA,gBAAA;;;YAI9D2B,EAIM,OAJNC,IAIM;AAAA,cAHJ0D,EAEOC,uBAFP,MAEO;AAAA,gBADL5D,EAAkD,QAAlDiB,IAAkDT,EAAf3C,EAAA,KAAK,GAAA,CAAA;AAAA,cAAA;;YAI5CmC,EAEM,OAFNG,IAEM;AAAA,cADJwD,EAA4BC,EAAA,QAAA,WAAA,CAAA,GAAA,QAAA,EAAA;AAAA,YAAA;;UAKhC5D,EAEM,OAFNmB,IAEM;AAAA,YADJwC,EAAaC,EAAA,QAAA,WAAA,CAAA,GAAA,QAAA,EAAA;AAAA,UAAA;UAIC/F,EAAA,kBAAhBK,EAiCWuB,GAAA,EAAA,KAAA,KAAA;AAAA,YAhCTO,EAGO,OAAA;AAAA,cAFL,OAAM;AAAA,cACL,aAASF,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAGd,MAAM+L,EAAkB/L,GAAC,GAAA;AAAA,YAAA;YAExCgB,EAGO,OAAA;AAAA,cAFL,OAAM;AAAA,cACL,aAASF,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAGd,MAAM+L,EAAkB/L,GAAC,GAAA;AAAA,YAAA;YAExCgB,EAGO,OAAA;AAAA,cAFL,OAAM;AAAA,cACL,aAASF,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAGd,MAAM+L,EAAkB/L,GAAC,GAAA;AAAA,YAAA;YAExCgB,EAGO,OAAA;AAAA,cAFL,OAAM;AAAA,cACL,aAASF,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAGd,MAAM+L,EAAkB/L,GAAC,GAAA;AAAA,YAAA;YAExCgB,EAGO,OAAA;AAAA,cAFL,OAAM;AAAA,cACL,aAASF,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAGd,MAAM+L,EAAkB/L,GAAC,IAAA;AAAA,YAAA;YAExCgB,EAGO,OAAA;AAAA,cAFL,OAAM;AAAA,cACL,aAASF,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAGd,MAAM+L,EAAkB/L,GAAC,IAAA;AAAA,YAAA;YAExCgB,EAGO,OAAA;AAAA,cAFL,OAAM;AAAA,cACL,aAASF,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAGd,MAAM+L,EAAkB/L,GAAC,IAAA;AAAA,YAAA;YAExCgB,EAGO,OAAA;AAAA,cAFL,OAAM;AAAA,cACL,aAASF,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAGd,MAAM+L,EAAkB/L,GAAC,IAAA;AAAA,YAAA;;;;;;;;;;;;;;;;;;ACuClD,UAAMpB,IAAQC,GAERgB,IAAOC,GAMPoM,IAA0E;AAAA,MAC9E,EAAE,OAAO,OAAO,OAAO,OAAO,KAAK,OAAA;AAAA,MACnC,EAAE,OAAO,OAAO,OAAO,iBAAiB,KAAK,UAAA;AAAA,MAC7C,EAAE,OAAO,UAAU,OAAO,mBAAmB,KAAK,WAAA;AAAA,MAClD,EAAE,OAAO,OAAO,OAAO,aAAa,KAAK,OAAA;AAAA,IAAO,GAI5CC,IAAgB;AAAA,MACpB,EAAE,OAAO,QAAQ,OAAO,MAAM,MAAM,aAAA;AAAA,MACpC,EAAE,OAAO,UAAU,OAAO,MAAM,MAAM,UAAA;AAAA,MACtC,EAAE,OAAO,QAAQ,OAAO,MAAM,MAAM,YAAA;AAAA,IAAY,GAG5CC,IAAS/J,EAAoB,KAAK,GAClCgK,IAAQhK,EAAmB,QAAQ,GACnCiK,IAAajK,EAAI,EAAE,GACnBkK,IAAelK,EAAI,EAAK,GACxBmK,IAAWnK,EAAI,EAAE,GACjBoK,IAAepK,EAAI,EAAK,GAGxBqK,IAAoB3N,EAAS,MAC7BH,EAAM,UAAU,WAAW,IAAU,YACrCA,EAAM,UAAU,WAAW,KAChBA,EAAM,UAAU,CAAC,EAAE,MAAM,GAAG,EAAE,IAAA,KAAS,WACxC,QAAQ,YAAY,EAAE,IAE7B,MACR,GAGK+N,IAAkB5N,EAAS,MAC3BH,EAAM,UAAU,WAAW,IACtBA,EAAM,UAAU,CAAC,EAAE,MAAM,GAAG,EAAE,IAAA,IAEhC,GAAGA,EAAM,UAAU,MAAM,MACjC,GAGKgO,IAAa7N,EAAS,MAAM;;AAChC,eAAOmB,IAAAgM,EAAe,KAAK,CAAAW,MAAKA,EAAE,UAAUT,EAAO,KAAK,MAAjD,gBAAAlM,EAAoD,QAAO;AAAA,IACpE,CAAC,GAGK4M,IAAiB/N,EAAS,MACvB,GAAGH,EAAM,SAAS,IAAI0N,EAAW,KAAK,GAAGM,EAAW,KAAK,EACjE,GAGKG,IAAmBhO,EAAS,MAEzB,EACR;AAGD,IAAA0I,GAAM,MAAM7I,EAAM,SAAS,CAACkJ,MAAY;AACtC,MAAIA,MACFwE,EAAW,QAAQI,EAAkB,OACrCN,EAAO,QAAQ,OACfC,EAAM,QAAQ,UACdE,EAAa,QAAQ,IACrBC,EAAS,QAAQ;AAAA,IAErB,CAAC;AAED,UAAMQ,IAAgB,MAAM;AAC1B,MAAAnN,EAAK,WAAW;AAAA,QACd,QAAQuM,EAAO;AAAA,QACf,OAAOC,EAAM;AAAA,QACb,YAAYC,EAAW,QAAQM,EAAW;AAAA,QAC1C,cAAcL,EAAa;AAAA,MAAA,CAC5B;AAAA,IACH;2BAhNEnL,EA+GWmH,IAAA,EA/GD,IAAG,UAAM;AAAA,MACN1J,EAAA,gBAAXK,EA6GM,OAAA;AAAA;QA7Gc,OAAM;AAAA,QAA2B,gCAAOW,EAAI,QAAA;AAAA,MAAA;QAC9DmB,EA2GM,OAAA;AAAA,UA3GD,OAAM;AAAA,UAAmB,2BAAD,MAAA;AAAA,UAAA,GAAW,CAAA,MAAA,CAAA;AAAA,QAAA;UAEtCA,EAQM,OARNW,IAQM;AAAA,YAPJX,EAGM,OAHNC,IAGM;AAAA,cAFJ9B,EAAqDC,EAAAC,CAAA,GAAA;AAAA,gBAA/C,MAAK;AAAA,gBAAiB,OAAM;AAAA,gBAAK,QAAO;AAAA,cAAA;cAC9CyB,EAAA,EAAA,MAAAA,EAAA,EAAA,IAAAE,EAAiB,cAAX,QAAI,EAAA;AAAA,YAAA;YAEZA,EAES,UAAA;AAAA,cAFD,OAAM;AAAA,cAAyB,gCAAOnB,EAAI,QAAA;AAAA,YAAA;cAChDV,EAA+CC,EAAAC,CAAA,GAAA;AAAA,gBAAzC,MAAK;AAAA,gBAAW,OAAM;AAAA,gBAAK,QAAO;AAAA,cAAA;;;UAK5C2B,EA+EM,OA/ENiB,IA+EM;AAAA,YA7EJjB,EAGM,OAHNG,IAGM;AAAA,cAFJhC,EAA0DC,EAAAC,CAAA,GAAA;AAAA,gBAApD,MAAK;AAAA,gBAAsB,OAAM;AAAA,gBAAK,QAAO;AAAA,cAAA;cACnD2B,EAAkC,gBAAzB2L,EAAA,KAAe,GAAA,CAAA;AAAA,YAAA;YAI1B3L,EAUM,OAVNmB,IAUM;AAAA,cATJrB,EAAA,EAAA,MAAAA,EAAA,EAAA,IAAAE,EAAkB,eAAX,OAAG,EAAA;AAAA,cACVA,EAOM,OAPN+D,IAOM;AAAA,mBANJ/D,EAIE,SAAA;AAAA,kBAHA,MAAK;AAAA,gEACIsL,EAAU,QAAA3L;AAAA,kBACnB,aAAY;AAAA,gBAAA;uBADH2L,EAAA,KAAU;AAAA,gBAAA;gBAGrBtL,EAAyD,QAAzDM,IAAyDE,EAApBoL,EAAA,KAAU,GAAA,CAAA;AAAA,cAAA;;YAKnD5L,EAOM,OAPN0H,IAOM;AAAA,cANJ5H,EAAA,EAAA,MAAAA,EAAA,EAAA,IAAAE,EAAmB,eAAZ,QAAI,EAAA;AAAA,iBACXA,EAIS,UAAA;AAAA,8DAJQoL,EAAM,QAAAzL;AAAA,cAAA;sBACrBzB,EAESuB,GAAA,MAAAC,EAFawL,GAAc,CAArB9E,MAAfpG,EAES,UAAA;AAAA,kBAF8B,KAAKoG,EAAI;AAAA,kBAAQ,OAAOA,EAAI;AAAA,gBAAA,GAC9D5F,EAAA4F,EAAI,KAAK,GAAA,GAAApC,EAAA;;qBAFCoH,EAAA,KAAM;AAAA,cAAA;;YAQzBpL,EAcM,OAdNO,IAcM;AAAA,cAbJT,EAAA,EAAA,MAAAA,EAAA,EAAA,IAAAE,EAAmB,eAAZ,QAAI,EAAA;AAAA,cACXA,EAWM,OAXNS,IAWM;AAAA,sBAVJvC,EASQuB,GAAA,MAAAC,EATayL,GAAa,CAApB/E,MAAdpG,EASQ,SAAA;AAAA,kBAT6B,KAAKoG,EAAI;AAAA,kBAAO,OAAM;AAAA,gBAAA;qBACzDpG,EAKE,SAAA;AAAA,oBAJA,MAAK;AAAA,oBACL,MAAK;AAAA,oBACJ,OAAOoG,EAAI;AAAA,kEACHiF,EAAK,QAAA1L;AAAA,kBAAA;yBAAL0L,EAAA,KAAK;AAAA,kBAAA;kBAEhBrL,EAAgE,QAAhEiM,IAAgEzL,EAAnB4F,EAAI,KAAK,GAAA,CAAA;AAAA,kBACtDpG,EAA8D,QAA9DkM,IAA8D1L,EAAlB4F,EAAI,IAAI,GAAA,CAAA;AAAA,gBAAA;;;YAM/C2F,EAAA,SAAX7L,EAAA,GAAAhC,EAgBM,OAhBNiO,IAgBM;AAAA,cAfJrM,EAAA,EAAA,MAAAA,EAAA,EAAA,IAAAE,EAAuB,eAAhB,YAAQ,EAAA;AAAA,cACfA,EAaM,OAbNoM,IAaM;AAAA,mBAZJpM,EAIE,SAAA;AAAA,kBAHC,MAAMyL,EAAA,QAAY,SAAA;AAAA,gEACVD,EAAQ,QAAA7L;AAAA,kBACjB,aAAY;AAAA,gBAAA;uBADH6L,EAAA,KAAQ;AAAA,gBAAA;gBAGnBxL,EAMS,UAAA;AAAA,kBALP,MAAK;AAAA,kBACL,OAAM;AAAA,kBACL,SAAKF,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAH,MAAE8L,EAAA,QAAY,CAAIA,EAAA;AAAA,gBAAA,KAErBA,EAAA,QAAY,OAAA,IAAA,GAAA,CAAA;AAAA,cAAA;;YAMrBzL,EAKM,OALNqM,IAKM;AAAA,cAJJrM,EAGQ,SAAA,MAAA;AAAA,mBAFNA,EAAgD,SAAA;AAAA,kBAAzC,MAAK;AAAA,gEAAoBuL,EAAY,QAAA5L;AAAA,gBAAA;uBAAZ4L,EAAA,KAAY;AAAA,gBAAA;gBAC5CzL,EAAA,EAAA,MAAAA,EAAA,EAAA,IAAAE,EAAqB,cAAf,YAAQ,EAAA;AAAA,cAAA;;YAKlBA,EAGM,OAHNsM,IAGM;AAAA,cAFJxM,EAAA,EAAA,MAAAA,EAAA,EAAA,IAAAE,EAAwD,QAAA,EAAlD,OAAM,gCAAA,GAAgC,SAAK,EAAA;AAAA,cACjDA,EAAsE,QAAtEuM,IAAsE/L,EAAxBsL,EAAA,KAAc,GAAA,CAAA;AAAA,YAAA;;UAKhE9L,EAWM,OAXNwM,IAWM;AAAA,YAVJxM,EAES,UAAA;AAAA,cAFD,OAAM;AAAA,cAAkD,gCAAOnB,EAAI,QAAA;AAAA,YAAA,GAAY,MAEvF;AAAA,YACAmB,EAMS,UAAA;AAAA,cALP,OAAM;AAAA,cACL,SAAOgM;AAAA,cACP,UAAQ,CAAGV,EAAA,MAAW,KAAA;AAAA,YAAI,GAC5B,QAED,GAAAmB,EAAA;AAAA,UAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACDV,UAAM7O,IAAQC,GAERgB,IAAOC,GAMP4N,IAAQ3O,EAAS,MAAMH,EAAM,SAAS,SAAS,aAAa,SAAS,MAAM,GAC3E+O,IAAc5O,EAAS,MAAMH,EAAM,SAAS,WAAW,aAAaA,EAAM,SAAS,WAAW,OAAO,GAErGgP,IAAiB7O,EAAS,MAAM;AACpC,cAAQH,EAAM,SAAS,QAAA;AAAA,QACrB,KAAK;AAAc,iBAAO;AAAA,QAC1B,KAAK;AAAW,iBAAO;AAAA,QACvB,KAAK;AAAS,iBAAO;AAAA,QACrB;AAAS,iBAAO;AAAA,MAAA;AAAA,IAEpB,CAAC,GAEKiP,IAAkB9O,EAAS,MAAM;AACrC,cAAQH,EAAM,SAAS,QAAA;AAAA,QACrB,KAAK;AAAc,iBAAO;AAAA,QAC1B,KAAK;AAAW,iBAAO;AAAA,QACvB,KAAK;AAAS,iBAAO;AAAA,QACrB;AAAS,iBAAO;AAAA,MAAA;AAAA,IAEpB,CAAC,GAEKkP,IAAa/O,EAAS,MAAM;AAChC,cAAQH,EAAM,SAAS,QAAA;AAAA,QACrB,KAAK;AAAW,iBAAO;AAAA,QACvB,KAAK;AAAc,iBAAOA,EAAM,SAAS,SAAS,aAAa,YAAY;AAAA,QAC3E,KAAK;AAAW,iBAAOA,EAAM,SAAS,SAAS,aAAa,SAAS;AAAA,QACrE,KAAK;AAAS,iBAAO;AAAA,QACrB;AAAS,iBAAO;AAAA,MAAA;AAAA,IAEpB,CAAC,GAEKgN,IAAc,MAAM;AACxB,MAAI+B,EAAY,QACd9N,EAAK,OAAO,IAEZA,EAAK,QAAQ;AAAA,IAEjB;2BAvJEuB,EA+EWmH,IAAA,EA/ED,IAAG,UAAM;AAAA,MACN1J,EAAA,WAAXqC,EAAA,GAAAhC,EA6EM,OA7ENyC,IA6EM;AAAA,QA5EJX,EA2EM,OA3ENC,IA2EM;AAAA,UAzEJD,EAQM,OARNiB,IAQM;AAAA,YAPJjB,EAGM,OAHNG,IAGM;AAAA,cAFJhC,EAA+EC,EAAAC,CAAA,GAAA;AAAA,gBAAxE,MAAMuO,EAAA;AAAA,gBAAgB,OAAM;AAAA,gBAAK,QAAO;AAAA,gBAAM,SAAOC,EAAA,KAAe;AAAA,cAAA;cAC3E7M,EAAwB,gBAAf0M,EAAA,KAAK,GAAA,CAAA;AAAA,YAAA;YAEFC,EAAA,cAAdzO,EAES,UAAA;AAAA;cAFkB,OAAM;AAAA,cAAyB,SAAO0M;AAAA,YAAA;cAC/DzM,EAA+CC,EAAAC,CAAA,GAAA;AAAA,gBAAzC,MAAK;AAAA,gBAAW,OAAM;AAAA,gBAAK,QAAO;AAAA,cAAA;;;UAK5C2B,EAmCM,OAnCNmB,IAmCM;AAAA,YAjCJnB,EAA0D,OAA1D+D,IAA0DvD,EAAnBsM,EAAA,KAAU,GAAA,CAAA;AAAA,YAGtCjP,EAAA,SAAS,WAAM,gBAA1BqC,KAAAhC,EAQM,OARNoC,IAQM;AAAA,cAPJN,EAKM,OALN0H,IAKM;AAAA,gBAJJ1H,EAGE,OAAA;AAAA,kBAFA,OAAM;AAAA,kBACL,OAAK+M,GAAA,EAAA,OAAA,GAAclP,EAAA,SAAS,OAAO,IAAA,CAAA;AAAA,gBAAA;;cAGxCmC,EAAoE,QAApEgE,IAAoExD,EAA3B3C,WAAS,OAAO,IAAG,KAAC,CAAA;AAAA,YAAA;YAIpDA,EAAA,SAAS,eAAeA,EAAA,SAAS,WAAM,gBAAlDqC,KAAAhC,EAEM,OAFNqC,IAEMC,EADD3C,EAAA,SAAS,WAAW,GAAA,CAAA;YAIdA,EAAA,SAAS,cAAcA,EAAA,SAAS,aAAU,KAAQA,EAAA,SAAS,WAAM,gBAA5EqC,EAAA,GAAAhC,EAEM,OAFNuC,IAEMD,EADD3C,EAAA,SAAS,kBAAc,CAAA,IAAQ,QAAG2C,EAAG3C,EAAA,SAAS,UAAU,IAAG,SAChE,CAAA;YAGWA,EAAA,SAAS,SAApBqC,EAAA,GAAAhC,EAEM,OAFN8O,IAEMxM,EADD3C,EAAA,SAAS,KAAK,GAAA,CAAA;YAIRA,EAAA,SAAS,WAAM,aAAkBA,EAAA,SAAS,cAArDqC,EAAA,GAAAhC,EAGM,OAHN+N,IAGM;AAAA,cAFJnM,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAE,EAAuD,QAAA,EAAjD,OAAM,+BAAA,GAA+B,SAAK,EAAA;AAAA,cAChDA,EAA0E,QAA1EkM,IAA0E1L,EAA7B3C,EAAA,SAAS,UAAU,GAAA,CAAA;AAAA,YAAA;;UAKpEmC,EAuBM,OAvBNmM,IAuBM;AAAA,YArBItO,EAAA,SAAS,WAAM,qBADvBK,EAMS,UAAA;AAAA;cAJP,OAAM;AAAA,cACL,gCAAOW,EAAI,QAAA;AAAA,YAAA,GACb,MAED;YAEQhB,EAAA,SAAS,WAAM,aAAkBA,EAAA,SAAS,mBADlDK,EAOS,UAAA;AAAA;cALP,OAAM;AAAA,cACL,SAAK4B,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAH,MAAEd,EAAI,cAAehB,EAAA,SAAS,UAAU;AAAA,YAAA;cAE9CM,EAAyDC,EAAAC,CAAA,GAAA;AAAA,gBAAnD,MAAK;AAAA,gBAAqB,OAAM;AAAA,gBAAK,QAAO;AAAA,cAAA;iCAAO,WAE3D,EAAA;AAAA,YAAA;YAEQsO,EAAA,cADRzO,EAMS,UAAA;AAAA;cAJP,OAAM;AAAA,cACL,SAAO0M;AAAA,YAAA,GACT,MAED;;;;;;;;;;;;;;;;;;;;ACoBV,UAAMhN,IAAQC,GAORgB,IAAOC;AAKb,aAASmO,EAAYhQ,GAAgBQ,GAAuB;AAE1D,UAAIR,MAASR,EAAS;AACpB,eAAO;AAIT,UAAIgB;AACF,eAAOZ,GAAgBY,GAAMR,CAAI;AAInC,cAAQA,GAAA;AAAA,QACN,KAAKR,EAAS;AAAO,iBAAO;AAAA,QAC5B,KAAKA,EAAS;AAAO,iBAAO;AAAA,QAC5B,KAAKA,EAAS;AAAO,iBAAO;AAAA,QAC5B,KAAKA,EAAS;AAAU,iBAAO;AAAA,QAC/B,KAAKA,EAAS;AAAM,iBAAO;AAAA,QAC3B,KAAKA,EAAS;AAAS,iBAAO;AAAA,QAC9B;AAAS,iBAAO;AAAA,MAAA;AAAA,IAEpB;AAGA,aAASyQ,EAAajQ,GAAwB;AAC5C,cAAQA,GAAA;AAAA,QACN,KAAKR,EAAS;AAAQ,iBAAO;AAAA,QAC7B,KAAKA,EAAS;AAAO,iBAAO;AAAA,QAC5B,KAAKA,EAAS;AAAO,iBAAO;AAAA,QAC5B,KAAKA,EAAS;AAAO,iBAAO;AAAA,QAC5B,KAAKA,EAAS;AAAU,iBAAO;AAAA,QAC/B,KAAKA,EAAS;AAAM,iBAAO;AAAA,QAC3B,KAAKA,EAAS;AAAS,iBAAO;AAAA,QAC9B;AAAS,iBAAO;AAAA,MAAA;AAAA,IAEpB;AAGA,aAAS0Q,EAAgBlQ,GAAgBE,GAAsB;AAC7D,cAAQF,GAAA;AAAA,QACN,KAAKR,EAAS;AAAQ,iBAAO;AAAA,QAC7B,KAAKA,EAAS;AAAO,iBAAO,KAAKU,IAAM,KAAKA,EAAI,aAAa,MAAM,EAAE;AAAA,QACrE,KAAKV,EAAS;AAAO,iBAAO,KAAKU,IAAM,KAAKA,EAAI,aAAa,MAAM,EAAE;AAAA,QACrE,KAAKV,EAAS;AAAO,iBAAO,KAAKU,IAAM,KAAKA,EAAI,aAAa,MAAM,EAAE;AAAA,QACrE,KAAKV,EAAS;AAAU,iBAAO,KAAKU,IAAM,KAAKA,EAAI,aAAa,MAAM,EAAE;AAAA,QACxE,KAAKV,EAAS;AAAM,iBAAO,OAAOU,IAAM,KAAKA,EAAI,aAAa,MAAM,EAAE;AAAA,QACtE,KAAKV,EAAS;AAAS,iBAAO,MAAMU,IAAM,KAAKA,EAAI,aAAa,MAAM,EAAE;AAAA,QACxE;AAAS,iBAAOA,IAAM,GAAGA,EAAI,YAAA,CAAa,QAAQ;AAAA,MAAA;AAAA,IAEtD;AAGA,UAAMiQ,IAAYrP,EAAS,MAAM;AAC/B,UAAI,CAACH,EAAM,KAAM;AACjB,YAAMY,IAAUZ,EAAM,KAAK,KAAK,YAAY,GAAG;AAC/C,UAAI,EAAAY,MAAY,MAAMA,MAAY;AAClC,eAAOZ,EAAM,KAAK,KAAK,UAAUY,IAAU,CAAC,EAAE,YAAA;AAAA,IAChD,CAAC,GAGK6O,IAAYtP,EAAS,MAAM;AAC/B,UAAI,CAACH,EAAM,KAAM,QAAO;AACxB,YAAM0P,IAAY1P,EAAM,KAAK,GAAG,YAAY,GAAG;AAC/C,aAAI0P,MAAc,KAAW1P,EAAM,KAAK,KACjCA,EAAM,KAAK,GAAG,UAAU,GAAG0P,CAAS,KAAK;AAAA,IAClD,CAAC;AAGD,aAAS3C,EAAoB3L,GAAe;AAC1C,MAAIA,EAAE,WAAWA,EAAE,iBACjBH,EAAK,OAAO;AAAA,IAEhB;AAGA,aAAS0O,EAAcvO,GAAkB;AACvC,MAAIA,EAAE,QAAQ,YAAYpB,EAAM,WAC9BiB,EAAK,OAAO;AAAA,IAEhB;AAEA,WAAAmM,GAAU,MAAM;AACd,eAAS,iBAAiB,WAAWuC,CAAa;AAAA,IACpD,CAAC,GAEDrG,GAAY,MAAM;AAChB,eAAS,oBAAoB,WAAWqG,CAAa;AAAA,IACvD,CAAC,mBA9LCnN,EAkFWmH,IAAA,EAlFD,IAAG,UAAM;AAAA,MACN1J,EAAA,WAAWA,EAAA,aAAtBK,EAgFM,OAAA;AAAA;QAhFsB,OAAM;AAAA,QAA4B,SAAOyM;AAAA,MAAA;QACnE3K,EA8EM,OA9ENW,IA8EM;AAAA,UA5EJX,EAUM,OAVNC,IAUM;AAAA,YATJD,EAKM,OALNiB,IAKM;AAAA,cAJJ9C,EAAiIC,EAAAC,CAAA,GAAA;AAAA,gBAA1H,MAAM4O,EAAYpP,EAAA,KAAK,MAAMA,EAAA,KAAK,IAAI;AAAA,gBAAG,OAAM;AAAA,gBAAK,QAAO;AAAA,gBAAK,UAAM,kBAAyBqP,EAAarP,EAAA,KAAK,IAAI,CAAA,CAAA;AAAA,cAAA;cAC5HmC,EAEO,QAAA;AAAA,gBAFD,OAAM;AAAA,gBAAyB,OAAOnC,EAAA,KAAK;AAAA,cAAA,GAC5C2C,EAAA3C,EAAA,KAAK,IAAI,GAAA,GAAAsC,EAAA;AAAA,YAAA;YAGhBH,EAES,UAAA;AAAA,cAFD,OAAM;AAAA,cAA0B,gCAAOnB,EAAI,OAAA;AAAA,YAAA;cACjDV,EAA+CC,EAAAC,CAAA,GAAA;AAAA,gBAAzC,MAAK;AAAA,gBAAW,OAAM;AAAA,gBAAK,QAAO;AAAA,cAAA;;;UAK5C2B,EAuDM,OAvDNmB,IAuDM;AAAA,YArDJnB,EAQM,OARN+D,IAQM;AAAA,cAPJ/D,EAGM,OAHNM,IAGM;AAAA,gBAFJnC,EAAkDC,EAAAC,CAAA,GAAA;AAAA,kBAA5C,MAAK;AAAA,kBAAc,OAAM;AAAA,kBAAK,QAAO;AAAA,gBAAA;gBAC3CyB,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAE,EAAe,cAAT,MAAE,EAAA;AAAA,cAAA;cAEVA,EAEM,OAFN0H,IAEMlH,EADD2M,EAAgBtP,EAAA,KAAK,MAAMuP,EAAA,KAAS,CAAA,GAAA,CAAA;AAAA,YAAA;YAKhCvP,EAAA,KAAK,SAASO,EAAA3B,CAAA,EAAS,UAAUoB,EAAA,KAAK,QAAjDqC,EAAA,GAAAhC,EAQM,OARN8F,IAQM;AAAA,cAPJhE,EAGM,OAHNO,IAGM;AAAA,gBAFJpC,EAAwDC,EAAAC,CAAA,GAAA;AAAA,kBAAlD,MAAK;AAAA,kBAAoB,OAAM;AAAA,kBAAK,QAAO;AAAA,gBAAA;gBACjDyB,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAE,EAAe,cAAT,MAAE,EAAA;AAAA,cAAA;cAEVA,EAEM,OAFNS,IAEMD,EADD3C,EAAA,KAAK,IAAI,GAAA,CAAA;AAAA,YAAA;YAKhBmC,EAQM,OARNgN,IAQM;AAAA,cAPJhN,EAGM,OAHNiM,IAGM;AAAA,gBAFJ9N,EAAqDC,EAAAC,CAAA,GAAA;AAAA,kBAA/C,MAAK;AAAA,kBAAiB,OAAM;AAAA,kBAAK,QAAO;AAAA,gBAAA;gBAC9CyB,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAE,EAAe,cAAT,MAAE,EAAA;AAAA,cAAA;cAEVA,EAEM,OAAA;AAAA,gBAFD,OAAM;AAAA,gBAAyC,OAAOqN,EAAA;AAAA,cAAA,KACtDA,EAAA,KAAS,GAAA,GAAAnB,EAAA;AAAA,YAAA;YAKhBlM,EAQM,OARNmM,IAQM;AAAA,cAPJnM,EAGM,OAHNoM,IAGM;AAAA,gBAFJjO,EAAqDC,EAAAC,CAAA,GAAA;AAAA,kBAA/C,MAAK;AAAA,kBAAiB,OAAM;AAAA,kBAAK,QAAO;AAAA,gBAAA;gBAC9CyB,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAE,EAAiB,cAAX,QAAI,EAAA;AAAA,cAAA;cAEZA,EAEM,OAAA;AAAA,gBAFD,OAAM;AAAA,gBAAyC,OAAOnC,EAAA,KAAK;AAAA,cAAA,GAC3D2C,EAAA3C,EAAA,KAAK,EAAE,GAAA,GAAA2P,EAAA;AAAA,YAAA;YAKH3P,EAAA,KAAK,gBAAhBqC,KAAAhC,EAQM,OARNmO,IAQM;AAAA,cAPJrM,EAGM,OAHNsM,IAGM;AAAA,gBAFJnO,EAAmDC,EAAAC,CAAA,GAAA;AAAA,kBAA7C,MAAK;AAAA,kBAAe,OAAM;AAAA,kBAAK,QAAO;AAAA,gBAAA;gBAC5CyB,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAE,EAAiB,cAAX,QAAI,EAAA;AAAA,cAAA;cAEZA,EAEM,OAFNuM,IAEM/L,EADD3C,EAAA,KAAK,YAAY,GAAA,CAAA;AAAA,YAAA;;UAM1BmC,EAIM,OAJNwM,IAIM;AAAA,YAHJxM,EAES,UAAA;AAAA,cAFD,OAAM;AAAA,cAAwB,gCAAOnB,EAAI,OAAA;AAAA,YAAA,GAAW,MAE5D;AAAA,UAAA;;;;;;AC7EH,SAAS4O,KAAe;AAC7B,QAAMrM,IAAcC,EAAiB,oBAAI,KAAK,GACxCqM,IAAiBrM,EAAmB,IAAI,GACxCC,IAAYD,EAAmB,IAAI,GAKnCa,IAAiB,MAAM;AAC3B,IAAAd,EAAY,4BAAY,IAAA,GACxBsM,EAAe,QAAQ;AAAA,EACzB;AA+EA,SAAO;AAAA,IACL,aAAAtM;AAAA,IACA,gBAAAsM;AAAA,IACA,WAAApM;AAAA,IACA,gBAAAY;AAAA,IACA,YA3EiB,CACjBkB,GACAoB,GACAmJ,IAAiB,IACjBC,IAAiB,OACd;AACH,UAAI,CAACxK,GAAI;AACP,QAAAlB,EAAA;AACA;AAAA,MACF;AAGA,UAAI0L,KAASF,EAAe,OAAO;AACjC,cAAMG,IAASrJ,EAAM,UAAU,OAAKhF,EAAE,OAAOkO,EAAe,KAAK,GAC3DI,IAAStJ,EAAM,UAAU,CAAAhF,MAAKA,EAAE,OAAO4D,CAAE;AAE/C,YAAIyK,MAAW,MAAMC,MAAW,IAAI;AAClC,gBAAM/L,IAAQ,KAAK,IAAI8L,GAAQC,CAAM,GAC/B9L,IAAM,KAAK,IAAI6L,GAAQC,CAAM,GAC7BnM,IAAS,IAAI,IAAIgM,IAAQvM,EAAY,QAAQ,EAAE;AACrD,mBAAS5B,IAAIuC,GAAOvC,KAAKwC,GAAKxC,KAAK;AACjC,kBAAMb,IAAO6F,EAAMhF,CAAC;AACpB,YAAIb,KACFgD,EAAO,IAAIhD,EAAK,EAAE;AAAA,UAEtB;AACA,UAAAyC,EAAY,QAAQO;AACpB;AAAA,QACF;AAAA,MACF;AAGA,UAAIgM,GAAO;AACT,cAAMhM,IAAS,IAAI,IAAIP,EAAY,KAAK;AACxC,QAAIO,EAAO,IAAIyB,CAAE,IACfzB,EAAO,OAAOyB,CAAE,IAEhBzB,EAAO,IAAIyB,CAAE,GAEfsK,EAAe,QAAQtK,GACvBhC,EAAY,QAAQO;AACpB;AAAA,MACF;AAGA,MAAA+L,EAAe,QAAQtK,GACvBhC,EAAY,QAAQ,oBAAI,IAAI,CAACgC,CAAE,CAAC;AAAA,IAClC;AAAA,IA6BE,WAxBgB,CAACoB,MAAsB;AACvC,MAAApD,EAAY,QAAQ,IAAI,IAAIoD,EAAM,IAAI,CAAAhF,MAAKA,EAAE,EAAE,CAAC;AAAA,IAClD;AAAA,IAuBE,YAlBiB,CAAC4D,MAAsB;AACxC,MAAA9B,EAAU,QAAQ8B;AAAA,IACpB;AAAA,IAiBE,YAZiB,CAACA,MACXhC,EAAY,MAAM,IAAIgC,CAAE;AAAA,EAW/B;AAEJ;ACnGO,SAAS2K,GACdC,GACAC,GACAC,GACA;AACA,QAAM3M,IAAaF,EAAmB,IAAI,GACpCuG,IAAavG,EAAI,EAAK;AAgF5B,SAAO;AAAA,IACL,YAAAE;AAAA,IACA,YAAAqG;AAAA,IACA,iBA9EsB,CAAC5I,GAAcmP,MAAmB;AACxD,UAAI,CAACnP,EAAE,aAAc;AAErB,YAAMoC,IAAc4M,EAAA;AAGpB,MAAK5M,EAAY,IAAI+M,CAAM,KACzBF,EAASE,GAAQ,IAAO,EAAK;AAI/B,YAAMlL,IAAa7B,EAAY,IAAI+M,CAAM,IAAI/M,IAAc,oBAAI,IAAI,CAAC+M,CAAM,CAAC;AAC3E,MAAAnP,EAAE,aAAa,QAAQ,cAAc,KAAK,UAAU,CAAC,GAAGiE,CAAU,CAAC,CAAC,GACpEjE,EAAE,aAAa,gBAAgB,QAE/B4I,EAAW,QAAQ;AAAA,IACrB;AAAA,IA+DE,gBA1DqB,CAAC5I,GAAcL,MAAmB;AACvD,MAAKiJ,EAAW,SAGZjJ,EAAK,SAASlC,EAAS,WACLuR,EAAA,EAEH,IAAIrP,EAAK,EAAE,MAC1BK,EAAE,eAAA,GACFuC,EAAW,QAAQ5C,EAAK;AAAA,IAG9B;AAAA,IA+CE,iBA1CsB,MAAM;AAC5B,MAAA4C,EAAW,QAAQ;AAAA,IACrB;AAAA,IAyCE,YApCiB,CAACvC,GAAc+D,MAAyB;AAIzD,UAHAxB,EAAW,QAAQ,MACnBqG,EAAW,QAAQ,IAEf,CAAC5I,EAAE,gBAAgB+D,EAAW,SAAStG,EAAS,OAAQ;AAE5D,YAAMuG,IAAOhE,EAAE,aAAa,QAAQ,YAAY;AAChD,UAAKgE;AAEL,YAAI;AACF,gBAAMC,IAAuB,KAAK,MAAMD,CAAI,GACtCoL,IAAU,IAAI,IAAInL,CAAU;AAGlC,cAAImL,EAAQ,IAAIrL,EAAW,EAAE,EAAG;AAEhC,UAAAmL,EAAOnL,EAAW,IAAIqL,CAAO;AAAA,QAC/B,QAAQ;AAAA,QAER;AAAA,IACF;AAAA,IAiBE,eAZoB,MAAM;AAC1B,MAAA7M,EAAW,QAAQ,MACnBqG,EAAW,QAAQ;AAAA,IACrB;AAAA,EASE;AAEJ;AChGO,SAASyG,GACdC,GACAC,GACA;AACA,QAAMC,IAAYnN,EAAI,EAAK,GACrBoN,IAAWpN,EAAI,CAAC,GAChBqN,IAAcrN,EAAI,CAAC,GACnBsN,IAAWtN,EAAI,CAAC,GAChBuN,IAAUvN,EAAI,EAAK,GACnBwN,IAASxN,EAAI,CAAC,GACdyN,IAAazN,EAAI,CAAC,GAClB0N,IAAe1N,EAAI,EAAK,GAExB2N,IAAUV,MAAc7R,EAAS,OAKjCwS,IAAiB,MAAM;AAC3B,UAAMC,IAAQX,EAAA;AACd,QAAIW,GAAO;AACT,YAAMC,IAAOD,EAAM,aACbE,IAAMF,EAAM;AAClB,MAAAR,EAAY,QAAQS,GAChBC,KAAO,CAAC,MAAMA,CAAG,MACnBT,EAAS,QAAQS,GACjBX,EAAS,QAASU,IAAOC,IAAO;AAAA,IAEpC;AAAA,EACF;AAuHA,SAAO;AAAA,IACL,WAAAZ;AAAA,IACA,UAAAC;AAAA,IACA,aAAAC;AAAA,IACA,UAAAC;AAAA,IACA,SAAAC;AAAA,IACA,QAAAC;AAAA,IACA,cAAAE;AAAA,IACA,SAAAC;AAAA,IACA,YA3HiB,MAAM;AACvB,YAAME,IAAQX,EAAA;AACd,MAAIW,MACEV,EAAU,SACZU,EAAM,MAAA,GACNV,EAAU,QAAQ,OAElBU,EAAM,KAAA,GACNV,EAAU,QAAQ;AAAA,IAGxB;AAAA,IAiHE,YA5GiB,MAAM;AACvB,YAAMU,IAAQX,EAAA;AACd,UAAIW;AACF,YAAIN,EAAQ,OAAO;AACjB,gBAAMS,IAAeP,EAAW,SAAS;AACzC,UAAAI,EAAM,SAASG,GACfH,EAAM,QAAQ,IACdL,EAAO,QAAQQ,GACfT,EAAQ,QAAQ;AAAA,QAClB;AACE,UAAAE,EAAW,QAAQD,EAAO,OAC1BK,EAAM,SAAS,GACfA,EAAM,QAAQ,IACdL,EAAO,QAAQ,GACfD,EAAQ,QAAQ;AAAA,IAGtB;AAAA,IA4FE,oBAvFyB,CAACU,MAAgB;AAC1C,MAAAT,EAAO,QAAQS;AACf,YAAMJ,IAAQX,EAAA;AACd,MAAIW,MACFA,EAAM,SAASI,GACXA,MAAQ,KACVV,EAAQ,QAAQ,IAChBM,EAAM,QAAQ,OAEdN,EAAQ,QAAQ,IAChBM,EAAM,QAAQ;AAAA,IAGpB;AAAA,IA2EE,QAtEa,CAACK,MAAiB;AAC/B,YAAML,IAAQX,EAAA;AACd,MAAIW,KAASP,EAAS,UACpBO,EAAM,cAAcK,GACpBb,EAAY,QAAQa,GACpBd,EAAS,QAASc,IAAOZ,EAAS,QAAS;AAAA,IAE/C;AAAA,IAgEE,YA3DiB,CAACY,MAAiB;AACnC,UAAI,MAAMA,CAAI,EAAG,QAAO;AACxB,YAAMC,IAAU,KAAK,MAAMD,IAAO,EAAE,GAC9BE,IAAU,KAAK,MAAMF,IAAO,EAAE;AACpC,aAAO,GAAGC,CAAO,IAAIC,EAAQ,WAAW,SAAS,GAAG,GAAG,CAAC;AAAA,IAC1D;AAAA,IAuDE,UAlDe,MAAM;AACrB,MAAA9I,GAAS,MAAM;AACb,cAAMuI,IAAQX,EAAA;AACd,SAAKD,MAAc7R,EAAS,SAASuS,MAAYE,MAC/CA,EAAM,SAASL,EAAO,OACtBK,EAAM,OAAO,MAAM,MAAM;AAAA,QAAC,CAAC,GAC3BV,EAAU,QAAQ;AAAA,MAEtB,CAAC;AAAA,IACH;AAAA,IA0CE,qBArC0B,MAAM;AAChC,YAAMU,IAAQX,EAAA;AACd,MAAIW,MACFA,EAAM,iBAAiB,cAAcD,CAAc,GACnDC,EAAM,iBAAiB,kBAAkBD,CAAc,GACvDC,EAAM,iBAAiB,SAAS,MAAM;AACpC,QAAAV,EAAU,QAAQ;AAAA,MACpB,CAAC;AAAA,IAEL;AAAA,IA6BE,uBAxB4B,MAAM;AAClC,YAAMU,IAAQX,EAAA;AACd,MAAIW,MACFA,EAAM,oBAAoB,cAAcD,CAAc,GACtDC,EAAM,oBAAoB,kBAAkBD,CAAc;AAAA,IAE9D;AAAA,IAmBE,gBAAAA;AAAA,EAAA;AAEJ;AC7JO,SAASS,GAAmBlL,GAAyB;AAE1D,QAAMmL,wBAAmB,IAAA,GAGnBC,IAAcvO,EAAyB,oBAAI,KAAK,GAKhDwO,IAAsB,OAAOlR,MAAmB;AACpD,QAAI,EAAAA,EAAK,SAASlC,EAAS,eAAe,CAACkC,EAAK,KAGhD;AAAA,UAAIgR,EAAa,IAAIhR,EAAK,EAAE,GAAG;AAC7B,cAAMmR,IAAYH,EAAa,IAAIhR,EAAK,EAAE;AAC1C,QAAImR,KACFF,EAAY,MAAM,IAAIjR,EAAK,IAAImR,CAAS;AAE1C;AAAA,MACF;AAGA,UAAI,CAAAF,EAAY,MAAM,IAAIjR,EAAK,EAAE,KAI7B,OAAO,OAAO,kBAAoB,OAAe,OAAO,gBAAgB;AAC1E,YAAI;AACF,gBAAMoR,IAAU,MAAM,OAAO,gBAAgB,mBAAmBpR,EAAK,EAAE;AACvE,UAAIoR,MACFJ,EAAa,IAAIhR,EAAK,IAAIoR,CAAO,GACjCH,EAAY,MAAM,IAAIjR,EAAK,IAAIoR,CAAO;AAAA,QAE1C,SAAS7M,GAAO;AACd,kBAAQ,MAAM,uCAAuCvE,EAAK,IAAI,KAAKuE,CAAK;AAAA,QAC1E;AAAA;AAAA,EAEJ;AAKA,SAAAuD,GAAMjC,GAAO,CAACwL,MAAa;AACzB,IAAAA,EAAS,QAAQ,CAAArR,MAAQ;AACvB,MAAIA,EAAK,SAASlC,EAAS,eAAe,CAACmT,EAAY,MAAM,IAAIjR,EAAK,EAAE,KACtEkR,EAAoBlR,CAAI;AAAA,IAE5B,CAAC;AAAA,EACH,GAAG,EAAE,WAAW,IAAM,MAAM,IAAM,GAS3B;AAAA,IACL,eALoB,CAACA,MACdiR,EAAY,MAAM,IAAIjR,EAAK,EAAE;AAAA,IAKpC,qBAAAkR;AAAA,EAAA;AAEJ;"}
|