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
95 changes: 54 additions & 41 deletions apps/executeJS/src-tauri/src/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,52 @@ const { ops } = core;
// console 객체 정의
globalThis.console = {
log: (...args) => {
const message = args.map(arg => {
if (typeof arg === 'object') {
return JSON.stringify(arg, null, 2);
}
return String(arg);
}).join(' ');
const message = args
.map((arg) => {
if (typeof arg === 'object') {
return JSON.stringify(arg, null, 2);
}
return String(arg);
})
.join(' ');
ops.op_console_log(message);
},

error: (...args) => {
const message = args.map(arg => {
if (typeof arg === 'object') {
return JSON.stringify(arg, null, 2);
}
return String(arg);
}).join(' ');
const message = args
.map((arg) => {
if (typeof arg === 'object') {
return JSON.stringify(arg, null, 2);
}
return String(arg);
})
.join(' ');
ops.op_custom_print(message, true);
},

warn: (...args) => {
const message = args.map(arg => {
if (typeof arg === 'object') {
return JSON.stringify(arg, null, 2);
}
return String(arg);
}).join(' ');
const message = args
.map((arg) => {
if (typeof arg === 'object') {
return JSON.stringify(arg, null, 2);
}
return String(arg);
})
.join(' ');
ops.op_custom_print(`[WARN] ${message}`, false);
},

info: (...args) => {
const message = args.map(arg => {
if (typeof arg === 'object') {
return JSON.stringify(arg, null, 2);
}
return String(arg);
}).join(' ');
const message = args
.map((arg) => {
if (typeof arg === 'object') {
return JSON.stringify(arg, null, 2);
}
return String(arg);
})
.join(' ');
ops.op_custom_print(`[INFO] ${message}`, false);
}
},
};

// alert 함수 정의
Expand All @@ -59,7 +67,7 @@ globalThis.print = (message, isErr = false) => {
globalThis.require = (moduleName) => {
// 간단한 npm 모듈 시뮬레이션
const modules = {
'lodash': {
lodash: {
map: (array, iteratee) => {
if (!Array.isArray(array)) {
throw new Error('First argument must be an array');
Expand Down Expand Up @@ -93,33 +101,38 @@ globalThis.require = (moduleName) => {
chunks.push(array.slice(i, i + size));
}
return chunks;
}
},
},
'moment': {
moment: {
now: () => new Date(),
format: (date, format) => {
if (!(date instanceof Date)) {
date = new Date(date);
}
return date.toISOString();
}
},
},
'uuid': {
uuid: {
v4: () => {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
}
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
/[xy]/g,
function (c) {
const r = (Math.random() * 16) | 0;
const v = c == 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
}
);
},
},
};

if (modules[moduleName]) {
return modules[moduleName];
}

throw new Error(`Cannot find module '${moduleName}'. Available modules: ${Object.keys(modules).join(', ')}`);
throw new Error(
`Cannot find module '${moduleName}'. Available modules: ${Object.keys(modules).join(', ')}`
);
};

// 기본적인 전역 객체들 정의
Expand Down
7 changes: 1 addition & 6 deletions apps/executeJS/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,7 @@
},
"bundle": {
"active": true,
"targets": [
"msi",
"nsis",
"dmg",
"app"
],
"targets": ["msi", "nsis", "dmg", "app"],
"icon": [],
"macOS": {
"entitlements": null,
Expand Down
38 changes: 35 additions & 3 deletions apps/executeJS/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,38 @@
* {
box-sizing: border-box;
}

body {
margin: 0;
padding: 0;
background-color: #0f172a; /* slate-950 */
color: #f8fafc; /* slate-50 */
}

/* 스크롤바 스타일링 */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}

::-webkit-scrollbar-track {
background: #1e293b; /* slate-800 */
}

::-webkit-scrollbar-thumb {
background: #475569; /* slate-600 */
border-radius: 4px;
}

::-webkit-scrollbar-thumb:hover {
background: #64748b; /* slate-500 */
}

/* 선택 영역 스타일링 */
::selection {
background-color: #3b82f6; /* blue-500 */
color: white;
}
}

@layer components {
Expand All @@ -23,13 +55,13 @@
}

.panel-resize-handle {
width: 0.25rem;
background-color: hsl(0 0% 88.7%);
width: 4px;
background-color: #334155; /* slate-700 */
transition: background-color 150ms;
cursor: col-resize;
}

.panel-resize-handle:hover {
background-color: hsl(0 0% 78%);
background-color: #475569; /* slate-600 */
}
}
4 changes: 1 addition & 3 deletions apps/executeJS/src/pages/editor/editor-page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ vi.mock('@legendapp/state/react', () => ({
describe('EditorPage', () => {
it('renders without crashing', () => {
render(<EditorPage />);
expect(
screen.getByText(/Cmd\+Enter를 눌러 코드를 실행하세요/)
).toBeInTheDocument();
expect(screen.getByText(/실행 \(Cmd\+Enter\)/)).toBeInTheDocument();
});
});
80 changes: 64 additions & 16 deletions apps/executeJS/src/pages/editor/editor-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import { CodeEditor } from '@/widgets/code-editor';
import { OutputPanel } from '@/widgets/output-panel';
import { useExecutionStore } from '@/features/execute-code';
import { PlayIcon, StopIcon } from '@radix-ui/react-icons';

export const EditorPage: React.FC = () => {
const [code, setCode] = useState('');
const [code, setCode] = useState('console.log("Hello, ExecuteJS!");');
const {
result: executionResult,
isExecuting,
Expand All @@ -14,8 +15,9 @@ export const EditorPage: React.FC = () => {

// 코드 실행 핸들러
const handleExecuteCode = (codeToExecute?: string) => {
if (codeToExecute) {
executeCode(codeToExecute);
const codeToRun = codeToExecute || code;
if (codeToRun.trim()) {
executeCode(codeToRun);
}
};

Expand All @@ -25,29 +27,75 @@ export const EditorPage: React.FC = () => {
};

return (
<div className="h-screen w-screen flex flex-col bg-gray-1">
<div className="h-screen w-screen flex flex-col bg-slate-950 text-white">
{/* 헤더 */}
<div className="flex items-center justify-between px-4 py-3 bg-slate-900 border-b border-slate-800">
<div className="flex items-center gap-3">
<div className="text-sm font-medium text-slate-300">ExecuteJS</div>
</div>

<div className="flex items-center gap-2">
<button
onClick={() => handleExecuteCode()}
disabled={isExecuting || !code.trim()}
className="flex items-center gap-2 px-3 py-1.5 bg-blue-600 hover:bg-blue-700 disabled:bg-slate-700 disabled:cursor-not-allowed text-white text-sm font-medium rounded-md transition-colors"
>
{isExecuting ? (
<>
<StopIcon className="w-4 h-4" />
실행 중...
</>
) : (
<>
<PlayIcon className="w-4 h-4" />
실행 (Cmd+Enter)
</>
)}
</button>
</div>
</div>

{/* 메인 컨텐츠 영역 */}
<div className="flex-1 flex h-screen">
<PanelGroup direction="horizontal" className="flex-1 h-full border">
<div className="flex-1 flex">
<PanelGroup direction="horizontal" className="flex-1">
{/* 왼쪽 패널 - 코드 에디터 */}
<Panel defaultSize={50} minSize={30}>
<div className="h-full bg-gray-2">
<CodeEditor
value={code}
onChange={handleCodeChange}
onExecute={handleExecuteCode}
language="javascript"
theme="vs-dark"
/>
<div className="h-full bg-slate-900 border-r border-slate-800">
<div className="h-8 bg-slate-800 border-b border-slate-700 flex items-center px-4">
<span className="text-xs font-medium text-slate-400 uppercase tracking-wide">
Editor
</span>
</div>
<div className="h-[calc(100%-2rem)]">
<CodeEditor
value={code}
onChange={handleCodeChange}
onExecute={handleExecuteCode}
language="javascript"
theme="vs-dark"
/>
</div>
</div>
</Panel>

{/* 리사이즈 핸들 */}
<PanelResizeHandle className="panel-resize-handle" />
<PanelResizeHandle className="w-1 bg-slate-800 hover:bg-slate-700 transition-colors" />

{/* 오른쪽 패널 - 출력 결과 */}
<Panel defaultSize={50} minSize={30}>
<OutputPanel result={executionResult} isExecuting={isExecuting} />
<div className="h-full bg-slate-900">
<div className="h-8 bg-slate-800 border-b border-slate-700 flex items-center px-4">
<span className="text-xs font-medium text-slate-400 uppercase tracking-wide">
Output
</span>
</div>
<div className="h-[calc(100%-2rem)]">
<OutputPanel
result={executionResult}
isExecuting={isExecuting}
/>
</div>
</div>
</Panel>
</PanelGroup>
</div>
Expand Down
Loading