diff --git a/eslint.config.js b/eslint.config.js
index 092408a..82ee3d1 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -19,6 +19,8 @@ export default tseslint.config(
},
rules: {
...reactHooks.configs.recommended.rules,
+ 'no-empty-pattern': 'off',
+ '@typescript-eslint/no-empty-object-type': 'off',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
diff --git a/src/App.styled.ts b/src/App.styled.ts
index 98b23f3..8f8ee95 100644
--- a/src/App.styled.ts
+++ b/src/App.styled.ts
@@ -27,6 +27,7 @@ export const Content = styled.div<{ isReady: boolean }>`
box-sizing: border-box;
display: flex;
+ flex-direction: column;
justify-content: center;
align-items: center;
diff --git a/src/App.tsx b/src/App.tsx
index 1f449a8..c436289 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -13,6 +13,7 @@ import useSessionAppStore from '@stores/session-app'
import useAppStore from '@stores/app'
import * as Styled from './App.styled'
+import SearchBar from '@components/SearchBar'
function App() {
const isReady = useSessionAppStore((store) => store.isReady)
@@ -51,6 +52,7 @@ function App() {
+
diff --git a/src/components/Box.styled.ts b/src/components/Box.styled.ts
new file mode 100644
index 0000000..8fe91cd
--- /dev/null
+++ b/src/components/Box.styled.ts
@@ -0,0 +1,7 @@
+import styled from '@emotion/styled'
+
+export const Root = styled.div`
+ border-radius: 4px;
+
+ background-color: rgba(255, 255, 255, 0.3);
+`
diff --git a/src/components/Box.tsx b/src/components/Box.tsx
new file mode 100644
index 0000000..e6a550a
--- /dev/null
+++ b/src/components/Box.tsx
@@ -0,0 +1,11 @@
+import React from 'react'
+
+import * as Styled from './Box.styled'
+
+interface BoxProps extends React.HTMLAttributes {}
+
+function Box(props: BoxProps) {
+ return
+}
+
+export default Box
diff --git a/src/components/IconTab.styled.ts b/src/components/IconTab.styled.ts
new file mode 100644
index 0000000..03b7356
--- /dev/null
+++ b/src/components/IconTab.styled.ts
@@ -0,0 +1,25 @@
+import styled from '@emotion/styled'
+
+export const Root = styled.div`
+ display: flex;
+`
+
+export const Item = styled.button<{ selected: boolean }>`
+ margin: 0;
+ padding: ${({ theme }) => theme.spacing(0.75)};
+ border: 0;
+
+ background-color: rgba(255, 255, 255, 0.3);
+
+ cursor: pointer;
+ opacity: ${({ selected }) => (selected ? 1 : 0.5)};
+
+ > svg {
+ width: 20px;
+ height: 20px;
+
+ display: block;
+
+ fill: white;
+ }
+`
diff --git a/src/components/IconTab.tsx b/src/components/IconTab.tsx
new file mode 100644
index 0000000..88393b7
--- /dev/null
+++ b/src/components/IconTab.tsx
@@ -0,0 +1,36 @@
+import React from 'react'
+
+import * as Styled from './IconTab.styled'
+
+export interface IconTabItem {
+ value: TValue
+ icon: React.ComponentType
+}
+
+interface IconTabProps {
+ value: TValue
+ onChange: (value: TValue) => void
+ items: IconTabItem[]
+}
+
+function IconTab({
+ value: currentValue,
+ items,
+ onChange,
+}: IconTabProps) {
+ return (
+
+ {items.map(({ icon: Icon, value }) => (
+ onChange(value)}
+ selected={value === currentValue}
+ >
+
+
+ ))}
+
+ )
+}
+
+export default IconTab
diff --git a/src/components/SearchBar.styled.ts b/src/components/SearchBar.styled.ts
new file mode 100644
index 0000000..faf2714
--- /dev/null
+++ b/src/components/SearchBar.styled.ts
@@ -0,0 +1,48 @@
+import styled from '@emotion/styled'
+
+import Box from '@components/Box'
+
+export const Root = styled(Box)`
+ width: 100%;
+ max-width: 764px;
+
+ margin-top: ${({ theme }) => theme.spacing(6)};
+ border-top-left-radius: 0;
+
+ position: relative;
+`
+
+export const Input = styled.input`
+ width: 100%;
+
+ margin: 0;
+ padding: ${({ theme }) => theme.spacing(1.5, 2)};
+ border: 0;
+
+ display: block;
+ box-sizing: border-box;
+
+ font-family: 'SUITE Variable', sans-serif;
+
+ color: white;
+ background-color: transparent;
+
+ outline: none;
+
+ ::placeholder {
+ color: rgba(255, 255, 255, 0.5);
+ }
+`
+
+export const IconTabWrapper = styled.div`
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+
+ position: absolute;
+ top: 0;
+ left: 0;
+
+ overflow: hidden;
+
+ transform: translateY(-100%);
+`
diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx
new file mode 100644
index 0000000..d4a7815
--- /dev/null
+++ b/src/components/SearchBar.tsx
@@ -0,0 +1,64 @@
+import React from 'react'
+import { RiOpenaiFill, RiGoogleFill } from 'react-icons/ri'
+
+import IconTab, { IconTabItem } from '@components/IconTab'
+
+import * as Styled from './SearchBar.styled'
+
+type SearchEngine = 'google' | 'chatgpt'
+
+const SEARCH_ENGiNE_ITEMS: IconTabItem[] = [
+ {
+ value: 'google',
+ icon: RiGoogleFill,
+ },
+ {
+ value: 'chatgpt',
+ icon: RiOpenaiFill,
+ },
+]
+
+const PLACEHOLDER_TEXT: Record = {
+ google: 'Search Google...',
+ chatgpt: 'Ask ChatGPT...',
+}
+
+function SearchBar() {
+ const [query, setQuery] = React.useState('')
+ const [searchEngine, setSearchEngine] = React.useState('google')
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setQuery(event.target.value)
+ }
+
+ const handleKeyDown = (event: React.KeyboardEvent) => {
+ if (event.key === 'Enter') {
+ if (searchEngine === 'google') {
+ location.href = `https://www.google.com/search?q=${query}`
+ } else if (searchEngine === 'chatgpt') {
+ location.href = `https://chat.openai.com/?q=${query}`
+ }
+ }
+ }
+
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default SearchBar
diff --git a/tsconfig.app.json b/tsconfig.app.json
index c95cefd..0bee672 100644
--- a/tsconfig.app.json
+++ b/tsconfig.app.json
@@ -9,7 +9,7 @@
/* Bundler mode */
"moduleResolution": "Bundler",
- "allowImportingTsExtensions": true,
+ "allowImportingTsExtensions": false,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,