feat: IDE
ci-front / build (push) Successful in 2m19s

This commit is contained in:
nikita
2026-04-04 04:59:42 +03:00
parent 9d1096a9b4
commit f537f1eab9
20 changed files with 2884 additions and 15 deletions
@@ -0,0 +1,89 @@
import React from "react";
import Editor from "@monaco-editor/react";
import { FiFolder } from "react-icons/fi";
import { getLanguage } from "../helpers/fileTree";
interface CodeEditorProps {
filePath: string;
content: string;
onChange: (content: string) => void;
}
export const CodeEditor: React.FC<CodeEditorProps> = ({
filePath,
content,
onChange,
}) => {
return (
<div
style={{
height: "100%",
display: "flex",
flexDirection: "column",
backgroundColor: "#1e1e1e",
}}
>
<div style={{ flex: 1 }}>
{filePath ? (
<Editor
height="100%"
language={getLanguage(filePath)}
value={content}
onChange={(value) => onChange(value || "")}
theme="vs-dark"
options={{
minimap: { enabled: false },
fontSize: 14,
fontFamily: "'Cascadia Code', 'Fira Code', monospace",
tabSize: 4,
wordWrap: "on",
lineNumbers: "on",
automaticLayout: true,
renderWhitespace: "selection",
smoothScrolling: true,
}}
/>
) : (
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "100%",
color: "#858585",
textAlign: "center",
}}
>
<div>
<div
style={{
marginBottom: "24px",
display: "flex",
justifyContent: "center",
opacity: 0.5,
}}
>
<FiFolder size={64} />
</div>
<div
style={{
fontSize: "18px",
marginBottom: "12px",
color: "#cccccc",
}}
>
Welcome to Web VS Code
</div>
<div style={{ fontSize: "13px", marginBottom: "8px" }}>
Right-click on a folder to create files
</div>
<div style={{ fontSize: "12px", color: "#0e639c" }}>
Or right-click anywhere in the explorer
</div>
</div>
</div>
)}
</div>
</div>
);
};
@@ -0,0 +1,99 @@
import React, { useEffect } from "react";
import { FiFile, FiFolder, FiEdit3, FiTrash2 } from "react-icons/fi";
const MenuItem: React.FC<{
onClick: () => void;
danger?: boolean;
children: React.ReactNode;
}> = ({ onClick, danger, children }) => (
<div
onClick={onClick}
style={{
padding: "8px 16px",
cursor: "pointer",
color: danger ? "#f48771" : "#cccccc",
fontSize: "13px",
transition: "background-color 0.1s",
display: "flex",
alignItems: "center",
gap: "10px",
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = "#2a2d2e";
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = "transparent";
}}
>
{children}
</div>
);
interface ContextMenuProps {
x: number;
y: number;
onClose: () => void;
onNewFile: () => void;
onNewFolder: () => void;
onRename: () => void;
onDelete: () => void;
hasNode: boolean;
}
export const ContextMenu: React.FC<ContextMenuProps> = ({
x,
y,
onClose,
onNewFile,
onNewFolder,
onRename,
onDelete,
hasNode,
}) => {
useEffect(() => {
const handleClick = () => onClose();
document.addEventListener("click", handleClick);
return () => document.removeEventListener("click", handleClick);
}, [onClose]);
return (
<div
style={{
position: "fixed",
top: y,
left: x,
backgroundColor: "#252526",
border: "1px solid #3e3e42",
borderRadius: "6px",
boxShadow: "0 4px 12px rgba(0,0,0,0.4)",
zIndex: 1000,
minWidth: "180px",
overflow: "hidden",
}}
>
<MenuItem onClick={onNewFile}>
<FiFile /> New File
</MenuItem>
<MenuItem onClick={onNewFolder}>
<FiFolder /> New Folder
</MenuItem>
{hasNode && (
<>
<div
style={{
height: "1px",
backgroundColor: "#3e3e42",
margin: "4px 0",
}}
/>
<MenuItem onClick={onRename}>
<FiEdit3 /> Rename
</MenuItem>
<MenuItem onClick={onDelete} danger>
<FiTrash2 /> Delete
</MenuItem>
</>
)}
</div>
);
};
@@ -0,0 +1,318 @@
import React, { useEffect, useState } from "react";
import { FiSearch, FiFile, FiFolder, FiMinus } from "react-icons/fi";
import { GoKebabHorizontal } from "react-icons/go";
import { MdClose, MdAdd } from "react-icons/md";
import { FileTreeItem } from "./FileTreeItem";
import { ContextMenu } from "./ContextMenu";
import { InputDialog } from "./InputDialog";
import { filterTree, collectPathsToExpand } from "../helpers/fileTree";
import { useIDEStore } from "../store/useIDEStore";
import type { FileNode } from "../types";
interface FileExplorerProps {
files: FileNode;
onDeleteRoot: () => void;
}
export const FileExplorer: React.FC<FileExplorerProps> = ({
files,
onDeleteRoot,
}) => {
const store = useIDEStore();
const [showSearch, setShowSearch] = useState(false);
const handleEmptyContextMenu = (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
store.setContextMenu({ x: e.clientX, y: e.clientY, node: null });
};
const handleNodeContextMenu = (e: React.MouseEvent, node: FileNode) => {
e.preventDefault();
e.stopPropagation();
store.setContextMenu({ x: e.clientX, y: e.clientY, node });
};
const filteredFiles = store.searchQuery
? filterTree(files, store.searchQuery)
: files;
useEffect(() => {
if (store.searchQuery && files) {
const pathsToExpand = collectPathsToExpand(files, store.searchQuery);
if (pathsToExpand.size > 0) {
store.autoExpandPaths(pathsToExpand);
}
}
}, [store.searchQuery, files, store.autoExpandPaths]);
return (
<div
style={{
height: "100%",
display: "flex",
flexDirection: "column",
backgroundColor: "#252526",
}}
onContextMenu={handleEmptyContextMenu}
>
<div
style={{
padding: "0 8px",
height: "35px",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
borderBottom: "1px solid #3e3e42",
}}
>
<span
style={{
color: "#bbbbbb",
fontWeight: 500,
fontSize: "11px",
letterSpacing: "0.8px",
}}
>
EXPLORER
</span>
<div style={{ display: "flex", gap: "2px", alignItems: "center" }}>
<button
onClick={() => setShowSearch(!showSearch)}
style={{
background: "transparent",
border: "none",
color: showSearch ? "#cccccc" : "#858585",
cursor: "pointer",
padding: "4px",
borderRadius: "4px",
display: "flex",
alignItems: "center",
justifyContent: "center",
transition: "all 0.1s",
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = "#2a2d2e";
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = "transparent";
}}
title="Search in files"
>
<FiSearch size={14} />
</button>
<button
onClick={store.collapseAllFolders}
style={{
background: "transparent",
border: "none",
color: "#858585",
cursor: "pointer",
padding: "4px",
borderRadius: "4px",
display: "flex",
alignItems: "center",
justifyContent: "center",
transition: "all 0.1s",
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = "#2a2d2e";
e.currentTarget.style.color = "#cccccc";
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = "transparent";
e.currentTarget.style.color = "#858585";
}}
title="Collapse All"
>
<FiMinus size={14} />
</button>
<button
onClick={store.expandAllFolders}
style={{
background: "transparent",
border: "none",
color: "#858585",
cursor: "pointer",
padding: "4px",
borderRadius: "4px",
display: "flex",
alignItems: "center",
justifyContent: "center",
transition: "all 0.1s",
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = "#2a2d2e";
e.currentTarget.style.color = "#cccccc";
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = "transparent";
e.currentTarget.style.color = "#858585";
}}
title="Expand All"
>
<GoKebabHorizontal size={14} />
</button>
</div>
</div>
<div
style={{
padding: "6px 12px",
display: "flex",
alignItems: "center",
gap: "6px",
borderBottom: "1px solid #3e3e42",
}}
>
<FiFolder size={14} color="#858585" />
<span
style={{
color: "#cccccc",
fontWeight: 600,
fontSize: "11px",
letterSpacing: "0.3px",
flex: 1,
}}
>
{files.name}
</span>
</div>
{showSearch && (
<div style={{ padding: "6px 8px", borderBottom: "1px solid #3e3e42" }}>
<div
style={{
display: "flex",
alignItems: "center",
backgroundColor: "#3c3c3c",
border: store.searchQuery
? "1px solid #007acc"
: "1px solid transparent",
borderRadius: "4px",
padding: "0 6px",
transition: "border-color 0.1s",
}}
>
<FiSearch size={13} color="#858585" />
<input
type="text"
value={store.searchQuery}
onChange={(e) => store.setSearchQuery(e.target.value)}
placeholder="Search..."
autoFocus
style={{
flex: 1,
padding: "5px 6px",
backgroundColor: "transparent",
border: "none",
color: "#cccccc",
fontSize: "12px",
outline: "none",
}}
/>
{store.searchQuery && (
<button
onClick={() => store.setSearchQuery("")}
style={{
background: "none",
border: "none",
color: "#858585",
cursor: "pointer",
padding: "2px",
display: "flex",
alignItems: "center",
}}
>
<MdClose size={12} />
</button>
)}
</div>
</div>
)}
<div style={{ flex: 1, overflowY: "auto" }}>
{filteredFiles ? (
<FileTreeItem
node={filteredFiles}
level={0}
onFileSelect={store.selectFile}
selectedFile={store.activeFile?.path || null}
onContextMenu={handleNodeContextMenu}
expandedFolders={store.expandedFolders}
onToggleFolder={store.toggleFolder}
onDelete={store.handleDeleteNode}
isRoot
searchQuery={store.searchQuery}
/>
) : (
<div
style={{
padding: "16px",
color: "#858585",
fontSize: "13px",
textAlign: "center",
}}
>
No results found
</div>
)}
</div>
{store.contextMenu && (
<ContextMenu
x={store.contextMenu.x}
y={store.contextMenu.y}
onClose={() => store.setContextMenu(null)}
onNewFile={() => {
store.setDialog({
type: "newFile",
node: store.contextMenu?.node || null,
});
store.setContextMenu(null);
}}
onNewFolder={() => {
store.setDialog({
type: "newFolder",
node: store.contextMenu?.node || null,
});
store.setContextMenu(null);
}}
onRename={() => {
store.setDialog({
type: "rename",
node: store.contextMenu?.node || null,
});
store.setContextMenu(null);
}}
onDelete={() => {
if (store.contextMenu?.node) {
store.handleDeleteNode(store.contextMenu.node);
}
store.setContextMenu(null);
}}
hasNode={!!store.contextMenu.node}
/>
)}
{store.dialog && (
<InputDialog
title={
store.dialog.type === "newFile"
? "New File"
: store.dialog.type === "newFolder"
? "New Folder"
: "Rename"
}
initialValue={
store.dialog.type === "rename" && store.dialog.node
? store.dialog.node.name
: ""
}
onConfirm={store.handleDialogConfirm}
onCancel={() => store.setDialog(null)}
/>
)}
</div>
);
};
@@ -0,0 +1,169 @@
import React, { useState } from "react";
import { FiChevronRight, FiChevronDown, FiTrash2 } from "react-icons/fi";
import { GoFile } from "react-icons/go";
import type { FileNode } from "../types";
interface FileTreeItemProps {
node: FileNode;
level: number;
onFileSelect: (node: FileNode) => void;
selectedFile: string | null;
onContextMenu: (e: React.MouseEvent, node: FileNode) => void;
expandedFolders: Set<string>;
onToggleFolder: (path: string) => void;
onDelete: (node: FileNode) => void;
isRoot?: boolean;
searchQuery?: string;
}
export const FileTreeItem: React.FC<FileTreeItemProps> = ({
node,
level,
onFileSelect,
selectedFile,
onContextMenu,
expandedFolders,
onToggleFolder,
onDelete,
isRoot,
searchQuery,
}) => {
const isFolder = node.type === "folder";
const isSelected = selectedFile === node.path && !isFolder;
const isExpanded = expandedFolders.has(node.path || node.name);
const [hovered, setHovered] = useState(false);
const handleClick = () => {
if (isFolder) {
onToggleFolder(node.path || node.name);
} else {
onFileSelect(node);
}
};
const handleDelete = (e: React.MouseEvent) => {
e.stopPropagation();
onDelete(node);
};
const highlightText = (text: string, query: string) => {
if (!query) return text;
const idx = text.toLowerCase().indexOf(query.toLowerCase());
if (idx === -1) return text;
return (
<>
{text.slice(0, idx)}
<span style={{ backgroundColor: "#613214", color: "#f9f9a4" }}>
{text.slice(idx, idx + query.length)}
</span>
{text.slice(idx + query.length)}
</>
);
};
return (
<div>
<div
onClick={handleClick}
onContextMenu={(e) => onContextMenu(e, node)}
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
style={{
paddingLeft: isRoot ? "8px" : `${level * 16 + 8}px`,
paddingTop: "4px",
paddingBottom: "4px",
cursor: "pointer",
display: "flex",
alignItems: "center",
gap: "6px",
backgroundColor: isSelected ? "#094771" : "transparent",
color: isSelected ? "#fff" : "#cccccc",
fontSize: "13px",
transition: "background-color 0.1s",
userSelect: "none",
minHeight: "28px",
}}
>
<span
style={{
fontSize: "14px",
width: "16px",
textAlign: "center",
display: "flex",
alignItems: "center",
justifyContent: "center",
flexShrink: 0,
}}
>
{isFolder ? (
isExpanded ? (
<FiChevronDown />
) : (
<FiChevronRight />
)
) : (
<GoFile />
)}
</span>
<span
style={{
flex: 1,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
}}
>
{searchQuery ? highlightText(node.name, searchQuery) : node.name}
</span>
{hovered && !isRoot && (
<button
onClick={handleDelete}
title={`Delete ${node.name}`}
style={{
background: "none",
border: "none",
color: "#858585",
cursor: "pointer",
padding: "2px",
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: "3px",
flexShrink: 0,
width: "20px",
height: "20px",
}}
onMouseEnter={(e) => {
e.currentTarget.style.color = "#f48771";
e.currentTarget.style.backgroundColor = "#3e3e42";
}}
onMouseLeave={(e) => {
e.currentTarget.style.color = "#858585";
e.currentTarget.style.backgroundColor = "transparent";
}}
>
<FiTrash2 size={13} />
</button>
)}
</div>
{isFolder && isExpanded && node.children && (
<div>
{node.children.map((child, idx) => (
<FileTreeItem
key={idx}
node={child}
level={level + 1}
onFileSelect={onFileSelect}
selectedFile={selectedFile}
onContextMenu={onContextMenu}
expandedFolders={expandedFolders}
onToggleFolder={onToggleFolder}
onDelete={onDelete}
searchQuery={searchQuery}
/>
))}
</div>
)}
</div>
);
};
@@ -0,0 +1,119 @@
import React, { useState, useRef, useEffect } from "react";
interface InputDialogProps {
title: string;
initialValue?: string;
onConfirm: (value: string) => void;
onCancel: () => void;
}
export const InputDialog: React.FC<InputDialogProps> = ({
title,
initialValue = "",
onConfirm,
onCancel,
}) => {
const [value, setValue] = useState(initialValue);
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
inputRef.current?.focus();
inputRef.current?.select();
}, []);
return (
<div
style={{
position: "fixed",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: "rgba(0,0,0,0.6)",
display: "flex",
alignItems: "center",
justifyContent: "center",
zIndex: 2000,
}}
onClick={onCancel}
>
<div
style={{
backgroundColor: "#2d2d30",
borderRadius: "8px",
padding: "24px",
minWidth: "320px",
border: "1px solid #3e3e42",
boxShadow: "0 8px 24px rgba(0,0,0,0.4)",
}}
onClick={(e) => e.stopPropagation()}
>
<h3
style={{
margin: "0 0 8px 0",
color: "#fff",
fontSize: "16px",
fontWeight: 500,
}}
>
{title}
</h3>
<p style={{ margin: "0 0 16px 0", color: "#858585", fontSize: "12px" }}>
Enter a new name
</p>
<input
ref={inputRef}
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
onKeyDown={(e) =>
e.key === "Enter" && value.trim() && onConfirm(value.trim())
}
style={{
width: "100%",
padding: "10px",
backgroundColor: "#3c3c3c",
border: "1px solid #3e3e42",
borderRadius: "6px",
color: "#ccc",
fontSize: "14px",
marginBottom: "20px",
outline: "none",
}}
/>
<div
style={{ display: "flex", gap: "12px", justifyContent: "flex-end" }}
>
<button
onClick={onCancel}
style={{
padding: "6px 16px",
backgroundColor: "transparent",
border: "1px solid #0e639c",
borderRadius: "4px",
color: "#0e639c",
cursor: "pointer",
fontSize: "12px",
}}
>
Cancel
</button>
<button
onClick={() => value.trim() && onConfirm(value.trim())}
style={{
padding: "6px 16px",
backgroundColor: "#0e639c",
border: "none",
borderRadius: "4px",
color: "#fff",
cursor: "pointer",
fontSize: "12px",
}}
>
OK
</button>
</div>
</div>
</div>
);
};
@@ -0,0 +1,44 @@
import React from "react";
import { FiGitBranch, FiCheckCircle, FiAlertCircle } from "react-icons/fi";
import type { FileNode } from "../types";
interface StatusBarProps {
activeFile: FileNode | null;
}
export const StatusBar: React.FC<StatusBarProps> = ({ activeFile }) => {
return (
<div
style={{
height: "22px",
backgroundColor: "#007acc",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: "0 12px",
fontSize: "12px",
color: "#ffffff",
userSelect: "none",
flexShrink: 0,
}}
>
<div style={{ display: "flex", gap: "16px", alignItems: "center" }}>
<span style={{ display: "flex", alignItems: "center", gap: "4px" }}>
<FiGitBranch size={12} /> main
</span>
<span style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<FiCheckCircle size={12} /> 0 <FiAlertCircle size={12} /> 0
</span>
</div>
<div style={{ display: "flex", gap: "16px", alignItems: "center" }}>
{activeFile && (
<span>
Ln 1, Col 1 | Spaces: 4 | UTF-8 |{" "}
{activeFile.path?.split(".").pop()?.toUpperCase() || "TXT"}
</span>
)}
<span>Web VS Code</span>
</div>
</div>
);
};
@@ -0,0 +1,196 @@
import React, { useState } from "react";
import { GoFile } from "react-icons/go";
import { MdClose } from "react-icons/md";
import type { FileNode } from "../types";
interface TabBarProps {
openFiles: FileNode[];
activeFile: FileNode | null;
onSelectFile: (file: FileNode) => void;
onCloseFile: (file: FileNode) => void;
onCloseAll: () => void;
onCloseOthers: (file: FileNode) => void;
}
export const TabBar: React.FC<TabBarProps> = ({
openFiles,
activeFile,
onSelectFile,
onCloseFile,
onCloseAll,
onCloseOthers,
}) => {
const [showContextMenu, setShowContextMenu] = useState<{
x: number;
y: number;
file: FileNode;
} | null>(null);
const handleContextMenu = (e: React.MouseEvent, file: FileNode) => {
e.preventDefault();
setShowContextMenu({ x: e.clientX, y: e.clientY, file });
};
return (
<>
<div
style={{
display: "flex",
alignItems: "center",
backgroundColor: "#1e1e1e",
borderBottom: "1px solid #3e3e42",
overflowX: "auto",
minHeight: "40px",
}}
>
<div
style={{
display: "flex",
padding: "0 12px",
gap: "8px",
borderRight: "1px solid #3e3e42",
height: "100%",
alignItems: "center",
}}
>
<button
onClick={onCloseAll}
style={{
background: "transparent",
border: "none",
color: "#cccccc",
cursor: "pointer",
fontSize: "14px",
padding: "6px 8px",
borderRadius: "4px",
display: "flex",
alignItems: "center",
gap: "6px",
transition: "all 0.1s",
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = "#2a2d2e";
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = "transparent";
}}
title="Close All"
>
<MdClose size={14} />
<span style={{ fontSize: "11px" }}>Close All</span>
</button>
</div>
{openFiles.map((file) => (
<div
key={file.path}
onClick={() => onSelectFile(file)}
onContextMenu={(e) => handleContextMenu(e, file)}
style={{
display: "flex",
alignItems: "center",
padding: "8px 16px",
backgroundColor:
activeFile?.path === file.path ? "#1e1e1e" : "#2d2d30",
color: activeFile?.path === file.path ? "#fff" : "#cccccc",
borderRight: "1px solid #3e3e42",
cursor: "pointer",
fontSize: "13px",
gap: "10px",
whiteSpace: "nowrap",
transition: "all 0.1s",
borderTop:
activeFile?.path === file.path
? "2px solid #0e639c"
: "2px solid transparent",
}}
>
<GoFile />
<span>{file.name}</span>
<button
onClick={(e) => {
e.stopPropagation();
onCloseFile(file);
}}
style={{
background: "none",
border: "none",
color: "#858585",
cursor: "pointer",
fontSize: "16px",
padding: "0 4px",
borderRadius: "4px",
}}
onMouseEnter={(e) => {
e.currentTarget.style.color = "#fff";
e.currentTarget.style.backgroundColor = "#3e3e42";
}}
onMouseLeave={(e) => {
e.currentTarget.style.color = "#858585";
e.currentTarget.style.backgroundColor = "transparent";
}}
>
<MdClose size={14} />
</button>
</div>
))}
</div>
{showContextMenu && (
<div
style={{
position: "fixed",
top: showContextMenu.y,
left: showContextMenu.x,
backgroundColor: "#252526",
border: "1px solid #3e3e42",
borderRadius: "6px",
boxShadow: "0 4px 12px rgba(0,0,0,0.4)",
zIndex: 1000,
minWidth: "160px",
overflow: "hidden",
}}
>
<div
onClick={() => {
onCloseOthers(showContextMenu.file);
setShowContextMenu(null);
}}
style={{
padding: "8px 16px",
cursor: "pointer",
color: "#cccccc",
fontSize: "13px",
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = "#2a2d2e";
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = "transparent";
}}
>
Close Others
</div>
<div
onClick={() => {
onCloseAll();
setShowContextMenu(null);
}}
style={{
padding: "8px 16px",
cursor: "pointer",
color: "#cccccc",
fontSize: "13px",
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = "#2a2d2e";
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = "transparent";
}}
>
Close All
</div>
</div>
)}
</>
);
};
@@ -0,0 +1,55 @@
import React from "react";
import { FiGitBranch, FiCheckCircle } from "react-icons/fi";
export const TitleBar: React.FC = () => {
return (
<div
style={{
height: "32px",
backgroundColor: "#2d2d30",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: "0 12px",
borderBottom: "1px solid #3e3e42",
}}
>
<div style={{ display: "flex", alignItems: "center", gap: "12px" }}>
<div style={{ display: "flex", gap: "8px" }}>
<div
style={{
width: "12px",
height: "12px",
borderRadius: "50%",
backgroundColor: "#ed6a5e",
}}
/>
<div
style={{
width: "12px",
height: "12px",
borderRadius: "50%",
backgroundColor: "#f5bd4f",
}}
/>
<div
style={{
width: "12px",
height: "12px",
borderRadius: "50%",
backgroundColor: "#61c454",
}}
/>
</div>
<span style={{ color: "#cccccc", fontSize: "12px", fontWeight: 500 }}>
Web VS Code
</span>
</div>
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<FiGitBranch size={12} color="#858585" />
<span style={{ color: "#858585", fontSize: "11px" }}>main</span>
<FiCheckCircle size={12} color="#61c454" />
</div>
</div>
);
};
@@ -0,0 +1,8 @@
export { ContextMenu } from "./ContextMenu";
export { InputDialog } from "./InputDialog";
export { FileTreeItem } from "./FileTreeItem";
export { FileExplorer } from "./FileExplorer";
export { TabBar } from "./TabBar";
export { CodeEditor } from "./CodeEditor";
export { TitleBar } from "./TitleBar";
export { StatusBar } from "./StatusBar";