diff --git a/apps/main/src/electron/electron.service.ts b/apps/main/src/electron/electron.service.ts
index e6a2a6c..68964a4 100644
--- a/apps/main/src/electron/electron.service.ts
+++ b/apps/main/src/electron/electron.service.ts
@@ -62,6 +62,11 @@ export class ElectronService implements OnApplicationBootstrap {
width: 1300,
height: 800,
minWidth: 500,
+ titleBarStyle: 'hidden',
+ trafficLightPosition: {
+ x: 15,
+ y: 13,
+ },
webPreferences: {
preload:
process.env.NODE_ENV === 'production'
diff --git a/apps/renderer/package.json b/apps/renderer/package.json
index 2549127..814d374 100644
--- a/apps/renderer/package.json
+++ b/apps/renderer/package.json
@@ -14,6 +14,7 @@
"@emotion/css": "^11.11.2",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
+ "@mui/icons-material": "^6.1.6",
"@mui/material": "^5.14.5",
"apollo-link-logger": "^2.0.1",
"graphql": "^16.9.0",
diff --git a/apps/renderer/src/components/App.tsx b/apps/renderer/src/components/App.tsx
index 8e99169..a5a2cc3 100644
--- a/apps/renderer/src/components/App.tsx
+++ b/apps/renderer/src/components/App.tsx
@@ -5,19 +5,15 @@ import { ThemeProvider } from '@mui/material'
import { ApolloProvider } from '@apollo/client'
import apolloClient from '@graphql/client'
-import { theme } from '@styles/theme'
-
-import { Layout } from '@components/Layout'
+import { darkTheme } from '@styles/theme'
import { Routes } from '@pages'
export function App() {
return (
-
-
-
-
+
+
)
diff --git a/apps/renderer/src/components/Layout.styles.tsx b/apps/renderer/src/components/Layout.styles.tsx
index da2e041..22327bb 100644
--- a/apps/renderer/src/components/Layout.styles.tsx
+++ b/apps/renderer/src/components/Layout.styles.tsx
@@ -1,5 +1,6 @@
import styled from '@emotion/styled'
import { css } from '@emotion/react'
+import { NAVIGATOR_WIDTH, TITLE_BAR_HEIGHT } from '@constants/layout'
export const GlobalStyles = css`
html,
@@ -12,3 +13,15 @@ export const GlobalStyles = css`
export const Root = styled.div`
height: 100%;
`
+
+export const Content = styled.div`
+ padding: ${({ theme }) => theme.spacing(2)};
+
+ position: fixed;
+ top: ${({ theme }) => theme.spacing(TITLE_BAR_HEIGHT)};
+ left: ${({ theme }) => theme.spacing(NAVIGATOR_WIDTH)};
+ right: 0;
+ bottom: 0;
+
+ overflow: auto;
+`
diff --git a/apps/renderer/src/components/Layout.tsx b/apps/renderer/src/components/Layout.tsx
index 574ecd5..1ba8342 100644
--- a/apps/renderer/src/components/Layout.tsx
+++ b/apps/renderer/src/components/Layout.tsx
@@ -1,18 +1,24 @@
import React from 'react'
+import { Outlet } from 'react-router-dom'
import { Global } from '@emotion/react'
import { CssBaseline } from '@mui/material'
-import { GlobalStyles, Root } from '@components/Layout.styles'
+import TitleBar from '@components/TitleBar'
+import Navigator from '@components/Navigator'
-export interface LayoutProps {}
+import * as Styled from '@components/Layout.styles'
-export function Layout({ children }: React.PropsWithChildren) {
+export function Layout() {
return (
-
-
+
+
- {children}
-
+
+
+
+
+
+
)
}
diff --git a/apps/renderer/src/components/Navigator.styled.ts b/apps/renderer/src/components/Navigator.styled.ts
new file mode 100644
index 0000000..033f743
--- /dev/null
+++ b/apps/renderer/src/components/Navigator.styled.ts
@@ -0,0 +1,17 @@
+import styled from '@emotion/styled'
+
+import { NAVIGATOR_WIDTH, TITLE_BAR_HEIGHT } from '@constants/layout'
+
+export const Root = styled.div`
+ width: ${({ theme }) => theme.spacing(NAVIGATOR_WIDTH)};
+
+ padding: ${({ theme }) => theme.spacing(1)};
+ border-right: 1px solid #505153;
+
+ position: fixed;
+ top: ${({ theme }) => theme.spacing(TITLE_BAR_HEIGHT)};
+ left: 0;
+ bottom: 0;
+
+ background-color: #3f4042;
+`
diff --git a/apps/renderer/src/components/Navigator.tsx b/apps/renderer/src/components/Navigator.tsx
new file mode 100644
index 0000000..86cc01a
--- /dev/null
+++ b/apps/renderer/src/components/Navigator.tsx
@@ -0,0 +1,66 @@
+import React from 'react'
+import { Link, useLocation } from 'react-router-dom'
+
+import { Box, IconButton, Stack, Tooltip } from '@mui/material'
+
+import { NAVIGATOR_ITEMS } from '@constants/navigator'
+
+import * as Styled from './Navigator.styled'
+
+interface NavigatorProps {}
+
+function Navigator({}: NavigatorProps) {
+ const location = useLocation()
+
+ return (
+
+
+ {NAVIGATOR_ITEMS.map(({ path, label, icon: Icon }) => (
+
+
+
+
+ theme.transitions.create(['color'], {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.shorter,
+ }),
+ }}
+ />
+
+
+
+ ))}
+
+
+ )
+}
+
+export default Navigator
diff --git a/apps/renderer/src/components/TitleBar.styled.ts b/apps/renderer/src/components/TitleBar.styled.ts
new file mode 100644
index 0000000..70819d3
--- /dev/null
+++ b/apps/renderer/src/components/TitleBar.styled.ts
@@ -0,0 +1,14 @@
+import styled from '@emotion/styled'
+
+import { TITLE_BAR_HEIGHT } from '@constants/layout'
+
+export const Root = styled.div`
+ height: ${({ theme }) => theme.spacing(TITLE_BAR_HEIGHT)};
+
+ border-bottom: 1px solid #505153;
+
+ background-color: #3f4042;
+
+ -webkit-app-region: drag;
+ user-select: none;
+`
diff --git a/apps/renderer/src/components/TitleBar.tsx b/apps/renderer/src/components/TitleBar.tsx
new file mode 100644
index 0000000..d98ee22
--- /dev/null
+++ b/apps/renderer/src/components/TitleBar.tsx
@@ -0,0 +1,11 @@
+import React from 'react'
+
+import * as Styled from './TitleBar.styled'
+
+interface TitleBarProps {}
+
+function TitleBar({}: TitleBarProps) {
+ return
+}
+
+export default TitleBar
diff --git a/apps/renderer/src/constants/layout.ts b/apps/renderer/src/constants/layout.ts
new file mode 100644
index 0000000..5952d1f
--- /dev/null
+++ b/apps/renderer/src/constants/layout.ts
@@ -0,0 +1,2 @@
+export const TITLE_BAR_HEIGHT = 5 // 40px
+export const NAVIGATOR_WIDTH = 8 // 64px
diff --git a/apps/renderer/src/constants/navigator.ts b/apps/renderer/src/constants/navigator.ts
new file mode 100644
index 0000000..0310468
--- /dev/null
+++ b/apps/renderer/src/constants/navigator.ts
@@ -0,0 +1,25 @@
+import React from 'react'
+
+import HomeRounded from '@mui/icons-material/HomeRounded'
+import SearchRounded from '@mui/icons-material/SearchRounded'
+
+import { SvgIconProps } from '@mui/material'
+
+export interface NavigatorItem {
+ icon: React.ComponentType
+ label: string
+ path: string
+}
+
+export const NAVIGATOR_ITEMS: NavigatorItem[] = [
+ {
+ icon: HomeRounded,
+ label: 'Home',
+ path: '/',
+ },
+ {
+ icon: SearchRounded,
+ label: 'Search',
+ path: '/search',
+ },
+]
diff --git a/apps/renderer/src/emotion.d.ts b/apps/renderer/src/emotion.d.ts
new file mode 100644
index 0000000..9c2507e
--- /dev/null
+++ b/apps/renderer/src/emotion.d.ts
@@ -0,0 +1,5 @@
+import { createTheme } from '@mui/material'
+
+declare module '@emotion/react' {
+ export interface Theme extends ReturnType {}
+}
diff --git a/apps/renderer/src/pages/Search.styled.ts b/apps/renderer/src/pages/Search.styled.ts
new file mode 100644
index 0000000..9048e73
--- /dev/null
+++ b/apps/renderer/src/pages/Search.styled.ts
@@ -0,0 +1,3 @@
+import styled from '@emotion/styled'
+
+export const Root = styled.div``
diff --git a/apps/renderer/src/pages/Search.tsx b/apps/renderer/src/pages/Search.tsx
new file mode 100644
index 0000000..7563b8a
--- /dev/null
+++ b/apps/renderer/src/pages/Search.tsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+import * as Styled from './Search.styled'
+
+interface SearchProps {}
+
+export function Search({}: SearchProps) {
+ return Search
+}
diff --git a/apps/renderer/src/pages/index.tsx b/apps/renderer/src/pages/index.tsx
index 4bdc093..77bd487 100644
--- a/apps/renderer/src/pages/index.tsx
+++ b/apps/renderer/src/pages/index.tsx
@@ -1,14 +1,26 @@
import React from 'react'
import { createHashRouter, createRoutesFromElements, Route, RouterProvider } from 'react-router-dom'
+import { Layout } from '@components/Layout'
+
import { Home } from '@pages/Home'
+import { Search } from '@pages/Search'
const router = createHashRouter(
createRoutesFromElements(
}
- />,
+ element={}
+ >
+ }
+ />
+ }
+ />
+ ,
),
)
diff --git a/apps/renderer/src/styles/theme.ts b/apps/renderer/src/styles/theme.ts
index 79b0c3e..1979837 100644
--- a/apps/renderer/src/styles/theme.ts
+++ b/apps/renderer/src/styles/theme.ts
@@ -1,3 +1,10 @@
import { createTheme } from '@mui/material'
-export const theme = createTheme()
+export const darkTheme = createTheme({
+ palette: {
+ mode: 'dark',
+ background: {
+ default: '#242428',
+ },
+ },
+})
diff --git a/apps/renderer/tsconfig.json b/apps/renderer/tsconfig.json
index aa5b7ba..f918db1 100644
--- a/apps/renderer/tsconfig.json
+++ b/apps/renderer/tsconfig.json
@@ -8,7 +8,8 @@
"@pages": ["src/pages"],
"@pages/*": ["src/pages/*"],
"@components/*": ["src/components/*"],
- "@styles/*": ["src/styles/*"]
+ "@styles/*": ["src/styles/*"],
+ "@constants/*": ["src/constants/*"],
}
},
"include": ["src"]
diff --git a/packages/tsconfig/renderer.json b/packages/tsconfig/renderer.json
index 51618a8..74bfc75 100644
--- a/packages/tsconfig/renderer.json
+++ b/packages/tsconfig/renderer.json
@@ -6,7 +6,7 @@
"noUnusedParameters": true,
"noImplicitReturns": true,
"moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
+ "allowImportingTsExtensions": false,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5fb37d7..f3dca6d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -229,6 +229,9 @@ importers:
'@emotion/styled':
specifier: ^11.11.0
version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.20)(react@18.2.0)
+ '@mui/icons-material':
+ specifier: ^6.1.6
+ version: 6.1.6(@mui/material@5.14.5)(@types/react@18.2.20)(react@18.2.0)
'@mui/material':
specifier: ^5.14.5
version: 5.14.5(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.20)(react-dom@18.2.0)(react@18.2.0)
@@ -1392,6 +1395,13 @@ packages:
dependencies:
regenerator-runtime: 0.14.0
+ /@babel/runtime@7.26.0:
+ resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ regenerator-runtime: 0.14.0
+ dev: false
+
/@babel/template@7.22.5:
resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==}
engines: {node: '>=6.9.0'}
@@ -3018,6 +3028,23 @@ packages:
resolution: {integrity: sha512-+wpGH1USwPcKMFPMvXqYPC6fEvhxM3FzxC8lyDiNK/imLyyJ6y2DPb1Oue7OGIKJWBmYBqrWWtfovrxd1aJHTA==}
dev: false
+ /@mui/icons-material@6.1.6(@mui/material@5.14.5)(@types/react@18.2.20)(react@18.2.0):
+ resolution: {integrity: sha512-5r9urIL2lxXb/sPN3LFfFYEibsXJUb986HhhIeu1gOcte460pwdSiEhBSxkAuyT8Dj7jvu9MjqSBmSumQELo8A==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@mui/material': ^6.1.6
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.26.0
+ '@mui/material': 5.14.5(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.20)(react-dom@18.2.0)(react@18.2.0)
+ '@types/react': 18.2.20
+ react: 18.2.0
+ dev: false
+
/@mui/material@5.14.5(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.20)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-4qa4GMfuZH0Ai3mttk5ccXP8a3sf7aPlAJwyMrUSz6h9hPri6BPou94zeu3rENhhmKLby9S/W1y+pmficy8JKA==}
engines: {node: '>=12.0.0'}