Merge branch 'feat/filesystem_and_search' of github.com:toeverything/AFFiNE into feat/filesystem_and_search

This commit is contained in:
DiamondThree
2022-12-22 17:00:23 +08:00
19 changed files with 213 additions and 85 deletions
@@ -12,24 +12,24 @@ export const StyledIsland = styled('div')(({ theme }) => {
zIndex: theme.zIndex.popover,
};
});
export const StyledTransformIcon = styled.div<{ in: boolean }>(
({ in: isIn, theme }) => ({
height: '32px',
width: '32px',
borderRadius: '50%',
position: 'absolute',
left: '0',
right: '0',
bottom: '0',
top: '0',
margin: 'auto',
...displayFlex('center', 'center'),
opacity: isIn ? 1 : 0,
backgroundColor: isIn
? theme.colors.hoverBackground
: theme.colors.pageBackground,
})
);
export const StyledTransformIcon = styled('div', {
shouldForwardProp: prop => prop !== 'in',
})<{ in: boolean }>(({ in: isIn, theme }) => ({
height: '32px',
width: '32px',
borderRadius: '50%',
position: 'absolute',
left: '0',
right: '0',
bottom: '0',
top: '0',
margin: 'auto',
...displayFlex('center', 'center'),
opacity: isIn ? 1 : 0,
backgroundColor: isIn
? theme.colors.hoverBackground
: theme.colors.pageBackground,
}));
export const StyledIconWrapper = styled('div')<{ isEdgelessDark: boolean }>(
({ theme, isEdgelessDark }) => {
return {
@@ -194,8 +194,9 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => {
.catch(err => {
console.log(err);
});
}, []);
}, [workspace.id]);
const { confirm } = useConfirm();
return (
<div>
<StyledMemberTitleContainer>
@@ -206,7 +207,7 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => {
{members.length ? (
members.map(member => {
return (
<StyledMemberListItem>
<StyledMemberListItem key={member.id}>
<StyledMemberNameContainer>
{member.user.type === 'Registered' ? (
<Avatar src={member.user.avatar_url}></Avatar>
@@ -11,20 +11,72 @@ import {
LoginItem,
} from './WorkspaceItem';
import { WorkspaceSetting } from '@/components/workspace-setting';
import { useState } from 'react';
import { WorkspaceType } from '@pathfinder/data-services';
import { useCallback, useEffect, useState } from 'react';
import { getWorkspaceDetail, WorkspaceType } from '@pathfinder/data-services';
export const SelectorPopperContent = () => {
const { user, workspacesMeta } = useAppState();
type WorkspaceDetails = Record<
string,
{ memberCount: number; owner: { id: string; name: string } }
>;
type SelectorPopperContentProps = {
isShow: boolean;
};
export const SelectorPopperContent = ({
isShow,
}: SelectorPopperContentProps) => {
const { user, workspacesMeta, workspaces } = useAppState();
const [settingWorkspaceId, setSettingWorkspaceId] = useState<string | null>(
null
);
const [workSpaceDetails, setWorkSpaceDetails] = useState<WorkspaceDetails>(
{}
);
const handleClickSettingWorkspace = (workspaceId: string) => {
setSettingWorkspaceId(workspaceId);
};
const handleCloseWorkSpace = () => {
setSettingWorkspaceId(null);
};
const refreshDetails = useCallback(async () => {
const workspaceDetailList = await Promise.all(
workspacesMeta?.map(async ({ id, type }) => {
if (user) {
if (type === WorkspaceType.Private) {
return { id, member_count: 1, owner: user };
} else {
const data = await getWorkspaceDetail({ id });
return { id, ...data } || { id, member_count: 0, owner: user };
}
}
})
);
let workSpaceDetails: WorkspaceDetails = {};
workspaceDetailList.forEach(details => {
if (details) {
const { id, member_count, owner } = details;
if (!owner) return;
workSpaceDetails[id] = {
memberCount: member_count || 1,
owner: {
id: owner.id,
name: owner.name,
},
};
}
});
setWorkSpaceDetails(workSpaceDetails);
}, [user, workspacesMeta]);
useEffect(() => {
if (isShow) {
setSettingWorkspaceId(null);
refreshDetails();
}
}, [isShow, refreshDetails]);
return !user ? (
<SelectorPopperContainer placement="bottom-start">
<LoginItem />
@@ -47,9 +99,13 @@ export const SelectorPopperContent = () => {
type={workspace.type}
key={workspace.id}
id={workspace.id}
name={`workspace-${workspace.id}`}
icon={''}
icon={workspaces[workspace.id]?.meta.avatar || ''}
onClick={handleClickSettingWorkspace}
name={
workspaces[workspace.id]?.meta.name ||
`workspace-${workspace.id}`
}
memberCount={workSpaceDetails[workspace.id]?.memberCount || 1}
/>
);
})}
@@ -1,4 +1,8 @@
import { createWorkspace } from '@pathfinder/data-services';
import {
createWorkspace,
getBlob,
uploadBlob,
} from '@pathfinder/data-services';
import Modal from '@/ui/modal';
import Input from '@/ui/input';
import { Button } from '@/ui/button';
@@ -19,6 +23,14 @@ interface WorkspaceCreateProps {
onClose: () => void;
}
const DefaultHeadImgColors = [
['#C6F2F3', '#0C6066'],
['#FFF5AB', '#896406'],
['#FFCCA7', '#8F4500'],
['#FFCECE', '#AF1212'],
['#E3DEFF', '#511AAB'],
];
export const WorkspaceCreate = ({ open, onClose }: WorkspaceCreateProps) => {
const [workspaceName, setWorkspaceId] = useState<string>('');
const [canCreate, setCanCreate] = useState<boolean>(false);
@@ -30,22 +42,34 @@ export const WorkspaceCreate = ({ open, onClose }: WorkspaceCreateProps) => {
canvas.height = 100;
canvas.width = 100;
const ctx = canvas.getContext('2d');
if (ctx) {
// TODO: add a image list
ctx.fillStyle = '#FFDE03';
ctx.fillRect(0, 0, 100, 100);
ctx.font = "600 50px 'PingFang SC', 'Microsoft Yahei'";
ctx.fillStyle = '#FFF';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(workspaceName[0], 50, 50);
const blob = canvas.toBlob(blob => {}, 'image/png');
}
return new Promise<string>((resolve, reject) => {
if (ctx) {
const randomNumber = Math.floor(Math.random() * 5);
const randomColor = DefaultHeadImgColors[randomNumber];
ctx.fillStyle = randomColor[0];
ctx.fillRect(0, 0, 100, 100);
ctx.font = "600 50px 'PingFang SC', 'Microsoft Yahei'";
ctx.fillStyle = randomColor[1];
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(workspaceName[0], 50, 50);
canvas.toBlob(blob => {
if (blob) {
const blobId = uploadBlob({ blob });
resolve(blobId);
} else {
reject();
}
}, 'image/png');
} else {
reject();
}
});
};
const handleCreateWorkspace = () => {
const handleCreateWorkspace = async () => {
setCanCreate(true);
createDefaultHeadImg(workspaceName);
createWorkspace({ name: workspaceName, avatar: '' })
const blobId = await createDefaultHeadImg(workspaceName);
createWorkspace({ name: workspaceName, avatar: `/api/blob/${blobId}` })
.then(data => {
// @ts-ignore
router.push(`/workspace/${data.created_at}`);
@@ -1,13 +1,15 @@
import { SettingsIcon } from '@blocksuite/icons';
import { styled } from '@/styles';
import { IconButton } from '@/ui/button';
import { MouseEventHandler } from 'react';
type SettingProps = {
onClick?: () => void;
};
export const FooterSetting = ({ onClick }: SettingProps) => {
const handleClick = () => {
const handleClick: MouseEventHandler<HTMLButtonElement> = e => {
e.stopPropagation();
onClick && onClick();
};
return (
@@ -15,7 +17,7 @@ export const FooterSetting = ({ onClick }: SettingProps) => {
className="footer-setting"
onClick={e => {
e.stopPropagation();
handleClick();
handleClick(e);
}}
>
<SettingsIcon />
@@ -2,12 +2,16 @@ import { UsersIcon } from '@blocksuite/icons';
import { styled } from '@/styles';
import { IconButton } from '@/ui/button';
export const FooterUsers = () => {
type FooterUsersProps = {
memberCount: number;
};
export const FooterUsers = ({ memberCount = 1 }: FooterUsersProps) => {
return (
<Wrapper className="footer-users">
<>
<UsersIcon />
<Tip>99+</Tip>
<Tip>{memberCount > 99 ? '99+' : memberCount}</Tip>
</>
</Wrapper>
);
@@ -14,6 +14,7 @@ interface WorkspaceItemProps {
name: string;
icon: string;
type: WorkspaceType;
memberCount: number;
onClick?: (workspaceId: string) => void;
}
@@ -23,6 +24,7 @@ export const WorkspaceItem = ({
icon,
type,
onClick,
memberCount,
}: WorkspaceItemProps) => {
const router = useRouter();
@@ -44,7 +46,7 @@ export const WorkspaceItem = ({
<Name title={name}>{name}</Name>
</WorkspaceItemContent>
<Footer>
<FooterUsers />
<FooterUsers memberCount={memberCount} />
<FooterSetting onClick={handleClickSetting} />
</Footer>
</StyledWrapper>
@@ -1,14 +1,18 @@
import { Popper } from '@/ui/popper';
import { Avatar, WorkspaceName, SelectorWrapper } from './styles';
import { SelectorPopperContent } from './SelectorPopperContent';
import { useState } from 'react';
export const WorkspaceSelector = () => {
const [isShow, setIsShow] = useState(false);
return (
<Popper
content={<SelectorPopperContent />}
content={<SelectorPopperContent isShow={isShow} />}
zIndex={1000}
placement="bottom-start"
trigger="click"
onVisibleChange={setIsShow}
>
<SelectorWrapper>
<Avatar alt="Affine" />