feat: use rounded corner design

This commit is contained in:
kangfenmao 2024-09-23 09:29:09 +08:00
parent d7f8eec59e
commit 3d3410b4fd
20 changed files with 142 additions and 65 deletions

View File

@ -21,13 +21,13 @@ export const DATA_PATH = getDataPath()
export const appConfig = new Store()
export const titleBarOverlayDark = {
height: 41,
height: 40,
color: '#00000000',
symbolColor: '#ffffff'
}
export const titleBarOverlayLight = {
height: 41,
height: 40,
color: '#00000000',
symbolColor: '#000000'
}

View File

@ -27,6 +27,7 @@ export function createMainWindow() {
autoHideMenuBar: true,
transparent: process.platform === 'darwin',
vibrancy: 'fullscreen-ui',
visualEffectState: 'active',
titleBarStyle: 'hidden',
titleBarOverlay: theme === 'dark' ? titleBarOverlayDark : titleBarOverlayLight,
trafficLightPosition: { x: 8, y: 12 },

View File

@ -7,11 +7,19 @@
http-equiv="Content-Security-Policy"
content="default-src 'self'; connect-src *; script-src 'self' *; worker-src 'self' blob:; style-src 'self' 'unsafe-inline' *; font-src 'self' data: *; img-src 'self' data: file: *; frame-src * file:" />
<style>
html,
body {
margin: 0;
}
#spinner {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
position: fixed;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
background: rgba(255, 255, 255, 0.5);
}
#spinner img {
width: 100px;

View File

