Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions apps/desktop/src/api/builtin.l10n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ export function registerBuiltinTranslations() {
'ai.disclaimer': 'Trixty AI can make mistakes. Check important info.',
'ai.chat_log_label': 'AI chat transcript',

'activitybar.label': 'Primary sidebar navigation',
'tabbar.label': 'Open editor tabs',
'tab.close_aria': 'Close {file}',

'terminal.error_connect': 'Error connecting to terminal: ',
'editor.empty_desc': 'Select a file from the explorer to begin',
'editor.view_not_found': 'View not found',
Expand Down Expand Up @@ -648,6 +652,10 @@ export function registerBuiltinTranslations() {
'ai.disclaimer': 'Trixty AI puede cometer errores. Verifica info importante.',
'ai.chat_log_label': 'Transcripción del chat de IA',

'activitybar.label': 'Navegación principal del panel lateral',
'tabbar.label': 'Pestañas de editores abiertos',
'tab.close_aria': 'Cerrar {file}',

'terminal.error_connect': 'Error al conectar con la terminal: ',
'editor.empty_desc': 'Selecciona un archivo del explorador para comenzar',
'editor.view_not_found': 'Vista no encontrada',
Expand Down
32 changes: 24 additions & 8 deletions apps/desktop/src/components/ActivityBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,47 +43,63 @@ const ActivityBar: React.FC = () => {
};

return (
<div className="w-[48px] bg-[#0a0a0a] border-r border-[#1a1a1a] flex flex-col items-center py-2 gap-1 shrink-0">
<div
role="tablist"
aria-orientation="vertical"
aria-label={t('activitybar.label')}
className="w-[48px] bg-[#0a0a0a] border-r border-[#1a1a1a] flex flex-col items-center py-2 gap-1 shrink-0"
>


{plugins.map((item) => {
const isActive = activeSidebarTab === item.id && isSidebarOpen;
return (
<button
key={item.id}
role="tab"
aria-selected={isActive}
aria-label={t(item.title)}
onClick={() => handleTabClick(item.id)}
className={`w-[40px] h-[40px] flex items-center justify-center rounded-lg transition-all relative group ${isActive ? "text-white bg-white/10" : "text-[#555] hover:text-white/80 hover:bg-white/5"
className={`w-[40px] h-[40px] flex items-center justify-center rounded-lg transition-all relative group focus:outline-none focus-visible:ring-2 focus-visible:ring-white/40 ${isActive ? "text-white bg-white/10" : "text-[#555] hover:text-white/80 hover:bg-white/5"
}`}
title={t(item.title)}
>
{item.icon}
{isActive && (
<div className="absolute left-0 top-[8px] bottom-[8px] w-[2px] bg-white rounded-r-full" />
<div aria-hidden="true" className="absolute left-0 top-[8px] bottom-[8px] w-[2px] bg-white rounded-r-full" />
)}
<div className="absolute left-full ml-3 px-2.5 py-1.5 bg-[#1a1a1a] text-white text-[11px] rounded-md border border-[#2a2a2a] opacity-0 group-hover:opacity-100 pointer-events-none whitespace-nowrap z-50 transition-opacity shadow-xl">
<div aria-hidden="true" className="absolute left-full ml-3 px-2.5 py-1.5 bg-[#1a1a1a] text-white text-[11px] rounded-md border border-[#2a2a2a] opacity-0 group-hover:opacity-100 pointer-events-none whitespace-nowrap z-50 transition-opacity shadow-xl">
{t(item.title)}
</div>
</button>
);
})}
<div className="mt-auto flex flex-col gap-1 items-center">
<button
role="tab"
aria-selected={false}
aria-label={t('extensions.title')}
onClick={() => handleTabClick("extensions")}
className="w-[40px] h-[40px] flex mb-1 items-center justify-center rounded-lg text-[#555] hover:text-white/80 hover:bg-white/5 transition-all group relative"
className="w-[40px] h-[40px] flex mb-1 items-center justify-center rounded-lg text-[#555] hover:text-white/80 hover:bg-white/5 transition-all group relative focus:outline-none focus-visible:ring-2 focus-visible:ring-white/40"
title={t('extensions.title')}
>
<Package size={18} strokeWidth={1.5} />
<div className="absolute left-full ml-3 px-2.5 py-1.5 bg-[#1a1a1a] text-white text-[11px] rounded-md border border-[#2a2a2a] opacity-0 group-hover:opacity-100 pointer-events-none whitespace-nowrap z-50 transition-opacity shadow-xl">
<div aria-hidden="true" className="absolute left-full ml-3 px-2.5 py-1.5 bg-[#1a1a1a] text-white text-[11px] rounded-md border border-[#2a2a2a] opacity-0 group-hover:opacity-100 pointer-events-none whitespace-nowrap z-50 transition-opacity shadow-xl">
{t('extensions.title')}
</div>
</button>

<button
role="tab"
aria-selected={activeSidebarTab === "settings"}
aria-label={t('settings.title')}
onClick={() => handleTabClick("settings")}
className={`w-[40px] h-[40px] flex items-center justify-center rounded-lg transition-all group relative ${activeSidebarTab === "settings" ? "text-white bg-white/10" : "text-[#555] hover:text-white/80 hover:bg-white/5"
className={`w-[40px] h-[40px] flex items-center justify-center rounded-lg transition-all group relative focus:outline-none focus-visible:ring-2 focus-visible:ring-white/40 ${activeSidebarTab === "settings" ? "text-white bg-white/10" : "text-[#555] hover:text-white/80 hover:bg-white/5"
}`}
title={t('settings.title')}
>
<Settings size={18} strokeWidth={1.5} />
<div className="absolute left-full ml-3 px-2.5 py-1.5 bg-[#1a1a1a] text-white text-[11px] rounded-md border border-[#2a2a2a] opacity-0 group-hover:opacity-100 pointer-events-none whitespace-nowrap z-50 transition-opacity shadow-xl">
<div aria-hidden="true" className="absolute left-full ml-3 px-2.5 py-1.5 bg-[#1a1a1a] text-white text-[11px] rounded-md border border-[#2a2a2a] opacity-0 group-hover:opacity-100 pointer-events-none whitespace-nowrap z-50 transition-opacity shadow-xl">
{t('settings.title')}
</div>
</button>
Expand Down
3 changes: 2 additions & 1 deletion apps/desktop/src/components/BottomPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ const BottomPanel: React.FC = () => {
<div className="flex items-center gap-1 text-[#555]">
<button
onClick={() => setBottomPanelOpen(false)}
className="hover:text-white p-1 rounded hover:bg-white/5 transition-colors"
aria-label={t('panel.bottom.close', { defaultValue: 'Close bottom panel' })}
className="hover:text-white p-1 rounded hover:bg-white/5 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-white/40"
>
<X size={16} strokeWidth={1.5} />
</button>
Expand Down
35 changes: 25 additions & 10 deletions apps/desktop/src/components/TabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,36 +72,51 @@ const TabBar: React.FC = () => {
if (openFiles.length === 0) return null;

return (
<div className="flex bg-[#0f0f0f] h-[36px] overflow-x-auto scrollbar-none border-b border-[#1a1a1a] shrink-0">
<div
role="tablist"
aria-label={t('tabbar.label')}
className="flex bg-[#0f0f0f] h-[36px] overflow-x-auto scrollbar-none border-b border-[#1a1a1a] shrink-0"
>
{openFiles.map((file) => {
const isActive = currentFile?.path === file.path;
return (
<div
key={file.path}
role="tab"
aria-selected={isActive}
aria-label={file.isModified ? `${file.name} (${t('tab.modified', { defaultValue: 'unsaved' })})` : file.name}
tabIndex={0}
onClick={() => setCurrentFile(file)}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
setCurrentFile(file);
}
}}
onContextMenu={(e) => handleContextMenu(e, file.path)}
className={`relative flex items-center gap-2 px-3 min-w-[100px] max-w-[180px] h-full cursor-pointer transition-all border-r border-[#1a1a1a] group ${
className={`relative flex items-center gap-2 px-3 min-w-[100px] max-w-[180px] h-full cursor-pointer transition-all border-r border-[#1a1a1a] group focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-white/40 ${
isActive
? "bg-[#141414] text-white"
? "bg-[#141414] text-white"
: "text-[#666] hover:text-[#999] hover:bg-[#111]"
}`}
>
{isActive && <div className="absolute top-0 left-0 right-0 h-[1px] bg-white/40" />}
<div className="shrink-0">{getFileIcon(file)}</div>
{isActive && <div aria-hidden="true" className="absolute top-0 left-0 right-0 h-[1px] bg-white/40" />}

<div aria-hidden="true" className="shrink-0">{getFileIcon(file)}</div>

<span className="text-[11px] truncate flex-1">
{file.name}
</span>

{file.isModified && (
<div className="w-[6px] h-[6px] rounded-full bg-white/40 shrink-0" />
<div aria-hidden="true" className="w-[6px] h-[6px] rounded-full bg-white/40 shrink-0" />
)}

<button
onClick={(e) => { e.stopPropagation(); closeFile(file.path); }}
className={`p-0.5 rounded hover:bg-white/10 transition-opacity shrink-0 ${
isActive ? "opacity-60 hover:opacity-100" : "opacity-0 group-hover:opacity-60 hover:!opacity-100"
aria-label={t('tab.close_aria', { file: file.name })}
className={`p-0.5 rounded hover:bg-white/10 transition-opacity shrink-0 focus:outline-none focus-visible:ring-2 focus-visible:ring-white/40 ${
isActive ? "opacity-60 hover:opacity-100" : "opacity-0 group-hover:opacity-60 hover:!opacity-100 focus-visible:opacity-100"
}`}
>
<X size={12} />
Expand Down
15 changes: 10 additions & 5 deletions apps/desktop/src/components/TitleBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ const TitleBar: React.FC = () => {
{/* Right Panel Toggle */}
<button
onClick={() => setRightPanelOpen(!isRightPanelOpen)}
className={`h-full w-[46px] flex items-center justify-center transition-colors ${
aria-label={t('panel.right.toggle')}
aria-pressed={isRightPanelOpen}
className={`h-full w-[46px] flex items-center justify-center transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-white/40 ${
isRightPanelOpen
? "text-white bg-white/10"
: "text-[#777] hover:bg-white/10 hover:text-white"
Expand All @@ -63,18 +65,20 @@ const TitleBar: React.FC = () => {
<PanelRight size={14} strokeWidth={1.5} />
</button>

<div className="w-[1px] h-[14px] bg-[#222]" />
<div aria-hidden="true" className="w-[1px] h-[14px] bg-[#222]" />
<button
onClick={minimize}
className="h-full w-[46px] flex items-center justify-center text-[#777] hover:bg-white/10 hover:text-white transition-colors"
aria-label={t('window.minimize')}
className="h-full w-[46px] flex items-center justify-center text-[#777] hover:bg-white/10 hover:text-white transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-white/40"
title={t('window.minimize')}
>
<Minus size={14} strokeWidth={1.5} />
</button>

<button
onClick={toggleMaximize}
className="h-full w-[46px] flex items-center justify-center text-[#777] hover:bg-white/10 hover:text-white transition-colors"
aria-label={isMaximized ? t('window.restore') : t('window.maximize')}
className="h-full w-[46px] flex items-center justify-center text-[#777] hover:bg-white/10 hover:text-white transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-white/40"
title={isMaximized ? t('window.restore') : t('window.maximize')}
>
{isMaximized ? (
Expand All @@ -86,7 +90,8 @@ const TitleBar: React.FC = () => {

<button
onClick={close}
className="h-full w-[46px] flex items-center justify-center text-[#777] hover:bg-[#e81123] hover:text-white transition-colors"
aria-label={t('window.close')}
className="h-full w-[46px] flex items-center justify-center text-[#777] hover:bg-[#e81123] hover:text-white transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-white/40"
title={t('window.close')}
>
<X size={14} strokeWidth={1.5} />
Expand Down
Loading