diff --git a/src/components/Sider/ChatSider/index.tsx b/src/components/Sider/ChatSider/index.tsx index 2a96748..5b253f0 100644 --- a/src/components/Sider/ChatSider/index.tsx +++ b/src/components/Sider/ChatSider/index.tsx @@ -6,7 +6,7 @@ import ChatItem from './ChatItem' function ChatSider() { const chats = [ { - id: 'test-chat', + _id: 'test-chat', avatar: 'https://avatars.githubusercontent.com/u/74760542?v=4', nickname: 'Test User', note: 'Test User', @@ -26,7 +26,7 @@ function ChatSider() {
{chats.map(chat => ( ))} diff --git a/src/components/Sider/ContactSider/ContactItem/index.module.less b/src/components/Sider/ContactSider/ContactItem/index.module.less new file mode 100644 index 0000000..3c4a3c4 --- /dev/null +++ b/src/components/Sider/ContactSider/ContactItem/index.module.less @@ -0,0 +1,6 @@ +@import url("@/themes/index.less"); + +.contactItem { + padding: 10px; + background-color: @colorPrimary; +} \ No newline at end of file diff --git a/src/components/Sider/ContactSider/ContactItem/index.tsx b/src/components/Sider/ContactSider/ContactItem/index.tsx new file mode 100644 index 0000000..0a5631d --- /dev/null +++ b/src/components/Sider/ContactSider/ContactItem/index.tsx @@ -0,0 +1,48 @@ +import { Badge, Flex, Typography } from 'antd' +import { useNavigate } from 'react-router-dom' +import { useMeasure } from 'react-use' +import styles from './index.module.less' +import type { Contact } from '@/typings' +import { useThemeToken, useTime } from '@/hooks' + +interface ContactItemProps { + contact: Contact +} + +function ContactItem({ contact }: ContactItemProps) { + const [ref, { width }] = useMeasure() + const { token } = useThemeToken() + const time = useTime() + const { updatedAt, avatar, sender, count, note, nickname, message } = contact + const navigate = useNavigate() + + return ( + { + navigate(`/contact/${contact.id}`) + }} + gap={10} + className={styles.contactItem} + > +
+ +
+ + + {note || nickname} + {time(updatedAt).fromNow()} + + + + {sender ? `${sender}:` : ''} + {message} + + + + +
+ ) +} + +export default ContactItem diff --git a/src/components/Sider/ContactSider/index.module.less b/src/components/Sider/ContactSider/index.module.less new file mode 100644 index 0000000..48bb509 --- /dev/null +++ b/src/components/Sider/ContactSider/index.module.less @@ -0,0 +1,14 @@ +.sider { + display: flex; + flex-direction: column; + height: 100%; + + .topBar { + padding: 20px 10px; + background-color: #fff; + } + + .list { + flex: 1; + } +} \ No newline at end of file diff --git a/src/components/Sider/ContactSider/index.tsx b/src/components/Sider/ContactSider/index.tsx index d0789f5..4abe3b7 100644 --- a/src/components/Sider/ContactSider/index.tsx +++ b/src/components/Sider/ContactSider/index.tsx @@ -1,8 +1,39 @@ -import React from 'react' +import { PlusOutlined } from '@ant-design/icons' +import { Button, Flex, Input } from 'antd' +import { useNavigate } from 'react-router-dom' +import ContactItem from './ContactItem' +import styles from './index.module.less' +import type { Contact } from '@/typings' function ContactSider() { + const navigate = useNavigate() + const contacts = [ + { + _id: '1234', + }, + ] as Contact[] + return ( -
ContactSider
+
+ + +
) } diff --git a/src/layouts/BasicLayout.tsx b/src/layouts/BasicLayout.tsx index 5a18f62..b3d86a2 100644 --- a/src/layouts/BasicLayout.tsx +++ b/src/layouts/BasicLayout.tsx @@ -1,11 +1,32 @@ import { MessageOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons' +import type { GlobalToken } from 'antd' import { ConfigProvider, Layout, Menu } from 'antd' import { useEffect, useState } from 'react' import { useLocation, useNavigate } from 'react-router-dom' -import { useAppStore } from '@/hooks' +import { useAppStore, useThemeToken } from '@/hooks' import { AUTH_TOKEN_KEY } from '@/config' import Loading from '@/components/Loading' +function AddThemeToVars() { + const { token: realToken } = useThemeToken() + + useEffect(() => { + realToken.fontSizeSM = 12 + const usefulToken = Object.keys(realToken).filter(_ => !/-[0-9]/.test(_)) + usefulToken.forEach((key) => { + const needUnit = ['borderRadius', 'fontSize', 'size'] + document.documentElement.style.setProperty( + `--${key}`, + needUnit.some(item => key.startsWith(item)) + ? `${realToken[key as (keyof GlobalToken)]}px` as string + : realToken[key as (keyof GlobalToken)] as string, + ) + }) + }, [realToken]) + + return null +} + function BasicLayout(props: any) { const navigate = useNavigate() const { pathname } = useLocation() @@ -33,6 +54,7 @@ function BasicLayout(props: any) { }, }} > + ContactDetail
+ ) +} + +export default ContactDetail diff --git a/src/pages/Contact/ContactSearch/index.tsx b/src/pages/Contact/ContactSearch/index.tsx new file mode 100644 index 0000000..7bca055 --- /dev/null +++ b/src/pages/Contact/ContactSearch/index.tsx @@ -0,0 +1,7 @@ +function ContactSearch() { + return ( +
ContactSearch
+ ) +} + +export default ContactSearch diff --git a/src/pages/Contact/index.tsx b/src/pages/Contact/index.tsx index 167842a..df7081a 100644 --- a/src/pages/Contact/index.tsx +++ b/src/pages/Contact/index.tsx @@ -1,11 +1,11 @@ import ContactSider from '@/components/Sider/ContactSider' import MainLayout from '@/layouts/MainLayout' -function Contact() { +function Contact(props: any) { return ( -
联系人
+ {props.children}
) } diff --git a/src/router/routes.tsx b/src/router/routes.tsx index 481896c..11c4528 100644 --- a/src/router/routes.tsx +++ b/src/router/routes.tsx @@ -6,6 +6,8 @@ import Contact from '@/pages/Contact' import Home from '@/pages/Home' import Login from '@/pages/Login' import Setting from '@/pages/Setting' +import ContactDetail from '@/pages/Contact/ContactDetail' +import ContactSearch from '@/pages/Contact/ContactSearch' const routes: RouteObject[] = [ { @@ -34,11 +36,17 @@ const routes: RouteObject[] = [ }, { path: 'contact', - element: , + element: + + , children: [ { path: ':id', - element: , + element: , + }, + { + path: 'search', + element: , }, ], }, diff --git a/src/themes/custom.less b/src/themes/custom.less new file mode 100644 index 0000000..1d7ec8a --- /dev/null +++ b/src/themes/custom.less @@ -0,0 +1,12 @@ +@scrollbar-height: var(--scrollbar-height); +@scrollbar-color: var(--scrollbar-color); +@scrollbar-track-color: var(--scrollbar-track-color); +@scrollbar-hover-color: var(--scrollbar-hover-color); +@scrollbar-border-radius: var(--scrollbar-border-radius); +@transition: var(--motionDurationMid) var(--motionEaseInOut); +@boxShadow: var(--box-shadow); +@boxShadowSecondary: var(--boxShadowSecondary); +@boxShadowCard: var(--boxShadowCard); +@headerHeight: var(--header-height); +@colorBorderBg: var(--colorBorderBg); +@colorBgTextHover: var(--colorBgTextHover); diff --git a/src/themes/default.less b/src/themes/default.less new file mode 100644 index 0000000..7bfa023 --- /dev/null +++ b/src/themes/default.less @@ -0,0 +1,275 @@ +/* +* MapToken +* https://ant.design/docs/react/customize-theme-cn#maptoken +*/ +@blue: var(--blue); +@purple: var(--purple); +@cyan: var(--cyan); +@green: var(--green); +@magenta: var(--magenta); +@pink: var(--pink); +@red: var(--red); +@orange: var(--orange); +@yellow: var(--yellow); +@volcano: var(--volcano); +@geekblue: var(--geekblue); +@gold: var(--gold); +@lime: var(--lime); +@colorPrimary: var(--colorPrimary); +@colorSuccess: var(--colorSuccess); +@colorWarning: var(--colorWarning); +@colorError: var(--colorError); +@colorInfo: var(--colorInfo); +@colorTextBase: var(--colorTextBase); +@colorBgBase: var(--colorBgBase); +@fontFamily: var(--fontFamily); +@fontFamilyCode: var(--fontFamilyCode); +@fontSize: var(--fontSize); +@lineWidth: var(--lineWidth); +@lineType: var(--lineType); +@motionUnit: var(--motionUnit); +@motionBase: var(--motionBase); +@motionEaseOutCirc: var(--motionEaseOutCirc); +@motionEaseInOutCirc: var(--motionEaseInOutCirc); +@motionEaseOut: var(--motionEaseOut); +@motionEaseInOut: var(--motionEaseInOut); +@motionEaseOutBack: var(--motionEaseOutBack); +@motionEaseInBack: var(--motionEaseInBack); +@motionEaseInQuint: var(--motionEaseInQuint); +@motionEaseOutQuint: var(--motionEaseOutQuint); +@borderRadius: var(--borderRadius); +@sizeUnit: var(--sizeUnit); +@sizeStep: var(--sizeStep); +@sizePopupArrow: var(--sizePopupArrow); +@controlHeight: var(--controlHeight); +@zIndexBase: var(--zIndexBase); +@zIndexPopupBase: var(--zIndexPopupBase); +@opacityImage: var(--opacityImage); +@wireframe: var(--wireframe); +@blue1: var(--blue1); +@blue2: var(--blue2); +@blue3: var(--blue3); +@blue4: var(--blue4); +@blue5: var(--blue5); +@blue6: var(--blue6); +@blue7: var(--blue7); +@blue8: var(--blue8); +@blue9: var(--blue9); +@blue10: var(--blue10); +@purple1: var(--purple1); +@purple2: var(--purple2); +@purple3: var(--purple3); +@purple4: var(--purple4); +@purple5: var(--purple5); +@purple6: var(--purple6); +@purple7: var(--purple7); +@purple8: var(--purple8); +@purple9: var(--purple9); +@purple10: var(--purple10); +@cyan1: var(--cyan1); +@cyan2: var(--cyan2); +@cyan3: var(--cyan3); +@cyan4: var(--cyan4); +@cyan5: var(--cyan5); +@cyan6: var(--cyan6); +@cyan7: var(--cyan7); +@cyan8: var(--cyan8); +@cyan9: var(--cyan9); +@cyan10: var(--cyan10); +@green1: var(--green1); +@green2: var(--green2); +@green3: var(--green3); +@green4: var(--green4); +@green5: var(--green5); +@green6: var(--green6); +@green7: var(--green7); +@green8: var(--green8); +@green9: var(--green9); +@green10: var(--green10); +@magenta1: var(--magenta1); +@magenta2: var(--magenta2); +@magenta3: var(--magenta3); +@magenta4: var(--magenta4); +@magenta5: var(--magenta5); +@magenta6: var(--magenta6); +@magenta7: var(--magenta7); +@magenta8: var(--magenta8); +@magenta9: var(--magenta9); +@magenta10: var(--magenta10); +@pink1: var(--pink1); +@pink2: var(--pink2); +@pink3: var(--pink3); +@pink4: var(--pink4); +@pink5: var(--pink5); +@pink6: var(--pink6); +@pink7: var(--pink7); +@pink8: var(--pink8); +@pink9: var(--pink9); +@pink10: var(--pink10); +@red1: var(--red1); +@red2: var(--red2); +@red3: var(--red3); +@red4: var(--red4); +@red5: var(--red5); +@red6: var(--red6); +@red7: var(--red7); +@red8: var(--red8); +@red9: var(--red9); +@red10: var(--red10); +@orange1: var(--orange1); +@orange2: var(--orange2); +@orange3: var(--orange3); +@orange4: var(--orange4); +@orange5: var(--orange5); +@orange6: var(--orange6); +@orange7: var(--orange7); +@orange8: var(--orange8); +@orange9: var(--orange9); +@orange10: var(--orange10); +@yellow1: var(--yellow1); +@yellow2: var(--yellow2); +@yellow3: var(--yellow3); +@yellow4: var(--yellow4); +@yellow5: var(--yellow5); +@yellow6: var(--yellow6); +@yellow7: var(--yellow7); +@yellow8: var(--yellow8); +@yellow9: var(--yellow9); +@yellow10: var(--yellow10); +@volcano1: var(--volcano1); +@volcano2: var(--volcano2); +@volcano3: var(--volcano3); +@volcano4: var(--volcano4); +@volcano5: var(--volcano5); +@volcano6: var(--volcano6); +@volcano7: var(--volcano7); +@volcano8: var(--volcano8); +@volcano9: var(--volcano9); +@volcano10: var(--volcano10); +@geekblue1: var(--geekblue1); +@geekblue2: var(--geekblue2); +@geekblue3: var(--geekblue3); +@geekblue4: var(--geekblue4); +@geekblue5: var(--geekblue5); +@geekblue6: var(--geekblue6); +@geekblue7: var(--geekblue7); +@geekblue8: var(--geekblue8); +@geekblue9: var(--geekblue9); +@geekblue10: var(--geekblue10); +@gold1: var(--gold1); +@gold2: var(--gold2); +@gold3: var(--gold3); +@gold4: var(--gold4); +@gold5: var(--gold5); +@gold6: var(--gold6); +@gold7: var(--gold7); +@gold8: var(--gold8); +@gold9: var(--gold9); +@gold10: var(--gold10); +@lime1: var(--lime1); +@lime2: var(--lime2); +@lime3: var(--lime3); +@lime4: var(--lime4); +@lime5: var(--lime5); +@lime6: var(--lime6); +@lime7: var(--lime7); +@lime8: var(--lime8); +@lime9: var(--lime9); +@lime10: var(--lime10); +@colorText: var(--colorText); +@colorTextSecondary: var(--colorTextSecondary); +@colorTextTertiary: var(--colorTextTertiary); +@colorTextQuaternary: var(--colorTextQuaternary); +@colorFill: var(--colorFill); +@colorFillSecondary: var(--colorFillSecondary); +@colorFillTertiary: var(--colorFillTertiary); +@colorFillQuaternary: var(--colorFillQuaternary); +@colorBgLayout: var(--colorBgLayout); +@colorBgContainer: var(--colorBgContainer); +@colorBgElevated: var(--colorBgElevated); +@colorBgSpotlight: var(--colorBgSpotlight); +@colorBorder: var(--colorBorder); +@colorBorderSecondary: var(--colorBorderSecondary); +@colorPrimaryBg: var(--colorPrimaryBg); +@colorPrimaryBgHover: var(--colorPrimaryBgHover); +@colorPrimaryBorder: var(--colorPrimaryBorder); +@colorPrimaryBorderHover: var(--colorPrimaryBorderHover); +@colorPrimaryHover: var(--colorPrimaryHover); +@colorPrimaryActive: var(--colorPrimaryActive); +@colorPrimaryTextHover: var(--colorPrimaryTextHover); +@colorPrimaryText: var(--colorPrimaryText); +@colorPrimaryTextActive: var(--colorPrimaryTextActive); +@colorSuccessBg: var(--colorSuccessBg); +@colorSuccessBgHover: var(--colorSuccessBgHover); +@colorSuccessBorder: var(--colorSuccessBorder); +@colorSuccessBorderHover: var(--colorSuccessBorderHover); +@colorSuccessHover: var(--colorSuccessHover); +@colorSuccessActive: var(--colorSuccessActive); +@colorSuccessTextHover: var(--colorSuccessTextHover); +@colorSuccessText: var(--colorSuccessText); +@colorSuccessTextActive: var(--colorSuccessTextActive); +@colorErrorBg: var(--colorErrorBg); +@colorErrorBgHover: var(--colorErrorBgHover); +@colorErrorBorder: var(--colorErrorBorder); +@colorErrorBorderHover: var(--colorErrorBorderHover); +@colorErrorHover: var(--colorErrorHover); +@colorErrorActive: var(--colorErrorActive); +@colorErrorTextHover: var(--colorErrorTextHover); +@colorErrorText: var(--colorErrorText); +@colorErrorTextActive: var(--colorErrorTextActive); +@colorWarningBg: var(--colorWarningBg); +@colorWarningBgHover: var(--colorWarningBgHover); +@colorWarningBorder: var(--colorWarningBorder); +@colorWarningBorderHover: var(--colorWarningBorderHover); +@colorWarningHover: var(--colorWarningHover); +@colorWarningActive: var(--colorWarningActive); +@colorWarningTextHover: var(--colorWarningTextHover); +@colorWarningText: var(--colorWarningText); +@colorWarningTextActive: var(--colorWarningTextActive); +@colorInfoBg: var(--colorInfoBg); +@colorInfoBgHover: var(--colorInfoBgHover); +@colorInfoBorder: var(--colorInfoBorder); +@colorInfoBorderHover: var(--colorInfoBorderHover); +@colorInfoHover: var(--colorInfoHover); +@colorInfoActive: var(--colorInfoActive); +@colorInfoTextHover: var(--colorInfoTextHover); +@colorInfoText: var(--colorInfoText); +@colorInfoTextActive: var(--colorInfoTextActive); +@colorBgMask: var(--colorBgMask); +@colorWhite: var(--colorWhite); +@fontSizeSM: var(--fontSizeSM); +@fontSizeLG: var(--fontSizeLG); +@fontSizeXL: var(--fontSizeXL); +@fontSizeHeading1: var(--fontSizeHeading1); +@fontSizeHeading2: var(--fontSizeHeading2); +@fontSizeHeading3: var(--fontSizeHeading3); +@fontSizeHeading4: var(--fontSizeHeading4); +@fontSizeHeading5: var(--fontSizeHeading5); +@lineHeight: var(--lineHeight); +@lineHeightLG: var(--lineHeightLG); +@lineHeightSM: var(--lineHeightSM); +@lineHeightHeading1: var(--lineHeightHeading1); +@lineHeightHeading2: var(--lineHeightHeading2); +@lineHeightHeading3: var(--lineHeightHeading3); +@lineHeightHeading4: var(--lineHeightHeading4); +@lineHeightHeading5: var(--lineHeightHeading5); +@sizeXXL: var(--sizeXXL); +@sizeXL: var(--sizeXL); +@sizeLG: var(--sizeLG); +@sizeMD: var(--sizeMD); +@sizeMS: var(--sizeMS); +@size: var(--size); +@sizeSM: var(--sizeSM); +@sizeXS: var(--sizeXS); +@sizeXXS: var(--sizeXXS); +@controlHeightSM: var(--controlHeightSM); +@controlHeightXS: var(--controlHeightXS); +@controlHeightLG: var(--controlHeightLG); +@motionDurationFast: var(--motionDurationFast); +@motionDurationMid: var(--motionDurationMid); +@motionDurationSlow: var(--motionDurationSlow); +@lineWidthBold: var(--lineWidthBold); +@borderRadiusXS: var(--borderRadiusXS); +@borderRadiusSM: var(--borderRadiusSM); +@borderRadiusLG: var(--borderRadiusLG); +@borderRadiusOuter: var(--borderRadiusOuter); diff --git a/src/themes/index.less b/src/themes/index.less new file mode 100644 index 0000000..65703ef --- /dev/null +++ b/src/themes/index.less @@ -0,0 +1,2 @@ +@import url('@/themes/default.less'); +@import url('@/themes/custom.less'); diff --git a/src/typings/common.ts b/src/typings/common.ts index 13b8f9a..50134d1 100644 --- a/src/typings/common.ts +++ b/src/typings/common.ts @@ -9,7 +9,7 @@ export interface Common { /** * id */ - id: string + _id: string /** * 更新时间 */ @@ -26,3 +26,10 @@ export enum Language { Zh = 'zh', En = 'en', } + +export enum Status { + Success = 'success', + Error = 'error', + Warning = 'warning', + Info = 'info', +} diff --git a/src/typings/contact/index.ts b/src/typings/contact/index.ts new file mode 100644 index 0000000..fc753b9 --- /dev/null +++ b/src/typings/contact/index.ts @@ -0,0 +1,24 @@ +import type { Common } from '..' + +export enum FriendRequestStatus { + Pending = 'pending', + Accepted = 'accepted', + Rejected = 'rejected', +} + +export interface Contact extends Common { + // 发起好友申请的用户 id + userId: string + // 被申请的用户 id + friendId: string + // 申请状态 + status: FriendRequestStatus + // 申请理由 + reason: string + // friend 给 user 的备注 + friendRemark: string + // user 给 friend 的备注 + userRemark: string + // 好友关系建立时间 + establishAt: string +} diff --git a/src/typings/index.ts b/src/typings/index.ts index d7f646c..3956478 100644 --- a/src/typings/index.ts +++ b/src/typings/index.ts @@ -1,3 +1,4 @@ export * from './common' export * from './user' export * from './chat' +export * from './contact'