From 09f964451d7d92e9891430ec4595c1276d486aab Mon Sep 17 00:00:00 2001
From: zwlucas <lucas.fariamo08@gmail.com>
Date: Fri, 5 Jun 2026 17:52:54 -0300
Subject: feat: upload

Signed-off-by: zwlucas <lucas.fariamo08@gmail.com>
---
 src/components/SidePanel/SidePanel.tsx | 187 +++++++++++++++++++++++++++++++++
 1 file changed, 187 insertions(+)
 create mode 100644 src/components/SidePanel/SidePanel.tsx

(limited to 'src/components/SidePanel/SidePanel.tsx')

diff --git a/src/components/SidePanel/SidePanel.tsx b/src/components/SidePanel/SidePanel.tsx
new file mode 100644
index 0000000..14668fb
--- /dev/null
+++ b/src/components/SidePanel/SidePanel.tsx
@@ -0,0 +1,187 @@
+import { useRef, useCallback, useEffect } from 'react'
+import FileTree from '@/components/Sidebar/FileTree'
+import SettingsPanel from '@/components/Settings/SettingsPanel'
+import { useFilesStore } from '@/stores/useFilesStore'
+import { useTabsStore } from '@/stores/useTabsStore'
+import { useLayoutStore } from '@/stores/useLayoutStore'
+
+function NewFileIcon() {
+  return (
+    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
+      <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
+      <polyline points="14 2 14 8 20 8" />
+      <line x1="12" y1="18" x2="12" y2="12" />
+      <line x1="9" y1="15" x2="15" y2="15" />
+    </svg>
+  )
+}
+
+function NewFolderIcon() {
+  return (
+    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
+      <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" />
+      <line x1="12" y1="11" x2="12" y2="17" />
+      <line x1="9" y1="14" x2="15" y2="14" />
+    </svg>
+  )
+}
+
+function OpenFolderIcon() {
+  return (
+    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
+      <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" />
+    </svg>
+  )
+}
+
+export default function SidePanel() {
+  const fileTree = useFilesStore((s) => s.fileTree)
+  const rootPath = useFilesStore((s) => s.rootPath)
+  const loading = useFilesStore((s) => s.loading)
+  const openFolder = useFilesStore((s) => s.openFolder)
+  const createFolder = useFilesStore((s) => s.createFolder)
+  const createUntitledFile = useTabsStore((s) => s.createUntitledFile)
+
+  const sidePanelWidth = useLayoutStore((s) => s.sidePanelWidth)
+  const setSidePanelWidth = useLayoutStore((s) => s.setSidePanelWidth)
+  const activeView = useLayoutStore((s) => s.activeView)
+
+  const dragRef = useRef(false)
+  const panelRef = useRef<HTMLDivElement>(null)
+
+  const handleMouseDown = useCallback(() => {
+    dragRef.current = true
+    document.body.style.cursor = 'col-resize'
+    document.body.style.userSelect = 'none'
+  }, [])
+
+  const handleMouseMove = useCallback((e: MouseEvent) => {
+    if (!dragRef.current || !panelRef.current) return
+    const rect = panelRef.current.getBoundingClientRect()
+    const newWidth = e.clientX - rect.left
+    setSidePanelWidth(newWidth)
+  }, [setSidePanelWidth])
+
+  const handleMouseUp = useCallback(() => {
+    dragRef.current = false
+    document.body.style.cursor = ''
+    document.body.style.userSelect = ''
+  }, [])
+
+  useEffect(() => {
+    window.addEventListener('mousemove', handleMouseMove)
+    window.addEventListener('mouseup', handleMouseUp)
+    return () => {
+      window.removeEventListener('mousemove', handleMouseMove)
+      window.removeEventListener('mouseup', handleMouseUp)
+    }
+  }, [handleMouseMove, handleMouseUp])
+
+  return (
+    <div
+      ref={panelRef}
+      className="relative flex flex-col h-full panel-mica select-none shrink-0 overflow-hidden"
+      style={{ width: `${sidePanelWidth}px` }}
+      role="complementary"
+      aria-label="Side panel"
+    >
+      <div className="group flex items-center justify-between px-3 shrink-0 h-tabs border-b border-panel-border">
+        <span className="uppercase tracking-widest text-[11px] font-medium text-zinc-500">
+          {activeView === 'search' ? 'SEARCH' : activeView === 'extensions' ? 'EXTENSIONS' : activeView === 'settings' ? 'SETTINGS' : 'EXPLORER'}
+        </span>
+        <div className="flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity duration-fast">
+            {activeView === 'explorer' && (
+              <>
+                <button
+                  onClick={() => createUntitledFile()}
+                  className="p-1 rounded text-zinc-500 hover:text-zinc-300 hover:bg-panel-hover transition-all duration-fast"
+                  title="New File"
+                >
+                  <NewFileIcon />
+                </button>
+                {rootPath && (
+                  <button
+                    onClick={() => createFolder()}
+                    className="p-1 rounded text-zinc-500 hover:text-zinc-300 hover:bg-panel-hover transition-all duration-fast"
+                    title="New Folder"
+                  >
+                    <NewFolderIcon />
+                  </button>
+                )}
+                <button
+                  onClick={openFolder}
+                  className="p-1 rounded text-zinc-500 hover:text-zinc-300 hover:bg-panel-hover transition-all duration-fast"
+                  title={rootPath ? 'Open another folder' : 'Open Folder'}
+                >
+                  <OpenFolderIcon />
+                </button>
+            </>
+          )}
+        </div>
+      </div>
+
+      <div className="flex-1 overflow-y-auto overflow-x-hidden">
+        {activeView === 'explorer' && (
+          <>
+            {!rootPath && !loading && (
+              <div className="flex flex-col items-center gap-3 px-4 py-8 text-center">
+                <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" className="text-text-muted">
+                  <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" />
+                </svg>
+                <p className="text-ui-sm text-text-secondary">No folder open</p>
+                <button
+                  onClick={openFolder}
+                  className="px-3 py-1.5 text-ui-xs font-medium rounded transition-all duration-150 hover:brightness-110 bg-accent text-editor-bg"
+                >
+                  Open Folder
+                </button>
+              </div>
+            )}
+
+            {loading && (
+              <div className="flex items-center justify-center gap-2 py-8">
+                <div className="w-3 h-3 rounded-full animate-pulse bg-accent" />
+                <span className="text-ui-sm text-text-secondary">Loading...</span>
+              </div>
+            )}
+
+            {rootPath && !loading && (
+              <>
+                <div className="px-3 py-1.5 text-ui-xs font-medium truncate text-text-muted border-b border-panel-border" title={rootPath}>
+                  {rootPath.split(/[\\/]/).pop()}
+                </div>
+                {fileTree.length > 0 ? (
+                  <FileTree entries={fileTree} />
+                ) : (
+                  <div className="py-8 text-ui-sm text-text-secondary text-center">Empty directory</div>
+                )}
+              </>
+            )}
+          </>
+        )}
+
+        {activeView === 'search' && (
+          <div className="flex items-center justify-center py-8 text-ui-sm text-text-muted">
+            Search coming soon
+          </div>
+        )}
+
+        {activeView === 'extensions' && (
+          <div className="flex items-center justify-center py-8 text-ui-sm text-text-muted">
+            Extensions coming soon
+          </div>
+        )}
+
+        {activeView === 'settings' && (
+          <SettingsPanel />
+        )}
+      </div>
+
+      <div
+        className="absolute right-0 top-0 bottom-0 w-[4px] cursor-col-resize hover:bg-accent/30 transition-colors duration-fast"
+        style={{ right: '-2px' }}
+        onMouseDown={handleMouseDown}
+      />
+    </div>
+  )
+}
-- 
cgit v1.2.3

