toolbar family keyed (57 -> 33)
Toolbar, ActionButtons, SelectionActions and DefaultActions. Almost every string here reused an existing files.menu.* key from the last two commits rather than adding a duplicate — cut/copy/paste/download/delete/newFolder/uploadFiles/ uploadFolder/hideHiddenFiles were all already there. Three new: gitClone, searchFiles, clearSelection, refresh, selected. The clone-URL placeholder here is the same hint as NewEntryDialog's, reused rather than restated with different example names (user/repo vs owner/repo) — one key per meaning, not per occurrence. The "N selected" count splits the number and the word across two spans (the word hidden on mobile); only the word needed a key, so files.menu.selected is standalone prose rather than an interpolated frame.
This commit is contained in:
+3
-1
@@ -1,5 +1,6 @@
|
||||
import { RefreshCw } from 'lucide-react';
|
||||
import type { UseFileBrowserAppType } from '../../useFileBrowserApp';
|
||||
import { useTranslation } from '../../../../../locales';
|
||||
import { SelectionActions } from './SelectionActions';
|
||||
import { DefaultActions } from './DefaultActions';
|
||||
|
||||
@@ -8,13 +9,14 @@ type ActionButtonsProps = {
|
||||
};
|
||||
|
||||
export const ActionButtons = ({ fileBrowserManager }: ActionButtonsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { refresh, selected } = fileBrowserManager;
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
<button
|
||||
onClick={refresh}
|
||||
title="Refresh"
|
||||
title={t('files.menu.refresh')}
|
||||
className="p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors"
|
||||
>
|
||||
<RefreshCw className="h-4 w-4" />
|
||||
|
||||
+6
-4
@@ -1,12 +1,14 @@
|
||||
import { useRef } from 'react';
|
||||
import { FolderPlus, Upload, FolderUp, ClipboardPaste } from 'lucide-react';
|
||||
import type { UseFileBrowserAppType } from '../../useFileBrowserApp';
|
||||
import { useTranslation } from '../../../../../locales';
|
||||
|
||||
type DefaultActionsProps = {
|
||||
fileBrowserManager: UseFileBrowserAppType;
|
||||
};
|
||||
|
||||
export const DefaultActions = ({ fileBrowserManager }: DefaultActionsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { setNewEntry, handleUpload, clipboard, handlePaste } = fileBrowserManager;
|
||||
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
||||
const folderInputRef = useRef<HTMLInputElement | null>(null);
|
||||
@@ -22,7 +24,7 @@ export const DefaultActions = ({ fileBrowserManager }: DefaultActionsProps) => {
|
||||
<>
|
||||
<button
|
||||
onClick={() => setNewEntry('folder')}
|
||||
title="New folder"
|
||||
title={t('files.menu.newFolder')}
|
||||
className="p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors"
|
||||
>
|
||||
<FolderPlus className="h-4 w-4" />
|
||||
@@ -30,7 +32,7 @@ export const DefaultActions = ({ fileBrowserManager }: DefaultActionsProps) => {
|
||||
|
||||
<button
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
title="Upload files"
|
||||
title={t('files.menu.uploadFiles')}
|
||||
className="p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors"
|
||||
>
|
||||
<Upload className="h-4 w-4" />
|
||||
@@ -39,7 +41,7 @@ export const DefaultActions = ({ fileBrowserManager }: DefaultActionsProps) => {
|
||||
|
||||
<button
|
||||
onClick={() => folderInputRef.current?.click()}
|
||||
title="Upload folder"
|
||||
title={t('files.menu.uploadFolder')}
|
||||
className="p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors"
|
||||
>
|
||||
<FolderUp className="h-4 w-4" />
|
||||
@@ -57,7 +59,7 @@ export const DefaultActions = ({ fileBrowserManager }: DefaultActionsProps) => {
|
||||
{clipboard !== null && (
|
||||
<button
|
||||
onClick={handlePaste}
|
||||
title="Paste"
|
||||
title={t('files.menu.paste')}
|
||||
className="p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors"
|
||||
>
|
||||
<ClipboardPaste className="h-4 w-4" />
|
||||
|
||||
+9
-7
@@ -1,11 +1,13 @@
|
||||
import { Scissors, Copy, ClipboardPaste, Download, Trash2, X } from 'lucide-react';
|
||||
import type { UseFileBrowserAppType } from '../../useFileBrowserApp';
|
||||
import { useTranslation } from '../../../../../locales';
|
||||
|
||||
type SelectionActionsProps = {
|
||||
fileBrowserManager: UseFileBrowserAppType;
|
||||
};
|
||||
|
||||
export const SelectionActions = ({ fileBrowserManager }: SelectionActionsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
selected,
|
||||
clipboard,
|
||||
@@ -21,18 +23,18 @@ export const SelectionActions = ({ fileBrowserManager }: SelectionActionsProps)
|
||||
<>
|
||||
<span className="text-sm font-medium text-duck-dark/70 mr-1">
|
||||
{selected.size}
|
||||
<span className="hidden md:inline"> selected</span>
|
||||
<span className="hidden md:inline"> {t('files.menu.selected')}</span>
|
||||
</span>
|
||||
<button
|
||||
onClick={handleCut}
|
||||
title="Cut"
|
||||
title={t('files.menu.cut')}
|
||||
className="p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors"
|
||||
>
|
||||
<Scissors className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={handleCopy}
|
||||
title="Copy"
|
||||
title={t('files.menu.copy')}
|
||||
className="p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors"
|
||||
>
|
||||
<Copy className="h-4 w-4" />
|
||||
@@ -40,7 +42,7 @@ export const SelectionActions = ({ fileBrowserManager }: SelectionActionsProps)
|
||||
{clipboard !== null && (
|
||||
<button
|
||||
onClick={handlePaste}
|
||||
title="Paste"
|
||||
title={t('files.menu.paste')}
|
||||
className="p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors"
|
||||
>
|
||||
<ClipboardPaste className="h-4 w-4" />
|
||||
@@ -48,21 +50,21 @@ export const SelectionActions = ({ fileBrowserManager }: SelectionActionsProps)
|
||||
)}
|
||||
<button
|
||||
onClick={handleDownloadSelected}
|
||||
title="Download"
|
||||
title={t('files.menu.download')}
|
||||
className="p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors"
|
||||
>
|
||||
<Download className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={handleDeleteSelected}
|
||||
title="Delete"
|
||||
title={t('files.menu.delete')}
|
||||
className="p-1.5 rounded-md text-destructive hover:bg-destructive cursor-pointer transition-colors"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setSelected(new Set())}
|
||||
title="Clear selection"
|
||||
title={t('files.menu.clearSelection')}
|
||||
className="p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
|
||||
+10
-8
@@ -1,5 +1,6 @@
|
||||
import { Loader2, LayoutGrid, List, Search, X, Check, GitBranch, Eye, EyeOff, Download, Mic } from 'lucide-react';
|
||||
import type { UseFileBrowserAppType } from '../../useFileBrowserApp';
|
||||
import { useTranslation } from '../../../../../locales';
|
||||
import { ActionButtons } from './ActionButtons';
|
||||
|
||||
type ToolbarProps = {
|
||||
@@ -7,6 +8,7 @@ type ToolbarProps = {
|
||||
};
|
||||
|
||||
export const Toolbar = ({ fileBrowserManager }: ToolbarProps) => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
showCloneInput,
|
||||
setShowCloneInput,
|
||||
@@ -41,7 +43,7 @@ export const Toolbar = ({ fileBrowserManager }: ToolbarProps) => {
|
||||
autoFocus
|
||||
value={cloneUrl}
|
||||
onChange={(ev) => setCloneUrl(ev.target.value)}
|
||||
placeholder="https://github.com/user/repo.git"
|
||||
placeholder={t('newEntry.clone.placeholder')}
|
||||
className="h-8 w-40 md:w-64 text-sm rounded-md border border-duck-dark/20 bg-background/60 text-duck-dark placeholder:text-duck-dark/40 outline-none focus:border-duck-teal/50 px-2"
|
||||
disabled={cloning}
|
||||
onKeyDown={(ev) => {
|
||||
@@ -55,7 +57,7 @@ export const Toolbar = ({ fileBrowserManager }: ToolbarProps) => {
|
||||
type="submit"
|
||||
disabled={cloning}
|
||||
className="p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors disabled:opacity-40"
|
||||
title="Clone"
|
||||
title={t('files.menu.cloneRepository')}
|
||||
>
|
||||
{cloning ? <Loader2 className="h-4 w-4 animate-spin" /> : <Check className="h-4 w-4" />}
|
||||
</button>
|
||||
@@ -67,7 +69,7 @@ export const Toolbar = ({ fileBrowserManager }: ToolbarProps) => {
|
||||
setCloneUrl('');
|
||||
}}
|
||||
className="p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors disabled:opacity-40"
|
||||
title="Cancel"
|
||||
title={t('newEntry.cancel')}
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
@@ -76,21 +78,21 @@ export const Toolbar = ({ fileBrowserManager }: ToolbarProps) => {
|
||||
<>
|
||||
<button
|
||||
onClick={() => setShowVideoDownload(true)}
|
||||
title="Download video"
|
||||
title={t('files.menu.downloadVideo')}
|
||||
className="hidden md:block p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors"
|
||||
>
|
||||
<Download className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowDictate(true)}
|
||||
title="Dictate"
|
||||
title={t('files.menu.dictate')}
|
||||
className="hidden md:block p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors"
|
||||
>
|
||||
<Mic className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowCloneInput(true)}
|
||||
title="Git clone"
|
||||
title={t('files.menu.gitClone')}
|
||||
className="hidden md:block p-1.5 rounded-md text-duck-teal hover:bg-duck-dark/5 cursor-pointer transition-colors"
|
||||
>
|
||||
<GitBranch className="h-4 w-4" />
|
||||
@@ -109,7 +111,7 @@ export const Toolbar = ({ fileBrowserManager }: ToolbarProps) => {
|
||||
searchInputRef.current?.blur();
|
||||
}
|
||||
}}
|
||||
placeholder="Search files..."
|
||||
placeholder={t('files.menu.searchFiles')}
|
||||
className="h-8 w-28 focus:w-40 md:w-40 md:focus:w-56 transition-all pl-8 pr-7 text-base md:text-sm rounded-md border border-duck-dark/20 bg-background/60 text-duck-dark placeholder:text-duck-dark/40 outline-none focus:border-duck-teal/50"
|
||||
/>
|
||||
{searchQuery && (
|
||||
@@ -124,7 +126,7 @@ export const Toolbar = ({ fileBrowserManager }: ToolbarProps) => {
|
||||
<button
|
||||
onClick={() => setShowHidden((v) => !v)}
|
||||
className={`hidden md:block p-1.5 rounded-md cursor-pointer transition-colors ${showHidden ? 'bg-duck-teal text-duck-yellow' : 'text-duck-teal hover:bg-duck-dark/5'}`}
|
||||
title={showHidden ? 'Hide hidden files' : 'Show hidden files'}
|
||||
title={showHidden ? t('files.menu.hideHiddenFiles') : t('files.menu.showHiddenFiles')}
|
||||
>
|
||||
{showHidden ? <Eye className="h-4 w-4" /> : <EyeOff className="h-4 w-4" />}
|
||||
</button>
|
||||
|
||||
@@ -521,7 +521,12 @@
|
||||
"unpin": "Unpin",
|
||||
"pin": "Pin",
|
||||
"chat": "Chat...",
|
||||
"delete": "Delete"
|
||||
"delete": "Delete",
|
||||
"gitClone": "Git clone",
|
||||
"searchFiles": "Search files...",
|
||||
"clearSelection": "Clear selection",
|
||||
"selected": "selected",
|
||||
"refresh": "Refresh"
|
||||
}
|
||||
},
|
||||
"taskRunner": {
|
||||
|
||||
@@ -521,7 +521,12 @@
|
||||
"unpin": "Remover fixação",
|
||||
"pin": "Fixar",
|
||||
"chat": "Chat...",
|
||||
"delete": "Eliminar"
|
||||
"delete": "Eliminar",
|
||||
"gitClone": "Clonar via Git",
|
||||
"searchFiles": "Pesquisar ficheiros...",
|
||||
"clearSelection": "Limpar seleção",
|
||||
"selected": "selecionados",
|
||||
"refresh": "Atualizar"
|
||||
}
|
||||
},
|
||||
"taskRunner": {
|
||||
|
||||
Reference in New Issue
Block a user