change prompt & confirm
This commit is contained in:
parent
16b4747eb6
commit
f1c35be539
273
frontend/app.js
273
frontend/app.js
|
|
@ -299,6 +299,18 @@ function noteApp() {
|
||||||
selectedTemplate: '',
|
selectedTemplate: '',
|
||||||
newTemplateNoteName: '',
|
newTemplateNoteName: '',
|
||||||
|
|
||||||
|
// New note / folder name modal (replaces window.prompt)
|
||||||
|
showCreateNameModal: false,
|
||||||
|
createNameModalKind: 'note',
|
||||||
|
createNameModalTargetFolder: '',
|
||||||
|
createNameModalInput: '',
|
||||||
|
|
||||||
|
// Rename folder modal (replaces window.prompt)
|
||||||
|
showRenameFolderModal: false,
|
||||||
|
renameFolderPath: '',
|
||||||
|
renameFolderOldName: '',
|
||||||
|
renameFolderInput: '',
|
||||||
|
|
||||||
// Share state
|
// Share state
|
||||||
showShareModal: false,
|
showShareModal: false,
|
||||||
shareInfo: null,
|
shareInfo: null,
|
||||||
|
|
@ -3342,57 +3354,131 @@ function noteApp() {
|
||||||
},
|
},
|
||||||
|
|
||||||
async createNote(folderPath = null, directPath = null) {
|
async createNote(folderPath = null, directPath = null) {
|
||||||
let notePath;
|
|
||||||
|
|
||||||
if (directPath) {
|
if (directPath) {
|
||||||
// Direct path provided (e.g., from wiki link) - skip prompting
|
const notePath = directPath.endsWith('.md') ? directPath : `${directPath}.md`;
|
||||||
notePath = directPath.endsWith('.md') ? directPath : `${directPath}.md`;
|
const existingNote = this.notes.find(note => note.path === notePath);
|
||||||
} else {
|
if (existingNote) {
|
||||||
// Use provided folder path, or dropdown target folder context, or homepage folder
|
this.toast(this.t('notes.already_exists', { name: notePath }), { type: 'warning' });
|
||||||
// Note: Check dropdownTargetFolder !== null to distinguish between '' (root) and not set
|
return;
|
||||||
let targetFolder;
|
|
||||||
if (folderPath !== null) {
|
|
||||||
targetFolder = folderPath;
|
|
||||||
} else if (this.dropdownTargetFolder !== null && this.dropdownTargetFolder !== undefined) {
|
|
||||||
targetFolder = this.dropdownTargetFolder; // Can be '' for root or a folder path
|
|
||||||
} else {
|
|
||||||
targetFolder = this.selectedHomepageFolder || '';
|
|
||||||
}
|
}
|
||||||
this.closeDropdown();
|
await this._finalizeCreateNote(notePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const explicitTarget = folderPath !== null && folderPath !== undefined ? folderPath : undefined;
|
||||||
|
this.openCreateNameModal('note', explicitTarget);
|
||||||
|
},
|
||||||
|
|
||||||
const promptText = targetFolder
|
/**
|
||||||
? this.t('notes.prompt_name_in_folder', { folder: targetFolder })
|
* @param {'note'|'folder'} kind
|
||||||
|
* @param {string|undefined} explicitTargetFolder - if set, use as parent folder context ("" = root)
|
||||||
|
*/
|
||||||
|
openCreateNameModal(kind, explicitTargetFolder = undefined) {
|
||||||
|
let targetFolder;
|
||||||
|
if (explicitTargetFolder !== undefined) {
|
||||||
|
targetFolder = explicitTargetFolder;
|
||||||
|
} else if (this.dropdownTargetFolder !== null && this.dropdownTargetFolder !== undefined) {
|
||||||
|
targetFolder = this.dropdownTargetFolder;
|
||||||
|
} else {
|
||||||
|
targetFolder = this.selectedHomepageFolder || '';
|
||||||
|
}
|
||||||
|
this.closeDropdown();
|
||||||
|
this.mobileSidebarOpen = false;
|
||||||
|
this.createNameModalKind = kind;
|
||||||
|
this.createNameModalTargetFolder = targetFolder;
|
||||||
|
this.createNameModalInput = '';
|
||||||
|
this.showCreateNameModal = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const el = document.getElementById('create-name-modal-input');
|
||||||
|
if (el) {
|
||||||
|
el.focus();
|
||||||
|
el.select();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
closeCreateNameModal() {
|
||||||
|
this.showCreateNameModal = false;
|
||||||
|
this.createNameModalInput = '';
|
||||||
|
},
|
||||||
|
|
||||||
|
cancelCreateNameModal() {
|
||||||
|
this.closeCreateNameModal();
|
||||||
|
},
|
||||||
|
|
||||||
|
createNameModalHelpText() {
|
||||||
|
const tf = this.createNameModalTargetFolder;
|
||||||
|
if (this.createNameModalKind === 'note') {
|
||||||
|
return tf
|
||||||
|
? this.t('notes.prompt_name_in_folder', { folder: tf })
|
||||||
: this.t('notes.prompt_name_with_path');
|
: this.t('notes.prompt_name_with_path');
|
||||||
|
}
|
||||||
|
return tf
|
||||||
|
? this.t('folders.prompt_name_in_folder', { folder: tf })
|
||||||
|
: this.t('folders.prompt_name_with_path');
|
||||||
|
},
|
||||||
|
|
||||||
const noteName = prompt(promptText);
|
createNameModalTitle() {
|
||||||
if (!noteName) return;
|
return this.createNameModalKind === 'note'
|
||||||
|
? this.t('sidebar.new_note')
|
||||||
|
: this.t('sidebar.new_folder');
|
||||||
|
},
|
||||||
|
|
||||||
// Validate the name/path (may contain / for paths when no target folder)
|
createNameModalLabel() {
|
||||||
|
return this.createNameModalKind === 'note'
|
||||||
|
? this.t('templates.note_name')
|
||||||
|
: this.t('folders.prompt_name');
|
||||||
|
},
|
||||||
|
|
||||||
|
async submitCreateNameModal() {
|
||||||
|
const rawName = (this.createNameModalInput || '').trim();
|
||||||
|
if (!rawName) {
|
||||||
|
this.closeCreateNameModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const targetFolder = this.createNameModalTargetFolder;
|
||||||
|
const kind = this.createNameModalKind;
|
||||||
|
|
||||||
|
if (kind === 'note') {
|
||||||
const validation = targetFolder
|
const validation = targetFolder
|
||||||
? FilenameValidator.validateFilename(noteName)
|
? FilenameValidator.validateFilename(rawName)
|
||||||
: FilenameValidator.validatePath(noteName);
|
: FilenameValidator.validatePath(rawName);
|
||||||
|
|
||||||
if (!validation.valid) {
|
if (!validation.valid) {
|
||||||
this.toast(this.getValidationErrorMessage(validation, 'note'), { type: 'warning' });
|
this.toast(this.getValidationErrorMessage(validation, 'note'), { type: 'warning' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedName = validation.sanitized;
|
const validatedName = validation.sanitized;
|
||||||
|
const notePath = targetFolder
|
||||||
if (targetFolder) {
|
? `${targetFolder}/${validatedName}.md`
|
||||||
notePath = `${targetFolder}/${validatedName}.md`;
|
: (validatedName.endsWith('.md') ? validatedName : `${validatedName}.md`);
|
||||||
} else {
|
const existingNote = this.notes.find(note => note.path === notePath);
|
||||||
notePath = validatedName.endsWith('.md') ? validatedName : `${validatedName}.md`;
|
if (existingNote) {
|
||||||
|
this.toast(this.t('notes.already_exists', { name: notePath }), { type: 'warning' });
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
const ok = await this._finalizeCreateNote(notePath);
|
||||||
|
if (ok) this.closeCreateNameModal();
|
||||||
// CRITICAL: Check if note already exists (applies to both prompt and direct path)
|
|
||||||
const existingNote = this.notes.find(note => note.path === notePath);
|
|
||||||
if (existingNote) {
|
|
||||||
this.toast(this.t('notes.already_exists', { name: notePath }), { type: 'warning' });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const validation = targetFolder
|
||||||
|
? FilenameValidator.validateFilename(rawName)
|
||||||
|
: FilenameValidator.validatePath(rawName);
|
||||||
|
if (!validation.valid) {
|
||||||
|
this.toast(this.getValidationErrorMessage(validation, 'folder'), { type: 'warning' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const validatedName = validation.sanitized;
|
||||||
|
const folderPath = targetFolder ? `${targetFolder}/${validatedName}` : validatedName;
|
||||||
|
const existingFolder = this.allFolders.find(folder => folder === folderPath);
|
||||||
|
if (existingFolder) {
|
||||||
|
this.toast(this.t('folders.already_exists', { name: validatedName }), { type: 'warning' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ok = await this._finalizeCreateFolder(folderPath, targetFolder);
|
||||||
|
if (ok) this.closeCreateNameModal();
|
||||||
|
},
|
||||||
|
|
||||||
|
async _finalizeCreateNote(notePath) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/notes/${notePath}`, {
|
const response = await fetch(`/api/notes/${notePath}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
@ -3401,60 +3487,22 @@ function noteApp() {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
// Expand parent folder if note is in a subfolder
|
|
||||||
const folderPart = notePath.includes('/') ? notePath.substring(0, notePath.lastIndexOf('/')) : '';
|
const folderPart = notePath.includes('/') ? notePath.substring(0, notePath.lastIndexOf('/')) : '';
|
||||||
if (folderPart) this.expandedFolders.add(folderPart);
|
if (folderPart) this.expandedFolders.add(folderPart);
|
||||||
await this.loadNotes();
|
await this.loadNotes();
|
||||||
await this.loadNote(notePath);
|
await this.loadNote(notePath);
|
||||||
this.focusEditorForNewNote();
|
this.focusEditorForNewNote();
|
||||||
} else {
|
return true;
|
||||||
ErrorHandler.handle('create note', new Error('Server returned error'));
|
|
||||||
}
|
}
|
||||||
|
ErrorHandler.handle('create note', new Error('Server returned error'));
|
||||||
|
return false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ErrorHandler.handle('create note', error);
|
ErrorHandler.handle('create note', error);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async createFolder(parentPath = null) {
|
async _finalizeCreateFolder(folderPath, targetFolder) {
|
||||||
// Use provided parent path, or dropdown target folder context, or homepage folder
|
|
||||||
// Note: Check dropdownTargetFolder !== null to distinguish between '' (root) and not set
|
|
||||||
let targetFolder;
|
|
||||||
if (parentPath !== null) {
|
|
||||||
targetFolder = parentPath;
|
|
||||||
} else if (this.dropdownTargetFolder !== null && this.dropdownTargetFolder !== undefined) {
|
|
||||||
targetFolder = this.dropdownTargetFolder; // Can be '' for root or a folder path
|
|
||||||
} else {
|
|
||||||
targetFolder = this.selectedHomepageFolder || '';
|
|
||||||
}
|
|
||||||
this.closeDropdown();
|
|
||||||
|
|
||||||
const promptText = targetFolder
|
|
||||||
? this.t('folders.prompt_name_in_folder', { folder: targetFolder })
|
|
||||||
: this.t('folders.prompt_name_with_path');
|
|
||||||
|
|
||||||
const folderName = prompt(promptText);
|
|
||||||
if (!folderName) return;
|
|
||||||
|
|
||||||
// Validate the name/path (may contain / for paths when no target folder)
|
|
||||||
const validation = targetFolder
|
|
||||||
? FilenameValidator.validateFilename(folderName)
|
|
||||||
: FilenameValidator.validatePath(folderName);
|
|
||||||
|
|
||||||
if (!validation.valid) {
|
|
||||||
this.toast(this.getValidationErrorMessage(validation, 'folder'), { type: 'warning' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const validatedName = validation.sanitized;
|
|
||||||
const folderPath = targetFolder ? `${targetFolder}/${validatedName}` : validatedName;
|
|
||||||
|
|
||||||
// Check if folder already exists
|
|
||||||
const existingFolder = this.allFolders.find(folder => folder === folderPath);
|
|
||||||
if (existingFolder) {
|
|
||||||
this.toast(this.t('folders.already_exists', { name: validatedName }), { type: 'warning' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/folders', {
|
const response = await fetch('/api/folders', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
@ -3468,23 +3516,57 @@ function noteApp() {
|
||||||
}
|
}
|
||||||
this.expandedFolders.add(folderPath);
|
this.expandedFolders.add(folderPath);
|
||||||
await this.loadNotes();
|
await this.loadNotes();
|
||||||
|
|
||||||
// Navigate to the newly created folder on the homepage
|
|
||||||
this.goToHomepageFolder(folderPath);
|
this.goToHomepageFolder(folderPath);
|
||||||
} else {
|
return true;
|
||||||
ErrorHandler.handle('create folder', new Error('Server returned error'));
|
|
||||||
}
|
}
|
||||||
|
ErrorHandler.handle('create folder', new Error('Server returned error'));
|
||||||
|
return false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ErrorHandler.handle('create folder', error);
|
ErrorHandler.handle('create folder', error);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Rename a folder
|
async createFolder(parentPath = null) {
|
||||||
async renameFolder(folderPath, currentName) {
|
const explicitTarget = parentPath !== null && parentPath !== undefined ? parentPath : undefined;
|
||||||
const newName = prompt(this.t('folders.prompt_rename', { name: currentName }), currentName);
|
this.openCreateNameModal('folder', explicitTarget);
|
||||||
if (!newName || newName === currentName) return;
|
},
|
||||||
|
|
||||||
|
renameFolder(folderPath, currentName) {
|
||||||
|
this.renameFolderPath = folderPath;
|
||||||
|
this.renameFolderOldName = currentName;
|
||||||
|
this.renameFolderInput = currentName;
|
||||||
|
this.showRenameFolderModal = true;
|
||||||
|
this.mobileSidebarOpen = false;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const el = document.getElementById('rename-folder-modal-input');
|
||||||
|
if (el) {
|
||||||
|
el.focus();
|
||||||
|
el.select();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
closeRenameFolderModal() {
|
||||||
|
this.showRenameFolderModal = false;
|
||||||
|
this.renameFolderPath = '';
|
||||||
|
this.renameFolderOldName = '';
|
||||||
|
this.renameFolderInput = '';
|
||||||
|
},
|
||||||
|
|
||||||
|
cancelRenameFolderModal() {
|
||||||
|
this.closeRenameFolderModal();
|
||||||
|
},
|
||||||
|
|
||||||
|
async submitRenameFolderModal() {
|
||||||
|
const folderPath = this.renameFolderPath;
|
||||||
|
const currentName = this.renameFolderOldName;
|
||||||
|
const newName = (this.renameFolderInput || '').trim();
|
||||||
|
if (!newName || newName === currentName) {
|
||||||
|
this.closeRenameFolderModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Validate the new name (single segment, no path separators)
|
|
||||||
const validation = FilenameValidator.validateFilename(newName);
|
const validation = FilenameValidator.validateFilename(newName);
|
||||||
if (!validation.valid) {
|
if (!validation.valid) {
|
||||||
this.toast(this.getValidationErrorMessage(validation, 'folder'), { type: 'warning' });
|
this.toast(this.getValidationErrorMessage(validation, 'folder'), { type: 'warning' });
|
||||||
|
|
@ -3492,12 +3574,15 @@ function noteApp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedName = validation.sanitized;
|
const validatedName = validation.sanitized;
|
||||||
|
|
||||||
// Calculate new path
|
|
||||||
const pathParts = folderPath.split('/');
|
const pathParts = folderPath.split('/');
|
||||||
pathParts[pathParts.length - 1] = validatedName;
|
pathParts[pathParts.length - 1] = validatedName;
|
||||||
const newPath = pathParts.join('/');
|
const newPath = pathParts.join('/');
|
||||||
|
|
||||||
|
const ok = await this._finalizeRenameFolder(folderPath, newPath);
|
||||||
|
if (ok) this.closeRenameFolderModal();
|
||||||
|
},
|
||||||
|
|
||||||
|
async _finalizeRenameFolder(folderPath, newPath) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/folders/rename', {
|
const response = await fetch('/api/folders/rename', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
@ -3509,13 +3594,11 @@ function noteApp() {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
// Update expanded folders state
|
|
||||||
if (this.expandedFolders.has(folderPath)) {
|
if (this.expandedFolders.has(folderPath)) {
|
||||||
this.expandedFolders.delete(folderPath);
|
this.expandedFolders.delete(folderPath);
|
||||||
this.expandedFolders.add(newPath);
|
this.expandedFolders.add(newPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update favorites that were in the renamed folder
|
|
||||||
const folderPrefix = folderPath + '/';
|
const folderPrefix = folderPath + '/';
|
||||||
const newFolderPrefix = newPath + '/';
|
const newFolderPrefix = newPath + '/';
|
||||||
const newFavorites = this.favorites.map(f => {
|
const newFavorites = this.favorites.map(f => {
|
||||||
|
|
@ -3524,24 +3607,24 @@ function noteApp() {
|
||||||
}
|
}
|
||||||
return f;
|
return f;
|
||||||
});
|
});
|
||||||
// Check if anything changed
|
|
||||||
if (JSON.stringify(newFavorites) !== JSON.stringify(this.favorites)) {
|
if (JSON.stringify(newFavorites) !== JSON.stringify(this.favorites)) {
|
||||||
this.favorites = newFavorites;
|
this.favorites = newFavorites;
|
||||||
this.favoritesSet = new Set(newFavorites);
|
this.favoritesSet = new Set(newFavorites);
|
||||||
this.saveFavorites();
|
this.saveFavorites();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update current note path if it's in the renamed folder
|
|
||||||
if (this.currentNote && this.currentNote.startsWith(folderPrefix)) {
|
if (this.currentNote && this.currentNote.startsWith(folderPrefix)) {
|
||||||
this.currentNote = this.currentNote.replace(folderPrefix, newFolderPrefix);
|
this.currentNote = this.currentNote.replace(folderPrefix, newFolderPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.loadNotes();
|
await this.loadNotes();
|
||||||
} else {
|
return true;
|
||||||
ErrorHandler.handle('rename folder', new Error('Server returned error'));
|
|
||||||
}
|
}
|
||||||
|
ErrorHandler.handle('rename folder', new Error('Server returned error'));
|
||||||
|
return false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ErrorHandler.handle('rename folder', error);
|
ErrorHandler.handle('rename folder', error);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3204,6 +3204,102 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- New note / folder name (replaces window.prompt) -->
|
||||||
|
<div x-show="showCreateNameModal"
|
||||||
|
@click.self="cancelCreateNameModal()"
|
||||||
|
@keydown.escape.window="showCreateNameModal && cancelCreateNameModal()"
|
||||||
|
class="fixed inset-0 flex items-center justify-center"
|
||||||
|
style="background-color: rgba(0, 0, 0, 0.5); z-index: 1100;"
|
||||||
|
x-cloak>
|
||||||
|
<div class="rounded-lg shadow-xl p-6 max-w-md w-full mx-4"
|
||||||
|
style="background-color: var(--bg-secondary); color: var(--text-primary);"
|
||||||
|
@click.stop>
|
||||||
|
<h2 class="text-xl font-bold mb-2" style="color: var(--text-primary);" x-text="createNameModalTitle()"></h2>
|
||||||
|
<p class="text-sm mb-4 whitespace-pre-line" style="color: var(--text-secondary);" x-text="createNameModalHelpText()"></p>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="create-name-modal-input" class="block text-sm font-medium mb-2" style="color: var(--text-secondary);" x-text="createNameModalLabel()"></label>
|
||||||
|
<input
|
||||||
|
id="create-name-modal-input"
|
||||||
|
type="text"
|
||||||
|
x-model="createNameModalInput"
|
||||||
|
:placeholder="createNameModalKind === 'folder' ? t('folders.prompt_name') : t('notes.prompt_name')"
|
||||||
|
class="w-full px-3 py-2 rounded border"
|
||||||
|
style="background-color: var(--bg-tertiary); color: var(--text-primary); border-color: var(--border-primary);"
|
||||||
|
@keydown.enter="submitCreateNameModal()"
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="submitCreateNameModal()"
|
||||||
|
class="flex-1 px-4 py-2 rounded font-medium text-white transition-colors"
|
||||||
|
style="background-color: var(--accent-primary);"
|
||||||
|
onmouseover="this.style.backgroundColor='var(--accent-hover)'"
|
||||||
|
onmouseout="this.style.backgroundColor='var(--accent-primary)'"
|
||||||
|
x-text="t('common.create')"
|
||||||
|
></button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="cancelCreateNameModal()"
|
||||||
|
class="flex-1 px-4 py-2 rounded font-medium transition-colors"
|
||||||
|
style="background-color: var(--bg-tertiary); color: var(--text-primary);"
|
||||||
|
onmouseover="this.style.backgroundColor='var(--bg-hover)'"
|
||||||
|
onmouseout="this.style.backgroundColor='var(--bg-tertiary)'"
|
||||||
|
x-text="t('common.cancel')"
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Rename folder (replaces window.prompt) -->
|
||||||
|
<div x-show="showRenameFolderModal"
|
||||||
|
@click.self="cancelRenameFolderModal()"
|
||||||
|
@keydown.escape.window="showRenameFolderModal && cancelRenameFolderModal()"
|
||||||
|
class="fixed inset-0 flex items-center justify-center"
|
||||||
|
style="background-color: rgba(0, 0, 0, 0.5); z-index: 1100;"
|
||||||
|
x-cloak>
|
||||||
|
<div class="rounded-lg shadow-xl p-6 max-w-md w-full mx-4"
|
||||||
|
style="background-color: var(--bg-secondary); color: var(--text-primary);"
|
||||||
|
@click.stop>
|
||||||
|
<h2 class="text-xl font-bold mb-2" style="color: var(--text-primary);" x-text="t('folders.rename_modal_title')"></h2>
|
||||||
|
<p class="text-sm mb-4" style="color: var(--text-secondary);" x-text="t('folders.rename_modal_description', { name: renameFolderOldName })"></p>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="rename-folder-modal-input" class="block text-sm font-medium mb-2" style="color: var(--text-secondary);" x-text="t('folders.rename_modal_label')"></label>
|
||||||
|
<input
|
||||||
|
id="rename-folder-modal-input"
|
||||||
|
type="text"
|
||||||
|
x-model="renameFolderInput"
|
||||||
|
:placeholder="renameFolderOldName"
|
||||||
|
class="w-full px-3 py-2 rounded border"
|
||||||
|
style="background-color: var(--bg-tertiary); color: var(--text-primary); border-color: var(--border-primary);"
|
||||||
|
@keydown.enter="submitRenameFolderModal()"
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="submitRenameFolderModal()"
|
||||||
|
class="flex-1 px-4 py-2 rounded font-medium text-white transition-colors"
|
||||||
|
style="background-color: var(--accent-primary);"
|
||||||
|
onmouseover="this.style.backgroundColor='var(--accent-hover)'"
|
||||||
|
onmouseout="this.style.backgroundColor='var(--accent-primary)'"
|
||||||
|
x-text="t('common.rename')"
|
||||||
|
></button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="cancelRenameFolderModal()"
|
||||||
|
class="flex-1 px-4 py-2 rounded font-medium transition-colors"
|
||||||
|
style="background-color: var(--bg-tertiary); color: var(--text-primary);"
|
||||||
|
onmouseover="this.style.backgroundColor='var(--bg-hover)'"
|
||||||
|
onmouseout="this.style.backgroundColor='var(--bg-tertiary)'"
|
||||||
|
x-text="t('common.cancel')"
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Quick Switcher Modal (Ctrl+K) -->
|
<!-- Quick Switcher Modal (Ctrl+K) -->
|
||||||
<div x-show="showQuickSwitcher"
|
<div x-show="showQuickSwitcher"
|
||||||
@click.self="closeQuickSwitcher()"
|
@click.self="closeQuickSwitcher()"
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,9 @@
|
||||||
"prompt_name_in_folder": "Unterordner in \"{{folder}}\" erstellen.\nOrdnername eingeben:",
|
"prompt_name_in_folder": "Unterordner in \"{{folder}}\" erstellen.\nOrdnername eingeben:",
|
||||||
"prompt_name_with_path": "Neuen Ordner erstellen.\nOrdnerpfad eingeben (z.B. \"Projekte\" oder \"Arbeit/2025\"):",
|
"prompt_name_with_path": "Neuen Ordner erstellen.\nOrdnerpfad eingeben (z.B. \"Projekte\" oder \"Arbeit/2025\"):",
|
||||||
"prompt_rename": "Ordner \"{{name}}\" umbenennen zu:",
|
"prompt_rename": "Ordner \"{{name}}\" umbenennen zu:",
|
||||||
|
"rename_modal_title": "Ordner umbenennen",
|
||||||
|
"rename_modal_description": "Neuen Namen für den Ordner „{{name}}“ eingeben.",
|
||||||
|
"rename_modal_label": "Neuer Name",
|
||||||
"invalid_name": "Ungültiger Ordnername.",
|
"invalid_name": "Ungültiger Ordnername.",
|
||||||
"cannot_move_into_self": "Ordner kann nicht in sich selbst oder einen Unterordner verschoben werden.",
|
"cannot_move_into_self": "Ordner kann nicht in sich selbst oder einen Unterordner verschoben werden.",
|
||||||
"empty": "leer"
|
"empty": "leer"
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,9 @@
|
||||||
"prompt_name_in_folder": "Create subfolder in \"{{folder}}\".\nEnter folder name:",
|
"prompt_name_in_folder": "Create subfolder in \"{{folder}}\".\nEnter folder name:",
|
||||||
"prompt_name_with_path": "Create new folder.\nEnter folder path (e.g., \"Projects\" or \"Work/2025\"):",
|
"prompt_name_with_path": "Create new folder.\nEnter folder path (e.g., \"Projects\" or \"Work/2025\"):",
|
||||||
"prompt_rename": "Rename folder \"{{name}}\" to:",
|
"prompt_rename": "Rename folder \"{{name}}\" to:",
|
||||||
|
"rename_modal_title": "Rename folder",
|
||||||
|
"rename_modal_description": "Enter the new name for the folder \"{{name}}\".",
|
||||||
|
"rename_modal_label": "New name",
|
||||||
"invalid_name": "Invalid folder name.",
|
"invalid_name": "Invalid folder name.",
|
||||||
"cannot_move_into_self": "Cannot move folder into itself or its subfolder.",
|
"cannot_move_into_self": "Cannot move folder into itself or its subfolder.",
|
||||||
"empty": "empty"
|
"empty": "empty"
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,9 @@
|
||||||
"prompt_name_in_folder": "Create subfolder in \"{{folder}}\".\nEnter folder name:",
|
"prompt_name_in_folder": "Create subfolder in \"{{folder}}\".\nEnter folder name:",
|
||||||
"prompt_name_with_path": "Create new folder.\nEnter folder path (e.g., \"Projects\" or \"Work/2025\"):",
|
"prompt_name_with_path": "Create new folder.\nEnter folder path (e.g., \"Projects\" or \"Work/2025\"):",
|
||||||
"prompt_rename": "Rename folder \"{{name}}\" to:",
|
"prompt_rename": "Rename folder \"{{name}}\" to:",
|
||||||
|
"rename_modal_title": "Rename folder",
|
||||||
|
"rename_modal_description": "Enter the new name for the folder \"{{name}}\".",
|
||||||
|
"rename_modal_label": "New name",
|
||||||
"invalid_name": "Invalid folder name.",
|
"invalid_name": "Invalid folder name.",
|
||||||
"cannot_move_into_self": "Cannot move folder into itself or its subfolder.",
|
"cannot_move_into_self": "Cannot move folder into itself or its subfolder.",
|
||||||
"empty": "empty"
|
"empty": "empty"
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,9 @@
|
||||||
"prompt_name_in_folder": "Crear subcarpeta en \"{{folder}}\".\nIntroduce el nombre de la carpeta:",
|
"prompt_name_in_folder": "Crear subcarpeta en \"{{folder}}\".\nIntroduce el nombre de la carpeta:",
|
||||||
"prompt_name_with_path": "Crear nueva carpeta.\nIntroduce la ruta de la carpeta (ej., \"Proyectos\" o \"Trabajo/2025\"):",
|
"prompt_name_with_path": "Crear nueva carpeta.\nIntroduce la ruta de la carpeta (ej., \"Proyectos\" o \"Trabajo/2025\"):",
|
||||||
"prompt_rename": "Renombrar carpeta \"{{name}}\" a:",
|
"prompt_rename": "Renombrar carpeta \"{{name}}\" a:",
|
||||||
|
"rename_modal_title": "Renombrar carpeta",
|
||||||
|
"rename_modal_description": "Introduce el nuevo nombre para la carpeta \"{{name}}\".",
|
||||||
|
"rename_modal_label": "Nombre nuevo",
|
||||||
"invalid_name": "Nombre de carpeta inválido.",
|
"invalid_name": "Nombre de carpeta inválido.",
|
||||||
"cannot_move_into_self": "No se puede mover una carpeta dentro de sí misma o de una subcarpeta.",
|
"cannot_move_into_self": "No se puede mover una carpeta dentro de sí misma o de una subcarpeta.",
|
||||||
"empty": "vacía"
|
"empty": "vacía"
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,9 @@
|
||||||
"prompt_name_in_folder": "Créer un sous-dossier dans \"{{folder}}\".\nEntrez le nom du dossier :",
|
"prompt_name_in_folder": "Créer un sous-dossier dans \"{{folder}}\".\nEntrez le nom du dossier :",
|
||||||
"prompt_name_with_path": "Créer un nouveau dossier.\nEntrez le chemin du dossier (ex. \"Projets\" ou \"Travail/2025\") :",
|
"prompt_name_with_path": "Créer un nouveau dossier.\nEntrez le chemin du dossier (ex. \"Projets\" ou \"Travail/2025\") :",
|
||||||
"prompt_rename": "Renommer le dossier \"{{name}}\" en :",
|
"prompt_rename": "Renommer le dossier \"{{name}}\" en :",
|
||||||
|
"rename_modal_title": "Renommer le dossier",
|
||||||
|
"rename_modal_description": "Saisissez le nouveau nom du dossier « {{name}} ».",
|
||||||
|
"rename_modal_label": "Nouveau nom",
|
||||||
"invalid_name": "Nom de dossier invalide.",
|
"invalid_name": "Nom de dossier invalide.",
|
||||||
"cannot_move_into_self": "Impossible de déplacer un dossier dans lui-même ou dans un sous-dossier.",
|
"cannot_move_into_self": "Impossible de déplacer un dossier dans lui-même ou dans un sous-dossier.",
|
||||||
"empty": "vide"
|
"empty": "vide"
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,9 @@
|
||||||
"prompt_name_in_folder": "Almappa létrehozása a \"{{folder}}\" mappában.\nAdd meg a mappa nevét:",
|
"prompt_name_in_folder": "Almappa létrehozása a \"{{folder}}\" mappában.\nAdd meg a mappa nevét:",
|
||||||
"prompt_name_with_path": "Új mappa létrehozása.\nAdd meg a mappa elérési útját (pl. \"Projektek\" vagy \"Munka/2026\"):",
|
"prompt_name_with_path": "Új mappa létrehozása.\nAdd meg a mappa elérési útját (pl. \"Projektek\" vagy \"Munka/2026\"):",
|
||||||
"prompt_rename": "Nevezd át a(z) \"{{name}}\" mappát:",
|
"prompt_rename": "Nevezd át a(z) \"{{name}}\" mappát:",
|
||||||
|
"rename_modal_title": "Mappa átnevezése",
|
||||||
|
"rename_modal_description": "Add meg a(z) „{{name}}” mappa új nevét.",
|
||||||
|
"rename_modal_label": "Új név",
|
||||||
"invalid_name": "Érvénytelen mappanév.",
|
"invalid_name": "Érvénytelen mappanév.",
|
||||||
"cannot_move_into_self": "A mappa nem mozgatható saját magába vagy bármelyik almappájába.",
|
"cannot_move_into_self": "A mappa nem mozgatható saját magába vagy bármelyik almappájába.",
|
||||||
"empty": "üres"
|
"empty": "üres"
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,9 @@
|
||||||
"prompt_name_in_folder": "Crea sottocartella in \"{{folder}}\".\nInserisci nome cartella:",
|
"prompt_name_in_folder": "Crea sottocartella in \"{{folder}}\".\nInserisci nome cartella:",
|
||||||
"prompt_name_with_path": "Crea nuova cartella.\nInserisci percorso cartella (es. \"Progetti\" o \"Lavoro/2025\"):",
|
"prompt_name_with_path": "Crea nuova cartella.\nInserisci percorso cartella (es. \"Progetti\" o \"Lavoro/2025\"):",
|
||||||
"prompt_rename": "Rinomina cartella \"{{name}}\" in:",
|
"prompt_rename": "Rinomina cartella \"{{name}}\" in:",
|
||||||
|
"rename_modal_title": "Rinomina cartella",
|
||||||
|
"rename_modal_description": "Inserisci il nuovo nome per la cartella \"{{name}}\".",
|
||||||
|
"rename_modal_label": "Nuovo nome",
|
||||||
"invalid_name": "Nome cartella non valido.",
|
"invalid_name": "Nome cartella non valido.",
|
||||||
"cannot_move_into_self": "Impossibile spostare la cartella in se stessa o in una sottocartella.",
|
"cannot_move_into_self": "Impossibile spostare la cartella in se stessa o in una sottocartella.",
|
||||||
"empty": "vuota"
|
"empty": "vuota"
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,9 @@
|
||||||
"prompt_name_in_folder": "「{{folder}}」にサブフォルダを作成します。\nフォルダ名を入力:",
|
"prompt_name_in_folder": "「{{folder}}」にサブフォルダを作成します。\nフォルダ名を入力:",
|
||||||
"prompt_name_with_path": "新規フォルダを作成します。\nフォルダパスを入力(例:「プロジェクト」または「仕事/2025」):",
|
"prompt_name_with_path": "新規フォルダを作成します。\nフォルダパスを入力(例:「プロジェクト」または「仕事/2025」):",
|
||||||
"prompt_rename": "フォルダ「{{name}}」の新しい名前:",
|
"prompt_rename": "フォルダ「{{name}}」の新しい名前:",
|
||||||
|
"rename_modal_title": "フォルダの名前を変更",
|
||||||
|
"rename_modal_description": "フォルダ「{{name}}」の新しい名前を入力してください。",
|
||||||
|
"rename_modal_label": "新しい名前",
|
||||||
"invalid_name": "無効なフォルダ名です。",
|
"invalid_name": "無効なフォルダ名です。",
|
||||||
"cannot_move_into_self": "フォルダを自身またはそのサブフォルダに移動できません。",
|
"cannot_move_into_self": "フォルダを自身またはそのサブフォルダに移動できません。",
|
||||||
"empty": "空"
|
"empty": "空"
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,9 @@
|
||||||
"prompt_name_in_folder": "Создать подпапку в «{{folder}}».\nВведите название:",
|
"prompt_name_in_folder": "Создать подпапку в «{{folder}}».\nВведите название:",
|
||||||
"prompt_name_with_path": "Создать новую папку.\nВведите путь (например, «Проекты» или «Работа/2025»):",
|
"prompt_name_with_path": "Создать новую папку.\nВведите путь (например, «Проекты» или «Работа/2025»):",
|
||||||
"prompt_rename": "Переименовать папку «{{name}}» в:",
|
"prompt_rename": "Переименовать папку «{{name}}» в:",
|
||||||
|
"rename_modal_title": "Переименовать папку",
|
||||||
|
"rename_modal_description": "Введите новое имя для папки «{{name}}».",
|
||||||
|
"rename_modal_label": "Новое имя",
|
||||||
"invalid_name": "Недопустимое название папки.",
|
"invalid_name": "Недопустимое название папки.",
|
||||||
"cannot_move_into_self": "Нельзя переместить папку в себя или в подпапку.",
|
"cannot_move_into_self": "Нельзя переместить папку в себя или в подпапку.",
|
||||||
"empty": "пусто"
|
"empty": "пусто"
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,9 @@
|
||||||
"prompt_name_in_folder": "Ustvari podmapo v \"{{folder}}\".\nVnesite ime mape:",
|
"prompt_name_in_folder": "Ustvari podmapo v \"{{folder}}\".\nVnesite ime mape:",
|
||||||
"prompt_name_with_path": "Ustvari novo mapo.\nVnesite pot mape (npr. \"Projekti\" ali \"Delo/2025\"):",
|
"prompt_name_with_path": "Ustvari novo mapo.\nVnesite pot mape (npr. \"Projekti\" ali \"Delo/2025\"):",
|
||||||
"prompt_rename": "Preimenuj mapo \"{{name}}\" v:",
|
"prompt_rename": "Preimenuj mapo \"{{name}}\" v:",
|
||||||
|
"rename_modal_title": "Preimenuj mapo",
|
||||||
|
"rename_modal_description": "Vnesite novo ime za mapo \"{{name}}\".",
|
||||||
|
"rename_modal_label": "Novo ime",
|
||||||
"invalid_name": "Neveljavno ime mape.",
|
"invalid_name": "Neveljavno ime mape.",
|
||||||
"cannot_move_into_self": "Mape ni mogoče premakniti vase ali v njeno podmapo.",
|
"cannot_move_into_self": "Mape ni mogoče premakniti vase ali v njeno podmapo.",
|
||||||
"empty": "prazno"
|
"empty": "prazno"
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,9 @@
|
||||||
"prompt_name_in_folder": "在 \"{{folder}}\" 中创建子文件夹。\n输入文件夹名称:",
|
"prompt_name_in_folder": "在 \"{{folder}}\" 中创建子文件夹。\n输入文件夹名称:",
|
||||||
"prompt_name_with_path": "创建新文件夹。\n输入文件夹路径(例如 \"Projects\" 或 \"Work/2025\"):",
|
"prompt_name_with_path": "创建新文件夹。\n输入文件夹路径(例如 \"Projects\" 或 \"Work/2025\"):",
|
||||||
"prompt_rename": "将文件夹 \"{{name}}\" 重命名为:",
|
"prompt_rename": "将文件夹 \"{{name}}\" 重命名为:",
|
||||||
|
"rename_modal_title": "重命名文件夹",
|
||||||
|
"rename_modal_description": "为文件夹 \"{{name}}\" 输入新名称。",
|
||||||
|
"rename_modal_label": "新名称",
|
||||||
"invalid_name": "无效的文件夹名称。",
|
"invalid_name": "无效的文件夹名称。",
|
||||||
"cannot_move_into_self": "无法将文件夹移动到其自身或其子文件夹中。",
|
"cannot_move_into_self": "无法将文件夹移动到其自身或其子文件夹中。",
|
||||||
"empty": "空"
|
"empty": "空"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue