Skip to content

Commit 8fe1e6f

Browse files
authored
Merge pull request #3 from Tekiter/improve-ux
feat: UI 개선
2 parents 63f3a80 + b2180b2 commit 8fe1e6f

8 files changed

Lines changed: 111 additions & 15 deletions

File tree

electron/main/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { autoUpdater } from "electron-updater";
55
import { release } from "os";
66
import { join } from "path";
77

8+
import { version } from "../../package.json";
9+
810
// Disable GPU Acceleration for Windows 7
911
if (release().startsWith("6.1")) app.disableHardwareAcceleration();
1012

@@ -39,7 +41,7 @@ const indexHtml = join(ROOT_PATH.dist, "index.html");
3941

4042
async function createWindow() {
4143
win = new BrowserWindow({
42-
title: "RunTC",
44+
title: "RunTC - " + version,
4345
icon: join(ROOT_PATH.public, "favicon.svg"),
4446
autoHideMenuBar: true,
4547
webPreferences: {

index.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
<link rel="icon" type="image/svg+xml" href="/src/assets/favicon.svg" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
8-
<title>RunTC</title>
98
</head>
109
<body>
1110
<div id="root"></div>

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"@vitejs/plugin-react": "^2.0.1",
2828
"allotment": "^1.17.0",
2929
"await-to-js": "^3.0.0",
30+
"compare-versions": "^5.0.1",
3031
"electron": "^20.0.2",
3132
"electron-builder": "^23.3.3",
3233
"electron-log": "^4.4.8",

src/components/sidePanel/testcaseList/SelectTestcaseItem.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@ const StyledItem = styled.div<{ selected: boolean }>`
3636
grid-template-columns: 10px minmax(16px, 1fr) max-content;
3737
align-items: center;
3838
39+
height: 40px;
40+
line-height: 40px;
41+
3942
cursor: pointer;
4043
border-radius: 6px;
4144
margin: 0 10px;
42-
padding: 10px 15px;
45+
padding: 0 15px;
4346
4447
${(props) =>
4548
props.selected &&

src/components/testcase/TerminalOutput.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ const TerminalOutput: FC<OutputProps> = ({ content }) => {
2626

2727
const term = new Terminal({
2828
fontFamily: "consolas",
29+
convertEol: true,
30+
disableStdin: true,
2931
});
3032
const fitAddon = new FitAddon();
3133

Lines changed: 97 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
import { Button, Editable, EditableInput, EditablePreview } from "@chakra-ui/react";
1+
import { Button, Editable, EditableInput, EditablePreview, useEditableControls } from "@chakra-ui/react";
2+
import { css } from "@emotion/react";
23
import styled from "@emotion/styled";
3-
import { FC } from "react";
4+
import { FC, ReactNode } from "react";
5+
import { MdDelete, MdEdit, MdPlayArrow } from "react-icons/md";
46
import { useRecoilValue } from "recoil";
57

68
import useTestcaseCommand from "@/commands/useTestcaseCommand";
79
import useTestcaseRunner from "@/commands/useTestcaseRunner";
810
import { testcaseFamily } from "@/states/testcase";
11+
import { TestcaseResult, testcaseResultFamily } from "@/states/testcaseResult";
12+
13+
import { getResultColor, getResultDescription } from "../common/renderResultUtil";
914

1015
interface TestcaseInfoProps {
1116
testcaseId: string;
@@ -15,29 +20,110 @@ const TestcaseInfo: FC<TestcaseInfoProps> = ({ testcaseId }) => {
1520
const command = useTestcaseCommand();
1621
const runner = useTestcaseRunner();
1722
const testcase = useRecoilValue(testcaseFamily(testcaseId));
23+
const result = useRecoilValue(testcaseResultFamily(testcaseId));
1824

1925
return (
2026
<StyledTestcaseInfo>
21-
<Name value={testcase.name} onChange={(name) => command.changeValue(testcaseId, { name })} fontSize={20}>
22-
<EditablePreview />
23-
<EditableInput />
24-
</Name>
25-
<Button onClick={() => runner.run(testcaseId)}>Run</Button>
26-
<Button onClick={() => command.remove(testcaseId)}>삭제</Button>
27+
<NameBox>
28+
<Name
29+
value={testcase.name}
30+
placeholder="이름 없음"
31+
onChange={(name) => command.changeValue(testcaseId, { name })}
32+
fontSize={20}>
33+
<WithEditButton>
34+
<EditablePreview
35+
overflow="hidden"
36+
textOverflow="ellipsis"
37+
whiteSpace="nowrap"
38+
display="block"
39+
justifySelf="normal"
40+
/>
41+
</WithEditButton>
42+
<EditableInput />
43+
</Name>
44+
</NameBox>
45+
<ActionBox>
46+
<ActionBoxLeft>
47+
<Button
48+
onClick={() => runner.run(testcaseId)}
49+
variant="outline"
50+
size="sm"
51+
leftIcon={<MdPlayArrow />}
52+
colorScheme="teal"
53+
isLoading={result === "running"}>
54+
실행
55+
</Button>
56+
<Result status={result}>{getResultDescription(result)}</Result>
57+
</ActionBoxLeft>
58+
<Spacer />
59+
<Button
60+
onClick={() => command.remove(testcaseId)}
61+
variant="outline"
62+
size="sm"
63+
leftIcon={<MdDelete />}
64+
colorScheme="red">
65+
삭제
66+
</Button>
67+
</ActionBox>
2768
</StyledTestcaseInfo>
2869
);
2970
};
3071

3172
export default TestcaseInfo;
3273

33-
const StyledTestcaseInfo = styled.div`
74+
const StyledTestcaseInfo = styled.div``;
75+
76+
const NameBox = styled.div`
77+
margin-top: 10px;
78+
height: 40px;
79+
`;
80+
81+
const ActionBox = styled.div`
3482
display: flex;
35-
height: 3.5rem;
83+
margin: 0 8px;
3684
`;
3785

38-
const Name = styled(Editable)`
86+
const ActionBoxLeft = styled.div`
87+
display: flex;
88+
align-items: center;
89+
`;
90+
91+
const Result = styled.div<{ status: TestcaseResult }>`
92+
margin-left: 0.8rem;
93+
font-size: 0.85rem;
94+
95+
${(props) => css`
96+
color: ${getResultColor(props.status)};
97+
`}
98+
`;
99+
100+
const Spacer = styled.div`
39101
flex-grow: 1;
102+
`;
103+
104+
const Name = styled(Editable)`
40105
font-weight: 500;
41106
align-self: center;
42107
margin: 0 10px;
43108
`;
109+
110+
const WithEditButton = ({ children }: { children: ReactNode }) => {
111+
const { isEditing, getEditButtonProps } = useEditableControls();
112+
113+
return isEditing ? (
114+
<></>
115+
) : (
116+
<StyledWithEditButton>
117+
{children}
118+
<Button size="sm" variant="link" {...getEditButtonProps()}>
119+
<MdEdit />
120+
</Button>
121+
</StyledWithEditButton>
122+
);
123+
};
124+
125+
const StyledWithEditButton = styled.div`
126+
display: grid;
127+
grid-template-columns: max-content 20px 1fr;
128+
align-items: center;
129+
`;

src/states/executableTarget.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export const executableTargetFilenameSelector = selector<string | null>({
1313
return null;
1414
}
1515

16-
return path.split("\\").at(-1) ?? null;
16+
const matches = path.match(/.+[\\/\\]([^\\/\\]+)/);
17+
18+
return matches?.[1] ?? null;
1719
},
1820
});

tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"noEmit": true,
2121
"jsx": "react-jsx"
2222
},
23+
2324
"include": ["src"],
2425
"exclude": ["src/**/*.test.ts"],
2526
"references": [{ "path": "./tsconfig.node.json" }],

0 commit comments

Comments
 (0)