Skip to content

Commit e523ed1

Browse files
authored
Merge pull request #26 from Queryus/feature/FRT-39
[FRT-39] 쿼리 편집기
2 parents 94118c8 + 05d5611 commit e523ed1

File tree

8 files changed

+147
-76
lines changed

8 files changed

+147
-76
lines changed
90 KB
Binary file not shown.

src/renderer/src/assets/main.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@
5454
font-weight: 900;
5555
font-style: normal;
5656
}
57+
@font-face {
58+
font-display: swap;
59+
font-family: 'JetBrains Mono';
60+
src: url('./fonts/JetBrainsMono-Regular.woff2') format('woff2');
61+
font-weight: 400;
62+
font-style: normal;
63+
}
5764

5865
@import 'tailwindcss';
5966
@plugin "tailwindcss-animate";

src/renderer/src/components/workspace/ai-chat-panel/chat-message.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export default function ChatMessage({
123123
)}
124124
{sql && (
125125
<div className="self-stretch p-4 bg-zinc-900 rounded-lg flex flex-col justify-start items-end gap-4">
126-
<div className="self-stretch justify-start text-neutral-200 text-sm font-normal font-['JetBrains_Mono'] leading-tight">
126+
<div className="self-stretch justify-start text-genie-100 text-code font-code">
127127
<HighlightedText text={sql} highlight={highlightTerm} />
128128
</div>
129129
<div className="inline-flex justify-start items-start gap-2.5">
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export { default as QueryPanel } from './query-panel'
2+
export { default as QueryEditor } from './query-editor'
3+
export { default as QueryResults } from './query-results'
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { useState } from 'react'
2+
3+
/**
4+
* @author nahyeongjin1
5+
* @summary 쿼리 편집기 패널
6+
* @returns JSX.Element
7+
*/
8+
export default function QueryEditor(): React.JSX.Element {
9+
const [query, setQuery] = useState(
10+
'SELECT p.ProductName, SUM(sod.sales_quantity) as total_quantity_sold, ' +
11+
'SUM(sod.sales_quantity * sod.UnitPrice) as total_revenue ' +
12+
'FROM Products p ' +
13+
'JOIN SalesOrderDetails sod ON p.ProductID = sod.ProductID ' +
14+
'GROUP BY p.ProductID, p.ProductName ' +
15+
'ORDER BY total_revenue DESC ' +
16+
'LIMIT 5;'
17+
)
18+
19+
return (
20+
<div className="h-full p-5">
21+
<textarea
22+
name="query"
23+
value={query}
24+
onChange={(e) => setQuery(e.target.value)}
25+
className="w-full h-full bg-transparent text-genie-100 font-code text-code resize-none focus:outline-none"
26+
spellCheck="false"
27+
/>
28+
</div>
29+
)
30+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import React, { useState } from 'react'
2+
import { Code2, ChartColumn, Download } from 'lucide-react'
3+
import { cn } from '@/lib/utils'
4+
import QueryEditor from './query-editor'
5+
import QueryResults from './query-results'
6+
7+
type ActiveTab = 'editor' | 'results'
8+
9+
/**
10+
* @author nahyeongjin1
11+
* @summary 쿼리 편집기 및 결과 탭 패널
12+
* @returns JSX.Element
13+
*/
14+
export default function QueryPanel(): React.JSX.Element {
15+
const [activeTab, setActiveTab] = useState<ActiveTab>('editor')
16+
17+
const TabButton = ({
18+
tabName,
19+
Icon,
20+
label
21+
}: {
22+
tabName: ActiveTab
23+
Icon: React.ElementType
24+
label: string
25+
}): React.JSX.Element => (
26+
<div
27+
onClick={() => setActiveTab(tabName)}
28+
className={cn(
29+
'group flex items-center gap-2 py-[16.5px] cursor-pointer border-b-3 -mb-px',
30+
activeTab === tabName
31+
? 'border-primary-light text-genie-100'
32+
: 'border-transparent text-genie-500 hover:text-genie-200 hover:opacity-80'
33+
)}
34+
>
35+
<Icon className="size-4 stroke-current" />
36+
<span className="text-title font-pretendard">{label}</span>
37+
</div>
38+
)
39+
40+
return (
41+
<div className="flex-1 h-full flex flex-col bg-neutral-800 outline-1 outline-offset-[-1px] outline-neutral-700">
42+
{/* Tab Header */}
43+
<div className="flex justify-between items-center border-b border-neutral-700 pr-3 pl-4">
44+
<div className="flex gap-6 px-1">
45+
<TabButton tabName="editor" Icon={Code2} label="쿼리 편집기" />
46+
<TabButton tabName="results" Icon={ChartColumn} label="실행 결과" />
47+
</div>
48+
<div className="px-3 py-1.5 bg-gradient-genie-primary rounded-lg outline-1 outline-offset-[-1px] outline-white/20 flex justify-center items-center gap-2 cursor-pointer">
49+
<Download className="size-3 stroke-genie-100" />
50+
<div className="justify-start text-genie-100 text-button font-pretendard">내보내기</div>
51+
</div>
52+
</div>
53+
54+
{/* Tab Content */}
55+
<div className="flex-1 overflow-auto">
56+
{activeTab === 'editor' && <QueryEditor />}
57+
{activeTab === 'results' && <QueryResults />}
58+
</div>
59+
</div>
60+
)
61+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* @author nahyeongjin1
3+
* @summary 쿼리 실행 결과 패널
4+
* @returns JSX.Element
5+
*/
6+
export default function QueryResults(): React.JSX.Element {
7+
return (
8+
<div className="flex-1 flex flex-col h-full">
9+
<div className="flex-1 p-5 overflow-auto">
10+
<div className="self-stretch rounded-lg outline-1 outline-offset-[-1px] outline-neutral-700 flex flex-col justify-start items-start overflow-hidden">
11+
<div className="self-stretch bg-neutral-700 inline-flex justify-start items-center">
12+
<div className="flex-1 p-2 justify-start text-neutral-200 text-xs font-medium font-['Pretendard'] leading-none">
13+
상품명
14+
</div>
15+
<div className="flex-1 p-2 justify-start text-neutral-200 text-xs font-medium font-['Pretendard'] leading-none">
16+
판매량
17+
</div>
18+
<div className="flex-1 p-2 justify-start text-neutral-200 text-xs font-medium font-['Pretendard'] leading-none">
19+
매출액
20+
</div>
21+
</div>
22+
{/* Table Rows */}
23+
{Array.from({ length: 5 }).map((_, index) => (
24+
<div
25+
key={index}
26+
className="self-stretch border-b border-neutral-700 last:border-b-0 inline-flex justify-start items-center"
27+
>
28+
<div className="flex-1 p-2 justify-start text-neutral-200 text-xs font-medium font-['Pretendard'] leading-none">
29+
item
30+
</div>
31+
<div className="flex-1 p-2 justify-start text-neutral-200 text-xs font-medium font-['Pretendard'] leading-none">
32+
1000
33+
</div>
34+
<div className="flex-1 p-2 justify-start text-neutral-200 text-xs font-medium font-['Pretendard'] leading-none">
35+
300,000
36+
</div>
37+
</div>
38+
))}
39+
</div>
40+
</div>
41+
</div>
42+
)
43+
}

src/renderer/src/components/workspace/workspace.tsx

Lines changed: 2 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { ChartColumn, Code2, Download } from 'lucide-react'
21
import { DbSchemaPanel } from './db-schema-panel'
32
import { AiChatPanel } from './ai-chat-panel'
3+
import { QueryPanel } from './query-panel'
44

55
const WorkSpace = (): React.JSX.Element => {
66
return (
@@ -14,80 +14,7 @@ const WorkSpace = (): React.JSX.Element => {
1414
<AiChatPanel />
1515

1616
{/* Query & Results Panel (Right) */}
17-
<div className="flex-1 h-full flex flex-col gap-2">
18-
<div className="flex-1 bg-neutral-800 outline-1 outline-offset-[-1px] outline-neutral-700 flex flex-col">
19-
<div className="self-stretch pl-4 pr-3 py-3 border-b border-neutral-700 inline-flex justify-between items-center">
20-
<div className="flex justify-start items-center gap-2">
21-
<Code2 className="size-4 stroke-[#E4E4E4]" />
22-
<div className="justify-start text-neutral-200 text-sm font-bold font-['Pretendard'] leading-tight">
23-
쿼리 편집기
24-
</div>
25-
</div>
26-
<div className="px-3 py-1.5 bg-gradient-to-b from-violet-700 to-violet-800 rounded-lg outline-1 outline-offset-[-1px] outline-white/20 flex justify-center items-center gap-2">
27-
<Download className="size-3 stroke-[#E4E4E4]" />
28-
<div className="justify-start text-neutral-200 text-xs font-semibold font-['Pretendard'] leading-none">
29-
내보내기
30-
</div>
31-
</div>
32-
</div>
33-
<div className="flex-1 p-5 overflow-auto">
34-
<div className="justify-start text-neutral-200 text-sm font-normal font-['JetBrains_Mono'] leading-tight">
35-
SELECT p.ProductName, SUM(sod.sales_quantity) as total_quantity_sold,
36-
SUM(sod.sales_quantity * sod.UnitPrice) as total_revenue FROM Products p JOIN
37-
SalesOrderDetails sod ON p.ProductID = sod.ProductID GROUP BY p.ProductID,
38-
p.ProductName ORDER BY total_revenue DESC LIMIT 5;
39-
</div>
40-
</div>
41-
</div>
42-
<div className="flex-1 bg-neutral-800 outline-1 outline-offset-[-1px] outline-neutral-700 flex flex-col">
43-
<div className="self-stretch pl-4 pr-3 py-3 border-b border-neutral-700 inline-flex justify-between items-center">
44-
<div className="flex justify-start items-center gap-2">
45-
<ChartColumn className="size-4 stroke-[#E4E4E4]" />
46-
<div className="justify-start text-neutral-200 text-sm font-bold font-['Pretendard'] leading-tight">
47-
실행 결과
48-
</div>
49-
</div>
50-
<div className="px-3 py-1.5 bg-gradient-to-b from-violet-700 to-violet-800 rounded-lg outline-1 outline-offset-[-1px] outline-white/20 flex justify-center items-center gap-2">
51-
<Download className="size-3 stroke-[#E4E4E4]" />
52-
<div className="justify-start text-neutral-200 text-xs font-semibold font-['Pretendard'] leading-none">
53-
내보내기
54-
</div>
55-
</div>
56-
</div>
57-
<div className="flex-1 p-5 overflow-auto">
58-
<div className="self-stretch rounded-lg outline-1 outline-offset-[-1px] outline-neutral-700 flex flex-col justify-start items-start overflow-hidden">
59-
<div className="self-stretch bg-neutral-700 inline-flex justify-start items-center">
60-
<div className="flex-1 p-2 justify-start text-neutral-200 text-xs font-medium font-['Pretendard'] leading-none">
61-
상품명
62-
</div>
63-
<div className="flex-1 p-2 justify-start text-neutral-200 text-xs font-medium font-['Pretendard'] leading-none">
64-
판매량
65-
</div>
66-
<div className="flex-1 p-2 justify-start text-neutral-200 text-xs font-medium font-['Pretendard'] leading-none">
67-
매출액
68-
</div>
69-
</div>
70-
{/* Table Rows */}
71-
{Array.from({ length: 5 }).map((_, index) => (
72-
<div
73-
key={index}
74-
className="self-stretch border-b border-neutral-700 last:border-b-0 inline-flex justify-start items-center"
75-
>
76-
<div className="flex-1 p-2 justify-start text-neutral-200 text-xs font-medium font-['Pretendard'] leading-none">
77-
item
78-
</div>
79-
<div className="flex-1 p-2 justify-start text-neutral-200 text-xs font-medium font-['Pretendard'] leading-none">
80-
1000
81-
</div>
82-
<div className="flex-1 p-2 justify-start text-neutral-200 text-xs font-medium font-['Pretendard'] leading-none">
83-
300,000
84-
</div>
85-
</div>
86-
))}
87-
</div>
88-
</div>
89-
</div>
90-
</div>
17+
<QueryPanel />
9118
</div>
9219
</main>
9320
)

0 commit comments

Comments
 (0)