@ -5,12 +5,12 @@
:root {
--color-white: #ffffff;
--color-white-soft: #f8f8f8;
--color-white-mute: #f2f2f2;
--color-white-soft: rgba(255, 255, 255, 0.8);
--color-white-mute: rgba(255, 255, 255, 0.94);
--color-black: #1b1b1f;
--color-black-soft: #262626;
--color-black-mute: #363636;
--color-black: #181818;
--color-black-soft: #202020;
--color-black-mute: #262626;
--color-gray-1: #515c67;
--color-gray-2: #414853;
@ -20,9 +20,9 @@
--color-text-2: rgba(235, 235, 245, 0.6);
--color-text-3: rgba(235, 235, 245, 0.38);
--color-background: #181818;
--color-background: var(--color-black);
--color-background-soft: var(--color-black-soft);
--color-background-mute: var(--color-black-soft);
--color-background-mute: var(--color-black-mute);
--color-primary: #00b96b;
--color-primary-soft: #00b96b99;
@ -31,32 +31,33 @@
--color-text: var(--color-text-1);
--color-icon: #ffffff99;
--color-icon-white: #ffffff;
--color-border: #ffffff20;
--color-border: #ffffff24;
--color-border-soft: #ffffff20;
--color-error: #f44336;
--color-link: #1677ff;
--color-code-background: #323232;
--color-scrollbar-thumb: rgba(255, 255, 255, 0.08);
--color-scrollbar-thumb-hover: rgba(255, 255, 255, 0.15);
--color-hover: rgba(40, 40, 40, 1);
--color-active: rgba(55, 55, 55, 1);
--navbar-background-mac: rgba(30, 30, 30, 0.8);
--navbar-background-mac: rgba(30, 30, 30, 0.4);
--navbar-background: rgba(30, 30, 30);
--input-bar-background: rgba(255, 255, 255, 0.02);
--navbar-height: 42px;
--sidebar-width: 52px;
--navbar-height: 40px;
--sidebar-width: 50px;
--status-bar-height: 40px;
--input-bar-height: 85px;
--assistants-width: 280px;
--topic-list-width: 280px;
--settings-width: 260px;
--assistants-width: 275px;
--topic-list-width: 275px;
--settings-width: 250px;
}
body[theme-mode='light'] {
--color-white: #ffffff;
--color-white-soft: #f8f8f8;
--color-white-mute: #efefef;
--color-white-soft: #f2f2f2;
--color-white-mute: #eee;
--color-black: #1b1b1f;
--color-black-soft: #262626;
@ -70,7 +71,7 @@ body[theme-mode='light'] {
--color-text-2: rgba(0, 0, 0, 0.6);
--color-text-3: rgba(0, 0, 0, 0.38);
--color-background: #ffffff;
--color-background: var(--color-white);
--color-background-soft: var(--color-white-soft);
--color-background-mute: var(--color-white-mute);
@ -88,10 +89,11 @@ body[theme-mode='light'] {
--color-code-background: #e3e3e3;
--color-scrollbar-thumb: rgba(0, 0, 0, 0.08);
--color-scrollbar-thumb-hover: rgba(0, 0, 0, 0.15);
--color-hover: var(--color-white-mute);
--color-active: var(--color-white-soft);
--navbar-background-mac: rgba(255, 255, 255, 0.75);
--navbar-background-mac: rgba(255, 255, 255, 0.4);
--navbar-background: rgba(255, 255, 255);
--input-bar-background: rgba(0, 0, 0, 0.02);
}
*,
@ -121,12 +123,12 @@ body {
font-size: 14px;
line-height: 1.6;
overflow: hidden;
background: transparent !important;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',
'Helvetica Neue', sans-serif;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
transition: background-color 0.3s linear;
}
a {
@ -148,6 +150,28 @@ body,
flex: 1;
}
#content-container {
overflow: hidden;
background-color: var(--color-background);
border-top: 0.5px solid var(--color-border);
}
body[os='mac'] {
#content-container {
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
border-top-right-radius: 10px;
border-left: 0.5px solid var(--color-border);
box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.05);
}
}
body[os='windows'] {
#app-sidebar {
border-right: 0.5px solid var(--color-border);
}
}
#inputbar .ant-input {
resize: none;
}
@ -189,6 +213,7 @@ body,
}
.minapp-drawer {
max-width: calc(100vw - var(--sidebar-width));
.ant-drawer-content-wrapper {
box-shadow: none;
}
@ -196,15 +221,15 @@ body,
position: absolute;
-webkit-app-region: drag;
min-height: calc(var(--navbar-height) + 0.5px);
background: var(--navbar-background);
width: calc(100vw - var(--sidebar-width));
border-bottom: 0.5px solid var(--color-border);
margin-top: -0.5px;
border-bottom: none;
}
.ant-drawer-body {
padding: 0;
margin-top: var(--navbar-height);
overflow: hidden;
@extend #content-container;
}
.minapp-mask {
background-color: transparent !important;
@ -216,6 +241,9 @@ body,
}
.segmented-tab {
.ant-segmented-item-selected {
background-color: var(--color-background-mute);
}
.ant-segmented-item-label {
align-items: center;
display: flex;

View File

@ -5,9 +5,10 @@ import { useBridge } from '@renderer/hooks/useBridge'
import store from '@renderer/store'
import { setMinappShow } from '@renderer/store/runtime'
import { MinAppType } from '@renderer/types'
import { Drawer } from 'antd'
import { Avatar, Drawer } from 'antd'
import { WebviewTag } from 'electron'
import { useEffect, useRef, useState } from 'react'
import BeatLoader from 'react-spinners/BeatLoader'
import styled from 'styled-components'
import { TopView } from '../TopView'
@ -19,6 +20,8 @@ interface Props {
const PopupContainer: React.FC<Props> = ({ app, resolve }) => {
const [open, setOpen] = useState(true)
const [opened, setOpened] = useState(false)
const [isReady, setIsReady] = useState(false)
const webviewRef = useRef<WebviewTag | null>(null)
useBridge()
@ -74,14 +77,22 @@ const PopupContainer: React.FC<Props> = ({ app, resolve }) => {
}
}
const onLoaded = () => setIsReady(true)
webview.addEventListener('new-window', handleNewWindow)
webview.addEventListener('did-finish-load', onLoaded)
return () => {
webview.removeEventListener('new-window', handleNewWindow)
webview.removeEventListener('did-finish-load', onLoaded)
}
}
return () => {}
}, [opened])
useEffect(() => {
setTimeout(() => setOpened(true), 350)
}, [])
return (
@ -97,7 +108,13 @@ const PopupContainer: React.FC<Props> = ({ app, resolve }) => {
maskClosable={false}
closeIcon={null}
style={{ marginLeft: 'var(--sidebar-width)' }}>
<webview src={app.url} ref={webviewRef} style={WebviewStyle} allowpopups={'true' as any} />
{!isReady && (
<EmptyView>
<Avatar src={app.logo} size={80} style={{ border: '1px solid var(--color-border)', marginTop: -150 }} />
<BeatLoader color="var(--color-text-2)" size="10" style={{ marginTop: 15 }} />
</EmptyView>
)}
{opened && <webview src={app.url} ref={webviewRef} style={WebviewStyle} allowpopups={'true' as any} />}
</Drawer>
)
}
@ -163,6 +180,17 @@ const Button = styled.div`
}
`
const EmptyView = styled.div`
display: flex;
flex: 1;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background-color: var(--color-background);
`
export default class MinApp {
static topviewId = 0
static onClose = () => {}

View File

@ -99,7 +99,7 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
autoFocus
style={{ paddingLeft: 0 }}
bordered={false}
size="large"
size="middle"
/>
</HStack>
<Divider style={{ margin: 0 }} />
@ -136,13 +136,13 @@ const AgentItem = styled.div`
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 10px 15px;
padding: 8px 15px;
border-radius: 8px;
user-select: none;
margin-bottom: 8px;
cursor: pointer;
&.default {
background-color: var(--color-background-soft);
background-color: var(--color-background-mute);
}
.anticon {
font-size: 16px;
@ -162,7 +162,7 @@ const SearchIcon = styled.div`
justify-content: center;
align-items: center;
background-color: var(--color-background-soft);
margin-right: 6px;
margin-right: 2px;
`
export default class AddAssistantPopup {

View File

@ -1,18 +1,15 @@
import { isMac } from '@renderer/config/constant'
import { useSettings } from '@renderer/hooks/useSettings'
import { useRuntime } from '@renderer/hooks/useStore'
import { FC, PropsWithChildren } from 'react'
import styled from 'styled-components'
type Props = PropsWithChildren & JSX.IntrinsicElements['div']
export const Navbar: FC<Props> = ({ children, ...props }) => {
const { minappShow } = useRuntime()
const { windowStyle } = useSettings()
const macTransparentWindow = isMac && windowStyle === 'transparent'
const navbarBgColor = macTransparentWindow ? 'var(--navbar-background-mac)' : 'var(--navbar-background)'
const backgroundColor = minappShow ? 'var(--navbar-background)' : navbarBgColor
const backgroundColor = macTransparentWindow ? 'transparent' : 'var(--navbar-background)'
return (
<NavbarContainer {...props} style={{ backgroundColor }}>
@ -41,7 +38,6 @@ const NavbarContainer = styled.div`
max-height: var(--navbar-height);
margin-left: ${isMac ? 'calc(var(--sidebar-width) * -1)' : 0};
padding-left: ${isMac ? 'var(--sidebar-width)' : 0};
border-bottom: 0.5px solid var(--color-border);
transition: background-color 0.3s ease;
-webkit-app-region: drag;
`

View File

@ -27,7 +27,7 @@ const Sidebar: FC = () => {
const onEditUser = () => UserPopup.show()
const macTransparentWindow = isMac && windowStyle === 'transparent'
const sidebarBgColor = macTransparentWindow ? 'var(--navbar-background-mac)' : 'var(--navbar-background)'
const sidebarBgColor = macTransparentWindow ? 'transparent' : 'var(--navbar-background)'
const to = (path: string) => {
if (generating) {
@ -39,8 +39,9 @@ const Sidebar: FC = () => {
return (
<Container
id="app-sidebar"
style={{
backgroundColor: minappShow ? 'var(--navbar-background)' : sidebarBgColor,
backgroundColor: sidebarBgColor,
zIndex: minappShow ? 10000 : 'initial'
}}>
<AvatarImg src={avatar || UserAvatar} draggable={false} className="nodrag" onClick={onEditUser} />
@ -93,7 +94,6 @@ const Container = styled.div`
min-width: var(--sidebar-width);
height: ${isMac ? 'calc(100vh - var(--navbar-height))' : '100vh'};
-webkit-app-region: drag !important;
border-right: 0.5px solid var(--color-border);
margin-top: ${isMac ? 'var(--navbar-height)' : 0};
transition: background-color 0.3s ease;
`
@ -103,7 +103,7 @@ const AvatarImg = styled(Avatar)`
height: 32px;
background-color: var(--color-background-soft);
margin-bottom: ${isMac ? '12px' : '12px'};
margin-top: ${isMac ? '5px' : '2px'};
margin-top: ${isMac ? '-5px' : '2px'};
border: none;
cursor: pointer;
`
@ -140,7 +140,7 @@ const Icon = styled.div`
font-size: 17px;
}
&:hover {
background-color: var(--color-background-soft);
background-color: var(--color-hover);
cursor: pointer;
.iconfont,
.anticon {
@ -148,7 +148,7 @@ const Icon = styled.div`
}
}
&.active {
background-color: var(--color-background-mute);
background-color: var(--color-active);
.iconfont,
.anticon {
color: var(--color-icon-white);

View File

@ -1,3 +1,4 @@
import { isMac } from '@renderer/config/constant'
import { useSettings } from '@renderer/hooks/useSettings'
import { ThemeMode } from '@renderer/types'
import React, { createContext, PropsWithChildren, useContext, useEffect, useState } from 'react'
@ -37,6 +38,10 @@ export const ThemeProvider: React.FC<PropsWithChildren> = ({ children }) => {
window.api?.setTheme(_theme === ThemeMode.dark ? 'dark' : 'light')
}, [_theme])
useEffect(() => {
document.body.setAttribute('os', isMac ? 'mac' : 'windows')
}, [])
return <ThemeContext.Provider value={{ theme: _theme, toggleTheme }}>{children}</ThemeContext.Provider>
}

View File

@ -1,3 +1,4 @@
import { isMac } from '@renderer/config/constant'
import { isLocalAi } from '@renderer/config/env'
import db from '@renderer/databases'
import i18n from '@renderer/i18n'
@ -9,10 +10,12 @@ import { useEffect } from 'react'
import { useDefaultModel } from './useAssistant'
import { useSettings } from './useSettings'
import { useRuntime } from './useStore'
export function useAppInit() {
const dispatch = useAppDispatch()
const { proxyUrl, language } = useSettings()
const { proxyUrl, language, windowStyle } = useSettings()
const { minappShow } = useRuntime()
const { setDefaultModel, setTopicNamingModel, setTranslateModel } = useDefaultModel()
const avatar = useLiveQuery(() => db.settings.get('image://avatar'))
@ -36,6 +39,13 @@ export function useAppInit() {
i18n.changeLanguage(language || navigator.language || 'en-US')
}, [language])
useEffect(() => {
const transparentWindow = windowStyle === 'transparent' && isMac && !minappShow
window.document.body.style.background = transparentWindow
? 'var(--navbar-background-mac)'
: 'var(--navbar-background)'
}, [windowStyle, minappShow])
useEffect(() => {
if (isLocalAi) {
const model = JSON.parse(import.meta.env.VITE_RENDERER_INTEGRATED_MODEL)

View File

@ -54,7 +54,7 @@ const AppsPage: FC = () => {
<Navbar>
<NavbarCenter style={{ borderRight: 'none' }}>{t('agents.title')}</NavbarCenter>
</Navbar>
<ContentContainer>
<ContentContainer id="content-container">
<AssistantsContainer>
<HStack alignItems="center" style={{ marginBottom: 16 }}>
<Title level={4}>{t('agents.my_agents')}</Title>
@ -98,7 +98,6 @@ const ContentContainer = styled.div`
justify-content: center;
height: 100%;
overflow-y: scroll;
background-color: var(--color-background);
`
const AssistantsContainer = styled.div`

View File

@ -39,7 +39,7 @@ const AppsPage: FC = () => {
<div style={{ width: 80 }} />
</NavbarCenter>
</Navbar>
<ContentContainer>
<ContentContainer id="content-container">
<AppsContainer>
{filteredApps.map((app) => (
<App key={app.id} app={app} />
@ -69,7 +69,6 @@ const ContentContainer = styled.div`
justify-content: center;
height: 100%;
overflow-y: scroll;
background-color: var(--color-background);
padding: 50px;
`

View File

@ -64,7 +64,7 @@ const FilesPage: FC = () => {
<Navbar>
<NavbarCenter style={{ borderRight: 'none' }}>{t('files.title')}</NavbarCenter>
</Navbar>
<ContentContainer>
<ContentContainer id="content-container">
<VStack style={{ flex: 1 }}>
<Table dataSource={dataSource} columns={columns} style={{ width: '100%', height: '100%' }} size="small" />
</VStack>
@ -87,7 +87,6 @@ const ContentContainer = styled.div`
justify-content: center;
height: 100%;
overflow-y: scroll;
background-color: var(--color-background);
padding: 20px;
`

View File

@ -47,6 +47,7 @@ const Container = styled.div`
height: 100%;
flex: 1;
justify-content: space-between;
background-color: var(--color-background);
`
const Main = styled(Flex)`

View File

@ -22,7 +22,7 @@ const HomePage: FC = () => {
return (
<Container>
<Navbar activeAssistant={activeAssistant} activeTopic={activeTopic} setActiveTopic={setActiveTopic} />
<ContentContainer>
<ContentContainer id="content-container">
{showAssistants && (
<RightSidebar
activeAssistant={activeAssistant}
@ -53,7 +53,6 @@ const ContentContainer = styled.div`
display: flex;
flex: 1;
flex-direction: row;
background-color: var(--color-background);
`
export default HomePage

View File

@ -354,8 +354,6 @@ const InputBarContainer = styled.div`
position: relative;
margin: 0 20px 15px 20px;
border-radius: 10px;
&.focus {
}
`
const Textarea = styled(TextArea)`

View File

@ -103,7 +103,7 @@ export const NewButton = styled.div`
transition: all 0.2s ease-in-out;
cursor: pointer;
.iconfont {
font-size: 19px;
font-size: 18px;
color: var(--color-icon);
&.icon-a-addchat {
font-size: 20px;
@ -114,7 +114,7 @@ export const NewButton = styled.div`
}
.anticon {
color: var(--color-icon);
font-size: 17px;
font-size: 16px;
}
&:hover {
background-color: var(--color-background-mute);

View File

@ -37,7 +37,8 @@ const RightSidebar: FC<Props> = ({ activeAssistant, activeTopic, setActiveAssist
const { t } = useTranslation()
const borderStyle = '0.5px solid var(--color-border)'
const border = position === 'left' ? { borderRight: borderStyle } : { borderLeft: borderStyle }
const border =
position === 'left' ? { borderRight: borderStyle } : { borderLeft: borderStyle, borderTopLeftRadius: 0 }
if (position === 'left' && topicPosition === 'left') {
_tab = tab
@ -98,7 +99,13 @@ const RightSidebar: FC<Props> = ({ activeAssistant, activeTopic, setActiveAssist
<Segmented
value={tab}
className="segmented-tab"
style={{ borderRadius: 0, padding: '10px', gap: 2, borderBottom: borderStyle }}
style={{
borderRadius: 0,
padding: '10px 0',
margin: '0 10px',
borderBottom: '0.5px solid var(--color-border)',
gap: 2
}}
options={
[
position === 'left' && topicPosition === 'left' ? assistantTab : undefined,
@ -141,6 +148,7 @@ const Container = styled.div`
flex-direction: column;
width: var(--assistants-width);
height: calc(100vh - var(--navbar-height));
overflow: hidden;
.collapsed {
width: 0;
border-left: none;

View File

@ -23,7 +23,7 @@ const SettingsPage: FC = () => {
<Navbar>
<NavbarCenter style={{ borderRight: 'none' }}>{t('settings.title')}</NavbarCenter>
</Navbar>
<ContentContainer>
<ContentContainer id="content-container">
<SettingMenus>
{!isLocalAi && (
<>
@ -84,7 +84,6 @@ const ContentContainer = styled.div`
display: flex;
flex: 1;
flex-direction: row;
background-color: var(--color-background);
`
const SettingMenus = styled.ul`

View File

@ -164,7 +164,7 @@ const TranslatePage: FC = () => {
<Navbar>
<NavbarCenter style={{ borderRight: 'none' }}>{t('translate.title')}</NavbarCenter>
</Navbar>
<ContentContainer>
<ContentContainer id="content-container">
<MenuContainer>
<Select
showSearch
@ -239,7 +239,6 @@ const ContentContainer = styled.div`
flex-direction: column;
height: 100%;
padding: 20px;
background-color: var(--color-background);
`
const MenuContainer = styled.div`