Refactor: improve UX to prevent accidental space as download path

This commit is contained in:
arabcoders 2025-12-29 17:11:07 +03:00
parent 450b140561
commit 0dccfad5c8
8 changed files with 134 additions and 95 deletions

View file

@ -9,7 +9,7 @@
<span class="icon"><i class="fa-solid fa-link" /></span>
<span class="has-tooltip" v-tooltip="'Use Shift+Enter to switch to multiline input mode.'">
URLs separated by newlines or <span class="is-bold is-lowercase">{{ getSeparatorsName(separator)
}}</span>
}}</span>
</span>
</label>
<div class="field is-grouped">
@ -33,11 +33,14 @@
</div>
<div class="column is-4-tablet is-12-mobile">
<label class="label" for="preset">
<span class="icon"><i class="fa-solid fa-sliders" /></span>
<span>Preset</span>
</label>
<div class="field has-addons">
<div class="control" @click="show_description = !show_description">
<label class="button is-static">
<span class="icon"><i class="fa-solid fa-sliders" /></span>
<span>Preset</span>
</label>
</div>
<div class="control is-expanded">
@ -62,22 +65,25 @@
</div>
<div class="column is-6-tablet is-12-mobile">
<div class="field has-addons" v-tooltip="'Folder relative to ' + config.app.download_path">
<div class="control">
<label class="label" for="folder">
<span class="icon"><i class="fa-solid fa-save" /></span>
<span>Download path</span>
</label>
<div class="field has-addons">
<div class="control" v-tooltip="`Download path relative to: ${config.app.download_path}`">
<label class="button is-static">
<span class="icon"><i class="fa-solid fa-folder" /></span>
<span>Save in</span>
<span>{{ shortPath(config.app.download_path) }}</span>
</label>
</div>
<div class="control is-expanded">
<input type="text" class="input is-fullwidth" id="path" v-model="form.folder"
<input type="text" class="input is-fullwidth" id="folder" v-model="form.folder"
:placeholder="getDefault('folder', '/')" :disabled="!socket.isConnected || addInProgress"
list="folders">
</div>
</div>
</div>
<div class="column">
<div class="column is-align-content-end">
<button type="button" class="button is-info" @click="showAdvanced = !showAdvanced"
:disabled="!socket.isConnected">
<span class="icon"><i class="fa-solid fa-cog" /></span>
@ -161,7 +167,7 @@
<span class="icon"><i class="fa-solid fa-info" /></span>
<span>Use the <NuxtLink target="_blank"
to="https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp">
Recommended addon</NuxtLink> by yt-dlp to export cookies. <span class="has-text-danger">The
Recommended addon</NuxtLink> to export cookies. <span class="has-text-danger">The
cookies MUST be in Netscape HTTP Cookie format.</span>
</span>
</span>
@ -401,12 +407,6 @@ const splitUrls = (urlString: string): Array<string> => {
}
const addDownload = async () => {
if (' ' === form.value?.folder) {
toast.warning('The download folder contain only spaces. Resetting to default.')
form.value.folder = ''
await nextTick()
}
if (form.value.folder) {
form.value.folder = form.value.folder.trim()
}
@ -578,14 +578,9 @@ onMounted(async () => {
form.value.preset = config.app.default_preset
}
if (' ' === form.value?.folder) {
toast.warning('The download folder contain only spaces. Resetting to default.')
form.value.folder = ''
await nextTick()
}
if (form.value.folder) {
if (form.value?.folder) {
form.value.folder = form.value.folder.trim()
await nextTick()
}
if (config.isLoaded() && form.value?.preset && !config.presets.some(p => p.name === form.value.preset)) {
@ -620,6 +615,11 @@ const runCliCommand = async (): Promise<void> => {
return
}
if (form.value?.folder) {
form.value.folder = form.value.folder.trim()
await nextTick()
}
const { status } = await dialog.confirmDialog({
title: 'Run CLI Command',
message: `This will generate a yt-dlp command and run it in the console. Continue?`,
@ -697,11 +697,13 @@ const testDownloadOptions = async (): Promise<void> => {
return
}
let form_cli = (form.value?.cli || '').trim()
if (' ' === form.value?.folder) {
form.value.folder = ''
if (form.value?.folder) {
form.value.folder = form.value.folder.trim()
await nextTick()
}
let form_cli = (form.value?.cli || '').trim()
if (dlFields.value && Object.keys(dlFields.value).length > 0) {
const joined = []
for (const [key, value] of Object.entries(dlFields.value)) {

View file

@ -1,7 +1,7 @@
<template>
<main class="columns mt-2 is-multiline">
<div class="column is-12">
<form autocomplete="off" id="presetForm" @submit.prevent="checkInfo()">
<form autocomplete="off" id="presetForm" @submit.prevent="checkInfo">
<div class="card">
<div class="card-header">
<div class="card-header-title is-text-overflow is-block">
@ -104,28 +104,32 @@
</div>
<div class="column is-6-tablet is-12-mobile">
<div class="field">
<label class="label is-inline" for="folder">
<span class="icon"><i class="fa-solid fa-folder" /></span>
Default Download path
</label>
<div class="control">
<label class="label is-inline" for="folder">
<span class="icon"><i class="fa-solid fa-save" /></span>
download path
</label>
<div class="field has-addons">
<div class="control" v-tooltip="`Full Path: ${config.app.download_path}`">
<span class="button is-static">
<span>{{ shortPath(config.app.download_path) }}</span>
</span>
</div>
<div class="control is-expanded">
<input type="text" class="input" id="folder" placeholder="Leave empty to use default download path"
v-model="form.folder" :disabled="addInProgress" list="folders">
</div>
<span class="help is-bold">
<span class="icon"><i class="fa-solid fa-info" /></span>
<span>Use this folder if non is given with URL. Leave empty to use default download path. Default
download path <code>{{ config.app.download_path }}</code>.</span>
</span>
</div>
<span class="help is-bold">
<span class="icon"><i class="fa-solid fa-info" /></span>
<span>Use this defined path if non are given with the URL.</span>
</span>
</div>
<div class="column is-6-tablet is-12-mobile">
<div class="field">
<label class="label is-inline" for="output_template">
<span class="icon"><i class="fa-solid fa-file" /></span>
Default Output template
Output template
</label>
<div class="control">
<input type="text" class="input" id="output_template" :disabled="addInProgress"
@ -133,10 +137,7 @@
</div>
<span class="help is-bold">
<span class="icon"><i class="fa-solid fa-info" /></span>
<span>Use this output template if non are given with URL. if not set, it will defaults to
<code>{{ config.app.output_template }}</code>. For more information visit <NuxtLink
href="https://github.com/yt-dlp/yt-dlp#output-template" target="_blank">this page</NuxtLink>.
</span>
<span>Use this output template if non are given with URL.</span>
</span>
</div>
</div>
@ -277,6 +278,11 @@ const checkInfo = async (): Promise<void> => {
}
}
if (form.folder) {
form.folder = form.folder.trim()
await nextTick()
}
if (form.cli && '' !== form.cli) {
const options = await convertOptions(form.cli)
if (null === options) {

View file

@ -191,8 +191,8 @@
<span class="help">
<span class="icon"><i class="fa-solid fa-info" /></span>
<span class="is-bold">
The CRON timer expression to use for this task. If not set, the task will be disabled. For more
information on CRON expressions, see <NuxtLink to="https://crontab.guru/" target="_blank">
The CRON timer expression to use for this task. If not set, the task runner will be disabled. For
more information on CRON expressions, see <NuxtLink to="https://crontab.guru/" target="_blank">
crontab.guru</NuxtLink>.
</span>
</span>
@ -200,21 +200,27 @@
</div>
<div class="column is-6-tablet is-12-mobile">
<div class="field">
<label class="label is-inline" for="folder">
<span class="icon"><i class="fa-solid fa-folder" /></span>
Save in
</label>
<div class="control">
<label class="label is-inline" for="folder">
<span class="icon"><i class="fa-solid fa-save" /></span>
Download path
</label>
<div class="field has-addons">
<div class="control" v-tooltip="`Full Path: ${config.app.download_path}`">
<span class="button is-static">
<span>{{ shortPath(config.app.download_path) }}</span>
</span>
</div>
<div class="control is-expanded">
<input type="text" class="input" id="folder" :placeholder="getDefault('folder', '/')"
v-model="form.folder" :disabled="addInProgress" list="folders">
</div>
<span class="help">
<span class="icon"><i class="fa-solid fa-info" /></span>
<span class="is-bold">All folders are sub-folders of
<code>{{ config.app.download_path }}</code>.</span>
</span>
</div>
<span class="help">
<span class="icon"><i class="fa-solid fa-info" /></span>
<span class="is-bold">
Path relative to the download path, leave empty to use preset or default download path.
</span>
</span>
</div>
<div class="column is-6-tablet is-12-mobile">
@ -230,7 +236,9 @@
</div>
<span class="help">
<span class="icon"><i class="fa-solid fa-info" /></span>
<span class="is-bold">The template to use for the output file name.</span>
<span class="is-bold">
The template to use for the output file name. Leave empty to use preset or default template.
</span>
</span>
</div>
</div>
@ -251,7 +259,8 @@
<span class="help">
<span class="icon"><i class="fa-solid fa-info" /></span>
<span class="is-bold">Some URLs have special handlers to monitor for new content. Like YouTube
channels/playlists.</span>
channels/playlists. <span class="has-text-danger">Handlers run regardless of task timer.</span>
</span>
</span>
</div>
</div>
@ -324,6 +333,10 @@
<Message class="is-info" :newStyle="true">
<span>
<ul>
<li><strong>Tasks:</strong> requires <code>--download-archive</code> in
<code>Command options for yt-dlp</code> can be set via presets or manually. Default presets already
include this option.
</li>
<li><strong>YouTube RSS:</strong> Use <code>channel_id</code> or <code>playlist_id</code> URLs. Other link
types (custom names, handles, user profiles) are not supported.
</li>
@ -334,9 +347,6 @@
<li><strong>RSS Monitoring Basics:</strong> Runs hourly independently. Timer controls scheduled downloads to
yt-dlp. Disable <code>Enable Handler</code> to disable RSS monitoring.
</li>
<li><strong>Archive Requirement:</strong> RSS monitoring requires <code>--download-archive</code> in
<code>Command options for yt-dlp</code> (set in task or preset).
</li>
</ul>
</span>
</Message>
@ -420,6 +430,11 @@ const checkInfo = async (): Promise<void> => {
}
}
if (form.folder) {
form.folder = form.folder.trim()
await nextTick()
}
if (form.timer) {
try {
CronExpressionParser.parse(form.timer)

View file

@ -129,7 +129,7 @@
<p :class="{ 'is-text-overflow': !isExpanded(item.id, 'folder'), 'is-clickable': true }"
v-if="item.folder" @click="toggleExpand(item.id, 'folder')"
:title="!isExpanded(item.id, 'folder') ? 'Click to expand' : 'Click to collapse'">
<span class="icon"><i class="fa-solid fa-folder" /></span>
<span class="icon"><i class="fa-solid fa-save" /></span>
<span>{{ calcPath(item.folder) }}</span>
</p>
<p :class="{ 'is-text-overflow': !isExpanded(item.id, 'template'), 'is-clickable': true }"

View file

@ -332,7 +332,7 @@
<span v-else class="has-text-danger">No timer or handler</span>
</p>
<p class="is-text-overflow" v-if="item.folder">
<span class="icon"><i class="fa-solid fa-folder" /></span>
<span class="icon"><i class="fa-solid fa-save" /></span>
<span>{{ calcPath(item.folder) }}</span>
</p>
<p class="is-text-overflow" v-if="item.template">

View file

@ -703,11 +703,26 @@ const stripPath = (base_path: string, real_path: string): string => {
return real_path.replace(base_path, '').replace(/^\//, '')
}
const shortPath = (path: string, prefix: string = '...'): string => {
if (typeof path !== 'string') {
return path;
}
const hasTrailingSlash = /\/$/.test(path);
const clean = path.replace(/\/+$/, '');
const parts = clean.split('/').filter(Boolean);
if (parts.length <= 1) {
return path;
}
return `${prefix}/${parts.at(-1)}${hasTrailingSlash ? '/' : ''}`;
}
export {
separators, convertCliOptions, getSeparatorsName, iTrim, eTrim, sTrim, ucFirst,
getValue, ag, ag_set, awaitElement, r, copyText, dEvent, makePagination, encodePath,
request, removeANSIColors, dec2hex, makeId, basename, dirname, getQueryParams,
makeDownload, formatBytes, has_data, toggleClass, cleanObject, uri, formatTime,
sleep, awaiter, encode, decode, disableOpacity, enableOpacity, stripPath
sleep, awaiter, encode, decode, disableOpacity, enableOpacity, stripPath, shortPath
}

View file

@ -34,7 +34,7 @@
"moment": "^2.30.1",
"nuxt": "^4.2.2",
"pinia": "^3.0.4",
"socket.io-client": "^4.8.2",
"socket.io-client": "^4.8.3",
"vue": "^3.5.26",
"vue-router": "^4.6.4",
"vue-toastification": "2.0.0-rc.5"

View file

@ -57,8 +57,8 @@ importers:
specifier: ^3.0.4
version: 3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3))
socket.io-client:
specifier: ^4.8.2
version: 4.8.2
specifier: ^4.8.3
version: 4.8.3
vue:
specifier: ^3.5.26
version: 3.5.26(typescript@5.9.3)
@ -1267,8 +1267,8 @@ packages:
'@rolldown/pluginutils@1.0.0-beta.53':
resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==}
'@rolldown/pluginutils@1.0.0-beta.9-commit.d91dfb5':
resolution: {integrity: sha512-8sExkWRK+zVybw3+2/kBkYBFeLnEUWz1fT7BLHplpzmtqkOfTbAQ9gkt4pzwGIIZmg4Qn5US5ACjUBenrhezwQ==}
'@rolldown/pluginutils@1.0.0-beta.57':
resolution: {integrity: sha512-aQNelgx14tGA+n2tNSa9x6/jeoCL9fkDeCei7nOKnHx0fEFRRMu5ReiITo+zZD5TzWDGGRjbSYCs93IfRIyTuQ==}
'@rollup/plugin-alias@5.1.1':
resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==}
@ -1577,8 +1577,8 @@ packages:
resolution: {integrity: sha512-IrDKrw7pCRUR94zeuCSUWQ+w8JEf5ZX5jl/e6AHGSLi1/zIr0lgutfn/7JpfCey+urpgQEdrZVYzCaVVKiTwhQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@unhead/vue@2.0.19':
resolution: {integrity: sha512-7BYjHfOaoZ9+ARJkT10Q2TjnTUqDXmMpfakIAsD/hXiuff1oqWg1xeXT5+MomhNcC15HbiABpbbBmITLSHxdKg==}
'@unhead/vue@2.1.1':
resolution: {integrity: sha512-WYa8ORhfv7lWDSoNpkMKhbW1Dbsux/3HqMcVkZS3xZ2/c/VrcChLj+IMadpCd1WNR0srITfRJhBYZ1i9hON5Qw==}
peerDependencies:
vue: '>=3.5.18'
@ -1690,11 +1690,11 @@ packages:
engines: {node: '>=18'}
hasBin: true
'@vitejs/plugin-vue-jsx@5.1.2':
resolution: {integrity: sha512-3a2BOryRjG/Iih87x87YXz5c8nw27eSlHytvSKYfp8ZIsp5+FgFQoKeA7k2PnqWpjJrv6AoVTMnvmuKUXb771A==}
'@vitejs/plugin-vue-jsx@5.1.3':
resolution: {integrity: sha512-I6Zr8cYVr5WHMW5gNOP09DNqW9rgO8RX73Wa6Czgq/0ndpTfJM4vfDChfOT1+3KtdrNqilNBtNlFwVeB02ZzGw==}
engines: {node: ^20.19.0 || >=22.12.0}
peerDependencies:
vite: ^5.0.0 || ^6.0.0 || ^7.0.0
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
vue: ^3.0.0
'@vitejs/plugin-vue@6.0.3':
@ -1877,8 +1877,8 @@ packages:
ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
alien-signals@3.1.1:
resolution: {integrity: sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==}
alien-signals@3.1.2:
resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==}
ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
@ -3831,8 +3831,8 @@ packages:
serialize-javascript@6.0.2:
resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
seroval@1.4.1:
resolution: {integrity: sha512-9GOc+8T6LN4aByLN75uRvMbrwY5RDBW6lSlknsY4LEa9ZmWcxKcRe1G/Q3HZXjltxMHTrStnvrwAICxZrhldtg==}
seroval@1.4.2:
resolution: {integrity: sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ==}
engines: {node: '>=10'}
serve-placeholder@2.0.2:
@ -3881,8 +3881,8 @@ packages:
smob@1.5.0:
resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==}
socket.io-client@4.8.2:
resolution: {integrity: sha512-4MY14EMsyEPFA6lM01XIYepRdV8P6dUir2hxAlAysOYcbNAy5QNHYgIHOcQ1KYM7wTcKnKEW/ZRoIxRinWRXvA==}
socket.io-client@4.8.3:
resolution: {integrity: sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==}
engines: {node: '>=10.0.0'}
socket.io-parser@4.2.5:
@ -4130,8 +4130,8 @@ packages:
unenv@2.0.0-rc.24:
resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==}
unhead@2.0.19:
resolution: {integrity: sha512-gEEjkV11Aj+rBnY6wnRfsFtF2RxKOLaPN4i+Gx3UhBxnszvV6ApSNZbGk7WKyy/lErQ6ekPN63qdFL7sa1leow==}
unhead@2.1.1:
resolution: {integrity: sha512-NOt8n2KybAOxSLfNXegAVai4SGU8bPKqWnqCzNAvnRH2i8mW+0bbFjN/L75LBgCSTiOjJSpANe5w2V34Grr7Cw==}
unicorn-magic@0.3.0:
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
@ -4456,6 +4456,7 @@ packages:
whatwg-encoding@3.1.1:
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
engines: {node: '>=18'}
deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation
whatwg-mimetype@4.0.0:
resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
@ -5421,7 +5422,7 @@ snapshots:
dependencies:
'@nuxt/devalue': 2.0.2
'@nuxt/kit': 4.2.2(magicast@0.5.1)
'@unhead/vue': 2.0.19(vue@3.5.26(typescript@5.9.3))
'@unhead/vue': 2.1.1(vue@3.5.26(typescript@5.9.3))
'@vue/shared': 3.5.26
consola: 3.4.2
defu: 6.1.4
@ -5511,7 +5512,7 @@ snapshots:
'@nuxt/kit': 4.2.2(magicast@0.5.1)
'@rollup/plugin-replace': 6.0.3(rollup@4.54.0)
'@vitejs/plugin-vue': 6.0.3(vite@7.3.0(@types/node@22.18.1)(jiti@2.6.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))
'@vitejs/plugin-vue-jsx': 5.1.2(vite@7.3.0(@types/node@22.18.1)(jiti@2.6.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))
'@vitejs/plugin-vue-jsx': 5.1.3(vite@7.3.0(@types/node@22.18.1)(jiti@2.6.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))
autoprefixer: 10.4.23(postcss@8.5.6)
consola: 3.4.2
cssnano: 7.1.2(postcss@8.5.6)
@ -5531,7 +5532,7 @@ snapshots:
pkg-types: 2.3.0
postcss: 8.5.6
rollup-plugin-visualizer: 6.0.5(rollup@4.54.0)
seroval: 1.4.1
seroval: 1.4.2
std-env: 3.10.0
ufo: 1.6.1
unenv: 2.0.0-rc.24
@ -5799,7 +5800,7 @@ snapshots:
'@rolldown/pluginutils@1.0.0-beta.53': {}
'@rolldown/pluginutils@1.0.0-beta.9-commit.d91dfb5': {}
'@rolldown/pluginutils@1.0.0-beta.57': {}
'@rollup/plugin-alias@5.1.1(rollup@4.54.0)':
optionalDependencies:
@ -6072,10 +6073,10 @@ snapshots:
'@typescript-eslint/types': 8.50.1
eslint-visitor-keys: 4.2.1
'@unhead/vue@2.0.19(vue@3.5.26(typescript@5.9.3))':
'@unhead/vue@2.1.1(vue@3.5.26(typescript@5.9.3))':
dependencies:
hookable: 5.5.3
unhead: 2.0.19
unhead: 2.1.1
vue: 3.5.26(typescript@5.9.3)
'@unrs/resolver-binding-android-arm-eabi@1.11.1':
@ -6156,12 +6157,12 @@ snapshots:
- rollup
- supports-color
'@vitejs/plugin-vue-jsx@5.1.2(vite@7.3.0(@types/node@22.18.1)(jiti@2.6.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))':
'@vitejs/plugin-vue-jsx@5.1.3(vite@7.3.0(@types/node@22.18.1)(jiti@2.6.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))':
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
'@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5)
'@rolldown/pluginutils': 1.0.0-beta.9-commit.d91dfb5
'@rolldown/pluginutils': 1.0.0-beta.57
'@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.28.5)
vite: 7.3.0(@types/node@22.18.1)(jiti@2.6.1)(terser@5.44.1)(yaml@2.8.2)
vue: 3.5.26(typescript@5.9.3)
@ -6345,7 +6346,7 @@ snapshots:
'@volar/language-core': 2.4.27
'@vue/compiler-dom': 3.5.26
'@vue/shared': 3.5.26
alien-signals: 3.1.1
alien-signals: 3.1.2
muggle-string: 0.4.1
path-browserify: 1.0.1
picomatch: 4.0.3
@ -6427,7 +6428,7 @@ snapshots:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
alien-signals@3.1.1: {}
alien-signals@3.1.2: {}
ansi-regex@5.0.1: {}
@ -7947,7 +7948,7 @@ snapshots:
'@nuxt/schema': 4.2.2
'@nuxt/telemetry': 2.6.6(magicast@0.5.1)
'@nuxt/vite-builder': 4.2.2(@types/node@22.18.1)(eslint@9.39.2(jiti@2.6.1))(magicast@0.5.1)(nuxt@4.2.2(@parcel/watcher@2.5.1)(@types/node@22.18.1)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.8.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@22.18.1)(jiti@2.6.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@3.2.1(typescript@5.9.3))(yaml@2.8.2))(optionator@0.9.4)(rollup@4.54.0)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@3.2.1(typescript@5.9.3))(vue@3.5.26(typescript@5.9.3))(yaml@2.8.2)
'@unhead/vue': 2.0.19(vue@3.5.26(typescript@5.9.3))
'@unhead/vue': 2.1.1(vue@3.5.26(typescript@5.9.3))
'@vue/shared': 3.5.26
c12: 3.3.3(magicast@0.5.1)
chokidar: 5.0.0
@ -8628,7 +8629,7 @@ snapshots:
dependencies:
randombytes: 2.1.0
seroval@1.4.1: {}
seroval@1.4.2: {}
serve-placeholder@2.0.2:
dependencies:
@ -8677,7 +8678,7 @@ snapshots:
smob@1.5.0: {}
socket.io-client@4.8.2:
socket.io-client@4.8.3:
dependencies:
'@socket.io/component-emitter': 3.1.2
debug: 4.4.3
@ -8928,7 +8929,7 @@ snapshots:
dependencies:
pathe: 2.0.3
unhead@2.0.19:
unhead@2.1.1:
dependencies:
hookable: 5.5.3