diff options
| author | zwlucas <lucas.fariamo08@gmail.com> | 2026-06-05 20:52:54 +0000 |
|---|---|---|
| committer | zwlucas <lucas.fariamo08@gmail.com> | 2026-06-05 20:52:54 +0000 |
| commit | 09f964451d7d92e9891430ec4595c1276d486aab (patch) | |
| tree | 28da4483f5c28924a8c47fceb648b1baebe88224 /src/components/StatusBar | |
| download | yace-09f964451d7d92e9891430ec4595c1276d486aab.tar.gz yace-09f964451d7d92e9891430ec4595c1276d486aab.zip | |
Signed-off-by: zwlucas <lucas.fariamo08@gmail.com>
Diffstat (limited to 'src/components/StatusBar')
| -rw-r--r-- | src/components/StatusBar/StatusBar.tsx | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/src/components/StatusBar/StatusBar.tsx b/src/components/StatusBar/StatusBar.tsx new file mode 100644 index 0000000..49f9346 --- /dev/null +++ b/src/components/StatusBar/StatusBar.tsx @@ -0,0 +1,163 @@ +import { useEffect, useRef } from 'react' +import { useTabsStore } from '@/stores/useTabsStore' +import { useSettingsStore } from '@/stores/useSettingsStore' + +function BranchIcon() { + return ( + <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="shrink-0 opacity-60"> + <line x1="6" y1="3" x2="6" y2="15" /> + <circle cx="18" cy="6" r="3" /> + <circle cx="6" cy="18" r="3" /> + <path d="M18 9a9 9 0 0 1-9 9" /> + </svg> + ) +} + +function ErrorIcon() { + return ( + <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" className="shrink-0"> + <circle cx="12" cy="12" r="10" /> + <line x1="12" y1="8" x2="12" y2="12" /> + <line x1="12" y1="16" x2="12.01" y2="16" /> + </svg> + ) +} + +function EncodingIcon() { + return ( + <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="shrink-0 opacity-60"> + <polyline points="16 18 22 12 16 6" /> + <polyline points="8 6 2 12 8 18" /> + </svg> + ) +} + +function Spinner() { + return ( + <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" className="shrink-0 animate-spin"> + <path d="M21 12a9 9 0 1 1-6.219-8.56" /> + </svg> + ) +} + +function Separator() { + return ( + <div className="w-px h-3 mx-2 shrink-0" style={{ backgroundColor: 'var(--color-panel-border)' }} /> + ) +} + +function StatusItem({ + children, + title, + onClick, +}: { + children: React.ReactNode + title?: string + onClick?: () => void +}) { + return ( + <button + className={`flex items-center gap-1 px-1.5 h-full text-[11px] font-medium transition-colors duration-fast ${onClick ? 'cursor-pointer' : 'cursor-default'} hover:text-text-primary`} + style={{ color: 'var(--color-text-muted)' }} + title={title} + onClick={onClick} + > + {children} + </button> + ) +} + +export default function StatusBar() { + const activeTab = useTabsStore((s) => + s.activeTabId ? s.tabs.find((t) => t.id === s.activeTabId) ?? null : null + ) + const cursorLine = useTabsStore((s) => s.cursorLine) + const cursorCol = useTabsStore((s) => s.cursorCol) + const savingId = useTabsStore((s) => s.savingId) + const statusMessage = useTabsStore((s) => s.statusMessage) + const clearStatusMessage = useTabsStore((s) => s.clearStatusMessage) + const tabSize = useSettingsStore((s) => s.tabSize) + + const isSaving = savingId === activeTab?.id + const statusTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined) + + useEffect(() => { + if (statusMessage) { + if (statusTimer.current) clearTimeout(statusTimer.current) + statusTimer.current = setTimeout(clearStatusMessage, 2000) + } + return () => { if (statusTimer.current) clearTimeout(statusTimer.current) } + }, [statusMessage, clearStatusMessage]) + + return ( + <div className="flex items-center h-status shrink-0 select-none bg-activity-bg text-[11px] text-text-muted font-medium" role="status" aria-label="Application status"> + <div className="flex items-center h-full"> + <StatusItem title="Git branch: main"> + <BranchIcon /> + <span>main</span> + </StatusItem> + + <Separator /> + + <StatusItem title="0 errors, 0 warnings"> + <ErrorIcon /> + <span className="font-mono tabular-nums text-semantic-error">0</span> + <span className="font-mono tabular-nums text-semantic-warning">0</span> + </StatusItem> + </div> + + <div className="flex-1" /> + + <div className="flex items-center h-full"> + {isSaving && ( + <StatusItem title="Saving..."> + <Spinner /> + <span className="text-accent">Saving</span> + </StatusItem> + )} + + {statusMessage && !isSaving && ( + <StatusItem title={statusMessage}> + <span className={statusMessage === 'Saved' ? 'text-semantic-success' : 'text-semantic-error'}> + {statusMessage === 'Saved' ? '✓' : '✗'} + </span> + <span className={statusMessage === 'Saved' ? 'text-semantic-success' : 'text-semantic-error'}> + {statusMessage} + </span> + </StatusItem> + )} + + {activeTab && ( + <StatusItem title={`Language: ${activeTab.language}`}> + <span className="text-text-secondary"> + {activeTab.language.charAt(0).toUpperCase() + activeTab.language.slice(1)} + </span> + </StatusItem> + )} + + <Separator /> + + <StatusItem title={`Tab Size: ${tabSize}`}> + <span>Spaces: {tabSize}</span> + </StatusItem> + + <Separator /> + + <StatusItem title="Encoding: UTF-8"> + <EncodingIcon /> + <span>UTF-8</span> + </StatusItem> + + <Separator /> + + {activeTab && ( + <StatusItem title={`Line ${cursorLine}, Column ${cursorCol}`}> + <span className="font-mono tabular-nums text-text-secondary"> + Ln {cursorLine}, Col {cursorCol} + </span> + </StatusItem> + )} + </div> + </div> + ) +} |