Merge branch 'master' into bugfix/iframe

This commit is contained in:
DiamondThree
2022-08-04 14:21:56 +08:00
31 changed files with 544 additions and 291 deletions

View File

@@ -1,5 +1,5 @@
{ {
"projectName": "Ligo-Virgo", "projectName": "toeverything",
"projectOwner": "toeverything", "projectOwner": "toeverything",
"repoType": "github", "repoType": "github",
"repoHost": "https://github.com", "repoHost": "https://github.com",
@@ -25,7 +25,7 @@
"login": "tzhangchi", "login": "tzhangchi",
"name": "Chi Zhang", "name": "Chi Zhang",
"avatar_url": "https://avatars.githubusercontent.com/u/5910926?v=4", "avatar_url": "https://avatars.githubusercontent.com/u/5910926?v=4",
"profile": "https://zhangchi.blog.csdn.net/", "profile": "http://zhangchi.page/",
"contributions": [ "contributions": [
"code", "code",
"doc" "doc"
@@ -33,7 +33,7 @@
}, },
{ {
"login": "alt1o", "login": "alt1o",
"name": "alt1o", "name": "wang xinglong",
"avatar_url": "https://avatars.githubusercontent.com/u/21084335?v=4", "avatar_url": "https://avatars.githubusercontent.com/u/21084335?v=4",
"profile": "https://github.com/alt1o", "profile": "https://github.com/alt1o",
"contributions": [ "contributions": [
@@ -43,7 +43,7 @@
}, },
{ {
"login": "DiamondThree", "login": "DiamondThree",
"name": "Diamond", "name": "DiamondThree",
"avatar_url": "https://avatars.githubusercontent.com/u/24630517?v=4", "avatar_url": "https://avatars.githubusercontent.com/u/24630517?v=4",
"profile": "https://github.com/DiamondThree", "profile": "https://github.com/DiamondThree",
"contributions": [ "contributions": [
@@ -63,7 +63,7 @@
}, },
{ {
"login": "zuoxiaodong0815", "login": "zuoxiaodong0815",
"name": "zuoxiaodong0815", "name": "xiaodong zuo",
"avatar_url": "https://avatars.githubusercontent.com/u/53252747?v=4", "avatar_url": "https://avatars.githubusercontent.com/u/53252747?v=4",
"profile": "https://github.com/zuoxiaodong0815", "profile": "https://github.com/zuoxiaodong0815",
"contributions": [ "contributions": [
@@ -73,7 +73,7 @@
}, },
{ {
"login": "SaikaSakura", "login": "SaikaSakura",
"name": "SaikaSakura", "name": "MingLIang Wang",
"avatar_url": "https://avatars.githubusercontent.com/u/11530942?v=4", "avatar_url": "https://avatars.githubusercontent.com/u/11530942?v=4",
"profile": "https://github.com/SaikaSakura", "profile": "https://github.com/SaikaSakura",
"contributions": [ "contributions": [
@@ -92,10 +92,10 @@
] ]
}, },
{ {
"login": "tuluffy", "login": "mitsuhatu",
"name": "tuluffy", "name": "mitsuhatu",
"avatar_url": "https://avatars.githubusercontent.com/u/26808339?v=4", "avatar_url": "https://avatars.githubusercontent.com/u/110213079?v=4",
"profile": "https://tuluffy.github.io/angular.github.io/", "profile": "https://github.com/mitsuhatu",
"contributions": [ "contributions": [
"code", "code",
"doc" "doc"

View File

@@ -14,7 +14,7 @@ Planning, Sorting and Creating all Together. Open-source, Privacy-First, and Fre
<!-- <!--
Make New Badge Pattern badges inline Make New Badge Pattern badges inline
See https://github.com/all-contributors/all-contributors/issues/361#issuecomment-637166066 See https://github.com/all-?/all-contributors/issues/361#issuecomment-637166066
--> -->
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --> <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
@@ -38,7 +38,7 @@ See https://github.com/all-contributors/all-contributors/issues/361#issuecomment
<a href="https://t.me/affineworkos"><b>Telegram</b></a> <a href="https://t.me/affineworkos"><b>Telegram</b></a>
</p> </p>
<p align="center"><img width="1920" alt="affine_screen" src="https://user-images.githubusercontent.com/79301703/182363099-48b479c3-dc26-4fc3-8f9b-45f9cf358f9a.png"><p/> <p align="center"><img width="1920" alt="affine_screen" src="https://user-images.githubusercontent.com/21084335/182552060-972cac0e-6258-4ccb-85bd-3bb466c30ccd.png"><p/>
# Stay Up-to-Date # Stay Up-to-Date
@@ -52,7 +52,8 @@ See https://github.com/all-contributors/all-contributors/issues/361#issuecomment
- [Plan your task](#plan-your-task) - [Plan your task](#plan-your-task)
- [Sort your knowledge](#sort-your-knowledge) - [Sort your knowledge](#sort-your-knowledge)
- [Create your story](#create-your-story) - [Create your story](#create-your-story)
- [Getting Started with development](#getting-started-with-development) - [Documentation](#documentation)
- [Getting Started with development](#getting-started-with-development)
- [Roadmap](#roadmap) - [Roadmap](#roadmap)
- [Releases](#releases) - [Releases](#releases)
- [Feature requests](#feature-requests) - [Feature requests](#feature-requests)
@@ -60,6 +61,7 @@ See https://github.com/all-contributors/all-contributors/issues/361#issuecomment
- [The Philosophy of AFFiNE](#the-philosophy-of-affine) - [The Philosophy of AFFiNE](#the-philosophy-of-affine)
- [Community](#community) - [Community](#community)
- [Contributors](#contributors) - [Contributors](#contributors)
- [Acknowledgments](#acknowledgments)
- [License](#license) - [License](#license)
## Shape your page ## Shape your page
@@ -80,9 +82,13 @@ We want your data always to be yours, and we don't want to make any sacrifice to
Collaboration isn't only necessary for teams -- you may take and insert pics on your phone, then edit them on your desktop, and share them with your collaborators. Collaboration isn't only necessary for teams -- you may take and insert pics on your phone, then edit them on your desktop, and share them with your collaborators.
Affine is fully built with web technologies so that consistency and accessibility are always guaranteed on Mac, Windows and Linux. The local file system support will be available when version 0.0.1beta is released. Affine is fully built with web technologies so that consistency and accessibility are always guaranteed on Mac, Windows and Linux. The local file system support will be available when version 0.0.1beta is released.
# Getting Started with development # Documentation
Please view the [documentation](https://affine.gitbook.io/affine/) in Contribute-to-AFFiNE/Software-Contributions/Environment-setup. Please view the [documentation](https://affine.gitbook.io/affine/)
## Getting Started with development
Please view the path Contribute-to-AFFiNE/Software-Contributions/Quick-Start in documentation.
# Roadmap # Roadmap
@@ -134,9 +140,17 @@ We would like to give special thanks to the innovators and pioneers who greatly
We would also like to give thanks to open-source projects that make affine possible: We would also like to give thanks to open-source projects that make affine possible:
- Yjs & Yrs - [Yjs](https://github.com/yjs/yjs) & [Yrs](https://github.com/y-crdt/y-crdt) -- Fundamental support of CRDTs for our implements on state management and data sync.
- React - [React](https://github.com/facebook/react) -- View layer support and web GUI framework.
- Rust - [Rust](https://github.com/rust-lang/rust) -- High performance language that extends the ability and availability of our real-time backend, JWST.
- [Fossil](https://www2.fossil-scm.org/home/doc/trunk/www/index.wiki) -- Source code management tool made with CRDTs which inspired our design on block data structure.
- [slatejs](https://github.com/ianstormtaylor/slate) -- Customizable rich-text editor.
- [Jotai](https://github.com/pmndrs/jotai) -- Minimal state management tool for frontend.
- [Tldraw](https://github.com/tldraw/tldraw) -- Excellent drawing board.
- [MUI](https://github.com/mui/material-ui) -- Our most used graphic UI component library.
- Other [dependancies](https://github.com/toeverything/AFFiNE/network/dependencies)
Thanks a lot to the community for providing such powerful and simple libraries, so that we can focus more on the implementation of the product logic, and we hope that in the future our projects will also provide a more easy-to-use knowledge base for everyone.
# Community # Community
@@ -152,16 +166,16 @@ For help, discussion about best practices, or any other conversation that would
<table> <table>
<tr> <tr>
<td align="center"><a href="https://darksky.eu.org/"><img src="https://avatars.githubusercontent.com/u/25152247?v=4?s=100" width="100px;" alt=""/><br /><sub><b>DarkSky</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=darkskygit" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=darkskygit" title="Documentation">📖</a></td> <td align="center"><a href="https://darksky.eu.org/"><img src="https://avatars.githubusercontent.com/u/25152247?v=4?s=100" width="100px;" alt=""/><br /><sub><b>DarkSky</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=darkskygit" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=darkskygit" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/tzhangchi"><img src="https://avatars.githubusercontent.com/u/5910926?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chi Zhang</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=tzhangchi" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=tzhangchi" title="Documentation">📖</a></td> <td align="center"><a href="http://zhangchi.page/"><img src="https://avatars.githubusercontent.com/u/5910926?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chi Zhang</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=tzhangchi" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=tzhangchi" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/alt1o"><img src="https://avatars.githubusercontent.com/u/21084335?v=4?s=100" width="100px;" alt=""/><br /><sub><b>alt1o</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=alt1o" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=alt1o" title="Documentation">📖</a></td> <td align="center"><a href="https://github.com/alt1o"><img src="https://avatars.githubusercontent.com/u/21084335?v=4?s=100" width="100px;" alt=""/><br /><sub><b>wang xinglong</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=alt1o" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=alt1o" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/DiamondThree"><img src="https://avatars.githubusercontent.com/u/24630517?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Diamond</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=DiamondThree" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=DiamondThree" title="Documentation">📖</a></td> <td align="center"><a href="https://github.com/DiamondThree"><img src="https://avatars.githubusercontent.com/u/24630517?v=4?s=100" width="100px;" alt=""/><br /><sub><b>DiamondThree</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=DiamondThree" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=DiamondThree" title="Documentation">📖</a></td>
<td align="center"><a href="https://lawvs.github.io/profile/"><img src="https://avatars.githubusercontent.com/u/18554747?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Whitewater</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=lawvs" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=lawvs" title="Documentation">📖</a></td> <td align="center"><a href="https://lawvs.github.io/profile/"><img src="https://avatars.githubusercontent.com/u/18554747?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Whitewater</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=lawvs" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=lawvs" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/zuoxiaodong0815"><img src="https://avatars.githubusercontent.com/u/53252747?v=4?s=100" width="100px;" alt=""/><br /><sub><b>zuoxiaodong0815</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=zuoxiaodong0815" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=zuoxiaodong0815" title="Documentation">📖</a></td> <td align="center"><a href="https://github.com/zuoxiaodong0815"><img src="https://avatars.githubusercontent.com/u/53252747?v=4?s=100" width="100px;" alt=""/><br /><sub><b>xiaodong zuo</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=zuoxiaodong0815" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=zuoxiaodong0815" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/SaikaSakura"><img src="https://avatars.githubusercontent.com/u/11530942?v=4?s=100" width="100px;" alt=""/><br /><sub><b>SaikaSakura</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=SaikaSakura" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=SaikaSakura" title="Documentation">📖</a></td> <td align="center"><a href="https://github.com/SaikaSakura"><img src="https://avatars.githubusercontent.com/u/11530942?v=4?s=100" width="100px;" alt=""/><br /><sub><b>MingLIang Wang</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=SaikaSakura" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=SaikaSakura" title="Documentation">📖</a></td>
</tr> </tr>
<tr> <tr>
<td align="center"><a href="https://github.com/QiShaoXuan"><img src="https://avatars.githubusercontent.com/u/22772830?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Qi</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=QiShaoXuan" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=QiShaoXuan" title="Documentation">📖</a></td> <td align="center"><a href="https://github.com/QiShaoXuan"><img src="https://avatars.githubusercontent.com/u/22772830?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Qi</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=QiShaoXuan" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=QiShaoXuan" title="Documentation">📖</a></td>
<td align="center"><a href="https://tuluffy.github.io/angular.github.io/"><img src="https://avatars.githubusercontent.com/u/26808339?v=4?s=100" width="100px;" alt=""/><br /><sub><b>tuluffy</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=tuluffy" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=tuluffy" title="Documentation">📖</a></td> <td align="center"><a href="https://github.com/mitsuhatu"><img src="https://avatars.githubusercontent.com/u/110213079?v=4?s=100" width="100px;" alt=""/><br /><sub><b>mitsuhatu</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=mitsuhatu" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=mitsuhatu" title="Documentation">📖</a></td>
<td align="center"><a href="https://shockwave.me/"><img src="https://avatars.githubusercontent.com/u/15013925?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Austaras</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=Austaras" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=Austaras" title="Documentation">📖</a></td> <td align="center"><a href="https://shockwave.me/"><img src="https://avatars.githubusercontent.com/u/15013925?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Austaras</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=Austaras" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=Austaras" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/uptonking?tab=repositories&type=source"><img src="https://avatars.githubusercontent.com/u/11391549?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jin Yao</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=uptonking" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=uptonking" title="Documentation">📖</a></td> <td align="center"><a href="https://github.com/uptonking?tab=repositories&type=source"><img src="https://avatars.githubusercontent.com/u/11391549?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jin Yao</b></sub></a><br /><a href="https://github.com/toeverything/AFFiNE/commits?author=uptonking" title="Code">💻</a> <a href="https://github.com/toeverything/AFFiNE/commits?author=uptonking" title="Documentation">📖</a></td>
</tr> </tr>

View File

@@ -31,7 +31,7 @@ import { WorkspaceName } from './workspace-name';
import { CollapsiblePageTree } from './collapsible-page-tree'; import { CollapsiblePageTree } from './collapsible-page-tree';
import { useFlag } from '@toeverything/datasource/feature-flags'; import { useFlag } from '@toeverything/datasource/feature-flags';
import { type BlockEditor } from '@toeverything/components/editor-core'; import { type BlockEditor } from '@toeverything/components/editor-core';
import { Tabs } from './components/tabs';
type PageProps = { type PageProps = {
workspace: string; workspace: string;
}; };
@@ -80,7 +80,9 @@ export function Page(props: PageProps) {
onMouseLeave={() => setSpaceSidebarVisible(false)} onMouseLeave={() => setSpaceSidebarVisible(false)}
> >
<WorkspaceName /> <WorkspaceName />
<Divider light={true} sx={{ my: 1, margin: '6px 0px' }} />
<Tabs />
<WorkspaceSidebarContent> <WorkspaceSidebarContent>
<div> <div>
{dailyNotesFlag && ( {dailyNotesFlag && (
@@ -219,4 +221,5 @@ const WorkspaceSidebar = styled('div')(({ hidden }) => ({
const WorkspaceSidebarContent = styled('div')({ const WorkspaceSidebarContent = styled('div')({
flex: 'auto', flex: 'auto',
overflow: 'hidden auto', overflow: 'hidden auto',
marginTop: '18px',
}); });

View File

@@ -0,0 +1,19 @@
export const Logo = ({ color, style, ...props }) => {
return (
<svg
width="52"
height="52"
viewBox="0 0 52 52"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect width="52" height="52" rx="10" fill="#3E6FDB" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M24.2189 11.4392L14.6321 38.7943H20.2472L26.3453 19.8747L32.4461 38.7943H38.0423L28.454 11.4392H24.2189Z"
fill="white"
/>
</svg>
);
};

View File

@@ -0,0 +1 @@
export { Logo } from './Logo';

View File

@@ -0,0 +1,61 @@
import { useState } from 'react';
import { MuiDivider as Divider, styled } from '@toeverything/components/ui';
import type { ValueOf } from '@toeverything/utils';
const StyledTabs = styled('div')({
width: '100%',
height: '12px',
marginTop: '12px',
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
});
const StyledDivider = styled(Divider)<{ isActive?: boolean }>(
({ isActive }) => {
return {
flex: 1,
backgroundColor: isActive ? '#3E6FDB' : '#ECF1FB',
borderWidth: '2px',
};
}
);
const TAB_TITLE = {
PAGES: 'pages',
GALLERY: 'gallery',
TOC: 'toc',
} as const;
const TabMap = new Map<TabKey, TabValue>([
['PAGES', 'pages'],
['GALLERY', 'gallery'],
['TOC', 'toc'],
]);
type TabKey = keyof typeof TAB_TITLE;
type TabValue = ValueOf<typeof TAB_TITLE>;
const Tabs = () => {
const [activeTab, setActiveTab] = useState<TabValue>(TAB_TITLE.PAGES);
const onClick = (v: TabValue) => {
setActiveTab(v);
};
return (
<StyledTabs>
{[...TabMap.entries()].map(([k, v]) => {
return (
<StyledDivider
key={v}
isActive={v === activeTab}
onClick={() => onClick(v)}
/>
);
})}
</StyledTabs>
);
};
export { Tabs };

View File

@@ -0,0 +1 @@
export { Tabs } from './Tabs';

View File

@@ -1,27 +1,28 @@
import { import {
MuiButton as Button,
Switch,
styled, styled,
MuiOutlinedInput as OutlinedInput, MuiOutlinedInput as OutlinedInput,
} from '@toeverything/components/ui'; } from '@toeverything/components/ui';
import { LogoIcon } from '@toeverything/components/icons'; import { PinIcon } from '@toeverything/components/icons';
import { import {
useUserAndSpaces, useUserAndSpaces,
useShowSpaceSidebar, useShowSpaceSidebar,
} from '@toeverything/datasource/state'; } from '@toeverything/datasource/state';
import { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { services } from '@toeverything/datasource/db-service'; import { services } from '@toeverything/datasource/db-service';
import { Logo } from './components/logo/Logo';
const WorkspaceContainer = styled('div')({ const WorkspaceContainer = styled('div')({
display: 'flex', display: 'flex',
alignItems: 'center', flexDirection: 'column',
minHeight: 60, paddingBottom: '12px',
padding: '12px 0px',
color: '#566B7D', color: '#566B7D',
}); });
const LeftContainer = styled('div')({ const LeftContainer = styled('div')({
flex: 'auto', flex: 'auto',
display: 'flex', display: 'flex',
height: '52px',
alignItems: 'center',
margin: '0 12px',
}); });
const LogoContainer = styled('div')({ const LogoContainer = styled('div')({
@@ -32,20 +33,36 @@ const LogoContainer = styled('div')({
minWidth: 24, minWidth: 24,
}); });
const StyledLogoIcon = styled(LogoIcon)(({ theme }) => { const StyledPin = styled('div')({
return { display: 'flex',
color: theme.affine.palette.primary, justifyContent: 'end',
width: '16px !important', alignItems: 'center',
height: '16px !important', });
};
const StyledWorkspace = styled('div')({
height: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
marginLeft: '12px',
paddingLeft: '12px',
});
const StyledWorkspaceDesc = styled('div')({
fontSize: '12px',
color: '#98ACBD',
height: '18px',
display: 'flex',
alignItems: 'center',
}); });
const WorkspaceNameContainer = styled('div')({ const WorkspaceNameContainer = styled('div')({
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
flex: 'auto', flex: 'auto',
width: '100px', width: '165px',
marginRight: '10px', height: '34px',
input: { input: {
padding: '5px 10px', padding: '5px 10px',
}, },
@@ -58,21 +75,15 @@ const WorkspaceNameContainer = styled('div')({
}); });
const WorkspaceReNameContainer = styled('div')({ const WorkspaceReNameContainer = styled('div')({
marginRight: '10px', height: '34px',
display: 'flex',
alignItems: 'center',
input: { input: {
padding: '5px 10px', padding: '5px 10px',
}, },
}); });
const ToggleDisplayContainer = styled('div')({
display: 'flex',
alignItems: 'center',
fontSize: 12,
color: '#3E6FDB',
padding: 6,
minWidth: 64,
});
export const WorkspaceName = () => { export const WorkspaceName = () => {
const { currentSpaceId } = useUserAndSpaces(); const { currentSpaceId } = useUserAndSpaces();
const { fixedDisplay, toggleSpaceSidebar } = useShowSpaceSidebar(); const { fixedDisplay, toggleSpaceSidebar } = useShowSpaceSidebar();
@@ -139,35 +150,46 @@ export const WorkspaceName = () => {
return ( return (
<WorkspaceContainer> <WorkspaceContainer>
<StyledPin>
<PinIcon
style={{
width: '20px',
height: '20px',
color: fixedDisplay ? '#3E6FDB' : '',
cursor: 'pointer',
}}
onClick={toggleSpaceSidebar}
/>
</StyledPin>
<LeftContainer> <LeftContainer>
<LogoContainer> <LogoContainer>
<StyledLogoIcon /> <Logo color={undefined} style={undefined} />
</LogoContainer> </LogoContainer>
{inRename ? ( <StyledWorkspace>
<WorkspaceReNameContainer> {inRename ? (
<OutlinedInput <WorkspaceReNameContainer>
value={workspaceName} <OutlinedInput
onChange={handleChange} style={{ width: '140px', height: '28px' }}
onKeyDown={handleKeyDown} value={workspaceName}
onMouseLeave={() => setInRename(false)} onChange={handleChange}
/> onKeyDown={handleKeyDown}
</WorkspaceReNameContainer> onMouseLeave={() => setInRename(false)}
) : ( />
<WorkspaceNameContainer> </WorkspaceReNameContainer>
<span onClick={() => setInRename(true)}> ) : (
{workspaceName || workspaceId} <WorkspaceNameContainer>
</span> <span onClick={() => setInRename(true)}>
</WorkspaceNameContainer> {workspaceName || workspaceId}
)} </span>
</WorkspaceNameContainer>
)}
<StyledWorkspaceDesc>
To shape, Not to Adapt.
</StyledWorkspaceDesc>
</StyledWorkspace>
</LeftContainer> </LeftContainer>
<ToggleDisplayContainer onClick={toggleSpaceSidebar}>
<Switch
checked={fixedDisplay}
checkedLabel="ON"
uncheckedLabel="OFF"
/>
</ToggleDisplayContainer>
</WorkspaceContainer> </WorkspaceContainer>
); );
}; };

View File

@@ -20,12 +20,12 @@ const DiscordIcon = (props: any) => {
width="71" width="71"
height="55" height="55"
viewBox="0 0 71 55" viewBox="0 0 71 55"
fill="none" fill="currentcolor"
> >
<g clip-path="url(#clip0)"> <g clip-path="url(#clip0)">
<path <path
d="M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z" d="M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z"
fill="#23272A" fill="currentcolor"
/> />
</g> </g>
<defs> <defs>
@@ -515,10 +515,12 @@ export function App() {
justifyContent: 'left', justifyContent: 'left',
textAlign: 'left', textAlign: 'left',
transition: 'all .5s', transition: 'all .5s',
// boxShadow: '2px 2px 40px #08f2', transform: 'scale(0.98)',
// ':hover': { boxShadow: '2px 2px 40px #0002',
// boxShadow: '2px 2px 40px #08f4', ':hover': {
// }, transform: 'scale(1)',
boxShadow: '2px 2px 40px #0004',
},
}} }}
> >
<AffineImage <AffineImage
@@ -537,10 +539,10 @@ export function App() {
}} }}
> >
<Grid <Grid
xs={matches ? 12 : 4} xs={matches ? 12 : 6}
sx={{ sx={{
display: 'flex', display: 'flex',
...(matches ? {} : { marginRight: '4em' }), ...(matches ? {} : { marginLeft: '4em' }),
}} }}
> >
<Box <Box
@@ -584,7 +586,7 @@ export function App() {
</Box> </Box>
</Grid> </Grid>
<Grid <Grid
xs={matches ? 12 : 8} xs={matches ? 12 : 6}
sx={{ display: 'flex', width: '100%' }} sx={{ display: 'flex', width: '100%' }}
> >
<Box <Box
@@ -595,10 +597,12 @@ export function App() {
justifyContent: 'left', justifyContent: 'left',
textAlign: 'left', textAlign: 'left',
transition: 'all .5s', transition: 'all .5s',
// boxShadow: '2px 2px 40px #08f2', transform: 'scale(0.98)',
// ':hover': { boxShadow: '2px 2px 40px #0002',
// boxShadow: '2px 2px 40px #08f4', ':hover': {
// }, transform: 'scale(1)',
boxShadow: '2px 2px 40px #0004',
},
}} }}
> >
<AffineImage <AffineImage
@@ -656,10 +660,10 @@ export function App() {
justifyContent: 'center', justifyContent: 'center',
margin: 'auto', margin: 'auto',
transition: 'all .5s', transition: 'all .5s',
// boxShadow: '2px 2px 40px #08f2', transform: 'scale(0.98)',
// ':hover': { ':hover': {
// boxShadow: '2px 2px 40px #08f4', transform: 'scale(1)',
// }, },
}} }}
> >
<AffineImage <AffineImage
@@ -738,13 +742,20 @@ export function App() {
}} }}
> >
<Box sx={{ display: 'flex', width: '100%' }}> <Box sx={{ display: 'flex', width: '100%' }}>
<Card <Button
variant="plain"
sx={{ sx={{
display: 'flex',
flexDirection: 'column',
margin: 'auto', margin: 'auto',
minWidth: '4em', padding: '1em',
'--Card-padding': '4px', minWidth: '6em',
'--Card-radius': '0',
}} }}
onClick={() =>
window.open(
'https://github.com/toeverything/AFFiNE/'
)
}
> >
<Grid <Grid
xs={12} xs={12}
@@ -767,21 +778,30 @@ export function App() {
}} }}
> >
<Typography <Typography
sx={{ display: 'flex', color: '#888' }} sx={{
display: 'flex',
color: '#888',
fontSize: '0.5em',
}}
> >
GitHub GitHub
</Typography> </Typography>
</Grid> </Grid>
</Card> </Button>
</Box> </Box>
<Box sx={{ display: 'flex', width: '100%' }}> <Box sx={{ display: 'flex', width: '100%' }}>
<Card <Button
variant="plain"
sx={{ sx={{
display: 'flex',
flexDirection: 'column',
margin: 'auto', margin: 'auto',
minWidth: '4em', padding: '1em',
'--Card-padding': '4px', minWidth: '6em',
'--Card-radius': '0',
}} }}
onClick={() =>
window.open('https://www.reddit.com/r/Affine/')
}
> >
<Grid <Grid
xs={12} xs={12}
@@ -804,12 +824,16 @@ export function App() {
}} }}
> >
<Typography <Typography
sx={{ display: 'flex', color: '#888' }} sx={{
display: 'flex',
color: '#888',
fontSize: '0.5em',
}}
> >
Reddit Reddit
</Typography> </Typography>
</Grid> </Grid>
</Card> </Button>
</Box> </Box>
<Box <Box
sx={{ sx={{
@@ -817,13 +841,18 @@ export function App() {
width: '100%', width: '100%',
}} }}
> >
<Card <Button
variant="plain"
sx={{ sx={{
display: 'flex',
flexDirection: 'column',
margin: 'auto', margin: 'auto',
minWidth: '4em', padding: '1em',
'--Card-padding': '4px', minWidth: '6em',
'--Card-radius': '0',
}} }}
onClick={() =>
window.open('https://t.me/affineworkos')
}
> >
<Grid <Grid
xs={12} xs={12}
@@ -846,21 +875,30 @@ export function App() {
}} }}
> >
<Typography <Typography
sx={{ display: 'flex', color: '#888' }} sx={{
display: 'flex',
color: '#888',
fontSize: '0.5em',
}}
> >
Telegram Telegram
</Typography> </Typography>
</Grid> </Grid>
</Card> </Button>
</Box> </Box>
<Box sx={{ display: 'flex', width: '100%' }}> <Box sx={{ display: 'flex', width: '100%' }}>
<Card <Button
variant="plain"
sx={{ sx={{
display: 'flex',
flexDirection: 'column',
margin: 'auto', margin: 'auto',
minWidth: '4em', padding: '1em',
'--Card-padding': '4px', minWidth: '6em',
'--Card-radius': '0',
}} }}
onClick={() =>
window.open('https://discord.gg/yz6tGVsf5p')
}
> >
<Grid <Grid
xs={12} xs={12}
@@ -870,7 +908,11 @@ export function App() {
}} }}
> >
<DiscordIcon <DiscordIcon
sx={{ width: '36px', height: '36px' }} sx={{
width: '36px',
height: '36px',
color: '#09449d',
}}
/> />
</Grid> </Grid>
@@ -883,12 +925,16 @@ export function App() {
}} }}
> >
<Typography <Typography
sx={{ display: 'flex', color: '#888' }} sx={{
display: 'flex',
color: '#888',
fontSize: '0.5em',
}}
> >
Discord Discord
</Typography> </Typography>
</Grid> </Grid>
</Card> </Button>
</Box> </Box>
</Box> </Box>
<Grid xs={12} sx={{ display: 'flex', marginBottom: '2em' }}> <Grid xs={12} sx={{ display: 'flex', marginBottom: '2em' }}>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@@ -1,10 +0,0 @@
<svg width="71" height="55" viewBox="0 0 71 55" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path d="M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z" fill="#23272A"/>
</g>
<defs>
<clipPath id="clip0">
<rect width="71" height="55" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 936 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

@@ -12,6 +12,8 @@ type GridHandleProps = {
blockId: string; blockId: string;
enabledAddItem: boolean; enabledAddItem: boolean;
draggable: boolean; draggable: boolean;
alertHandleId: string;
onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;
}; };
export const GridHandle: FC<GridHandleProps> = function ({ export const GridHandle: FC<GridHandleProps> = function ({
@@ -21,6 +23,8 @@ export const GridHandle: FC<GridHandleProps> = function ({
onDrag, onDrag,
onMouseDown, onMouseDown,
draggable, draggable,
alertHandleId,
onMouseEnter,
}) { }) {
const [isMouseDown, setIsMouseDown] = useState<boolean>(false); const [isMouseDown, setIsMouseDown] = useState<boolean>(false);
const handleMouseDown: React.MouseEventHandler<HTMLDivElement> = e => { const handleMouseDown: React.MouseEventHandler<HTMLDivElement> = e => {
@@ -44,16 +48,17 @@ export const GridHandle: FC<GridHandleProps> = function ({
editor.selectionManager.setActivatedNodeId(textBlock.id); editor.selectionManager.setActivatedNodeId(textBlock.id);
} }
}; };
const handleMouseEnter: React.MouseEventHandler<HTMLDivElement> = e => {
onMouseEnter && onMouseEnter(e);
};
return ( return (
<GridHandleContainer <GridHandleContainer
style={ isMouseDown={isMouseDown}
isMouseDown
? {
backgroundColor: '#3E6FDB',
}
: {}
}
onMouseDown={handleMouseDown} onMouseDown={handleMouseDown}
onMouseEnter={handleMouseEnter}
isAlert={alertHandleId === blockId}
> >
{enabledAddItem ? ( {enabledAddItem ? (
<AddGridHandle <AddGridHandle
@@ -67,7 +72,10 @@ export const GridHandle: FC<GridHandleProps> = function ({
); );
}; };
const GridHandleContainer = styled('div')(({ theme }) => ({ const GridHandleContainer = styled('div')<{
isMouseDown: boolean;
isAlert: boolean;
}>(({ theme, isMouseDown, isAlert }) => ({
position: 'relative', position: 'relative',
width: '10px', width: '10px',
flexGrow: '0', flexGrow: '0',
@@ -78,11 +86,15 @@ const GridHandleContainer = styled('div')(({ theme }) => ({
borderRadius: '1px', borderRadius: '1px',
backgroundClip: 'content-box', backgroundClip: 'content-box',
' &:hover': { ' &:hover': {
backgroundColor: theme.affine.palette.primary, backgroundColor: isAlert ? 'red' : theme.affine.palette.primary,
[`.${GRID_ADD_HANDLE_NAME}`]: { [`.${GRID_ADD_HANDLE_NAME}`]: {
display: 'block', display: 'block',
}, },
}, },
...(isMouseDown &&
(isAlert
? { backgroundColor: 'red' }
: { backgroundColor: theme.affine.palette.primary })),
})); }));
const AddGridHandle = styled('div')(({ theme }) => ({ const AddGridHandle = styled('div')(({ theme }) => ({

View File

@@ -31,6 +31,7 @@ export const Grid: FC<CreateView> = function (props) {
const gridItemCountRef = useRef<number>(); const gridItemCountRef = useRef<number>();
const originalLeftWidth = useRef<number>(GRID_ITEM_MIN_WIDTH); const originalLeftWidth = useRef<number>(GRID_ITEM_MIN_WIDTH);
const originalRightWidth = useRef<number>(GRID_ITEM_MIN_WIDTH); const originalRightWidth = useRef<number>(GRID_ITEM_MIN_WIDTH);
const [alertHandleId, setAlertHandleId] = useState<string>(null);
const getLeftRightGridItemDomByIndex = (index: number) => { const getLeftRightGridItemDomByIndex = (index: number) => {
const gridItems = Array.from(gridContainerRef.current?.children).filter( const gridItems = Array.from(gridContainerRef.current?.children).filter(
@@ -117,7 +118,7 @@ export const Grid: FC<CreateView> = function (props) {
itemDom.style.width = width; itemDom.style.width = width;
}; };
const handleDragGrid = (e: MouseEvent, index: number) => { const handleDragGrid = async (e: MouseEvent, index: number) => {
setIsOnDrag(true); setIsOnDrag(true);
window.getSelection().removeAllRanges(); window.getSelection().removeAllRanges();
if (!isSetMouseUp.current) { if (!isSetMouseUp.current) {
@@ -165,39 +166,47 @@ export const Grid: FC<CreateView> = function (props) {
setItemWidth(leftGrid, newLeft); setItemWidth(leftGrid, newLeft);
setItemWidth(rightGrid, newRight); setItemWidth(rightGrid, newRight);
updateDbWidth(leftBlockId, newLeft, rightBlockId, newRight); updateDbWidth(leftBlockId, newLeft, rightBlockId, newRight);
[leftBlockId, rightBlockId].forEach(async blockId => {
if (await checkGridItemHasOverflow(blockId)) {
setAlertHandleId(leftBlockId);
} else {
setAlertHandleId(null);
}
});
} }
} }
}; };
const children = ( const checkGridItemHasOverflow = async (blockId: string) => {
<> let isOverflow = false;
{block.childrenIds.map((id, i) => { const block = await editor.getBlockById(blockId);
return ( if (block) {
<GridItem const blockDom = block.dom;
style={{ if (blockDom) {
transition: isOnDrag block.dom.style.overflow = 'scroll';
? 'none' if (block.dom.clientWidth !== block.dom.scrollWidth) {
: 'all 0.2s ease-in-out', isOverflow = true;
}} }
key={id} blockDom.style.overflow = 'visible';
className={GRID_ITEM_CLASS_NAME} }
> }
<RenderBlock hasContainer={false} blockId={id} /> return isOverflow;
<GridHandle };
onDrag={event => handleDragGrid(event, i)}
editor={editor} const handleHandleMouseEnter = (
onMouseDown={event => handleMouseDown(event, i)} e: React.MouseEvent<HTMLDivElement>,
blockId={id} index: number
enabledAddItem={ ) => {
block.childrenIds.length < MAX_ITEM_COUNT const leftBlockId = block.childrenIds[index];
} const rightBlockId = block.childrenIds[index + 1];
draggable={i !== block.childrenIds.length - 1} [leftBlockId, rightBlockId].forEach(async blockId => {
/> if (await checkGridItemHasOverflow(blockId)) {
</GridItem> setAlertHandleId(leftBlockId);
); } else {
})} setAlertHandleId(null);
</> }
); });
};
return ( return (
<> <>
@@ -206,7 +215,35 @@ export const Grid: FC<CreateView> = function (props) {
ref={gridContainerRef} ref={gridContainerRef}
isOnDrag={isOnDrag} isOnDrag={isOnDrag}
> >
{children} {block.childrenIds.map((id, i) => {
return (
<GridItem
style={{
transition: isOnDrag
? 'none'
: 'all 0.2s ease-in-out',
}}
key={id}
className={GRID_ITEM_CLASS_NAME}
>
<RenderBlock hasContainer={false} blockId={id} />
<GridHandle
onDrag={event => handleDragGrid(event, i)}
editor={editor}
onMouseDown={event => handleMouseDown(event, i)}
blockId={id}
enabledAddItem={
block.childrenIds.length < MAX_ITEM_COUNT
}
onMouseEnter={event =>
handleHandleMouseEnter(event, i)
}
alertHandleId={alertHandleId}
draggable={i !== block.childrenIds.length - 1}
/>
</GridItem>
);
})}
</GridContainer> </GridContainer>
{isOnDrag {isOnDrag
? ReactDOM.createPortal(<GridMask />, window.document.body) ? ReactDOM.createPortal(<GridMask />, window.document.body)

View File

@@ -60,7 +60,7 @@ const GroupContainer = styled('div')<{ isSelect?: boolean }>(
({ isSelect, theme }) => ({ ({ isSelect, theme }) => ({
background: theme.affine.palette.white, background: theme.affine.palette.white,
border: '2px solid rgba(236,241,251,.5)', border: '2px solid rgba(236,241,251,.5)',
padding: '15px 12px', padding: `15px 16px 0 16px`,
borderRadius: '10px', borderRadius: '10px',
...(isSelect ...(isSelect
? { ? {

View File

@@ -9,6 +9,7 @@ type BlockContentWrapperProps = {
children: ReactElement | null; children: ReactElement | null;
}; };
// TODO: remove
export const WrapperWithPendantAndDragDrop: FC<BlockContentWrapperProps> = export const WrapperWithPendantAndDragDrop: FC<BlockContentWrapperProps> =
function ({ block, children, editor }) { function ({ block, children, editor }) {
return ( return (

View File

@@ -1,5 +1,4 @@
import type { FC, PropsWithChildren } from 'react'; import type { FC, PropsWithChildren } from 'react';
import React, { useState } from 'react';
import { styled } from '@toeverything/components/ui'; import { styled } from '@toeverything/components/ui';
import type { AsyncBlock } from '../editor'; import type { AsyncBlock } from '../editor';
import { PendantPopover } from './pendant-popover'; import { PendantPopover } from './pendant-popover';
@@ -11,74 +10,68 @@ interface BlockTagProps {
block: AsyncBlock; block: AsyncBlock;
} }
/**
* @deprecated Need to be refactored
*/
export const BlockPendantProvider: FC<PropsWithChildren<BlockTagProps>> = ({ export const BlockPendantProvider: FC<PropsWithChildren<BlockTagProps>> = ({
block, block,
children, children,
}) => { }) => {
const [container, setContainer] = useState<HTMLElement>(null);
const [isHover, setIsHover] = useState(false);
return ( return (
<Container ref={(dom: HTMLElement) => setContainer(dom)}> <Container>
{children} {children}
{container && (
<PendantPopover <PendantPopover block={block}>
block={block} <StyledTriggerLine />
container={container} </PendantPopover>
onVisibleChange={visible => {
setIsHover(visible);
}}
>
<StyledTriggerLine
className="triggerLine"
isHover={isHover}
/>
</PendantPopover>
)}
<PendantRender block={block} /> <PendantRender block={block} />
</Container> </Container>
); );
}; };
const Container = styled('div')({ export const LINE_GAP = 16;
const TAG_GAP = 4;
const StyledTriggerLine = styled('div')({
padding: `${TAG_GAP}px 0`,
width: '100px',
cursor: 'default',
display: 'flex',
alignItems: 'flex-end',
position: 'relative', position: 'relative',
padding: '4px',
'&:hover .triggerLine::before': { '::before': {
display: 'flex', content: "''",
width: '100%',
height: '2px',
background: '#dadada',
display: 'none',
position: 'absolute',
left: '0',
top: '4px',
},
'::after': {
content: "''",
width: '0',
height: '2px',
background: '#aac4d5',
display: 'block',
position: 'absolute',
left: '0',
top: '4px',
transition: 'width .3s',
}, },
}); });
const StyledTriggerLine = styled('div')<{ isHover: boolean }>(({ isHover }) => { const Container = styled('div')({
return { position: 'relative',
padding: '4px 0', paddingBottom: `${LINE_GAP - TAG_GAP * 2}px`,
width: '100px', '&:hover': {
cursor: 'default', [StyledTriggerLine.toString()]: {
display: 'flex', '&::before': {
alignItems: 'flex-end', display: 'flex',
position: 'relative', },
'&::after': {
'::before': { width: '100%',
content: "''", },
width: '100%',
height: '2px',
background: '#dadada',
display: 'none',
position: 'absolute',
left: '0',
top: '4px',
}, },
'::after': { },
content: "''",
width: isHover ? '100%' : '0',
height: '2px',
background: '#aac4d5',
display: 'block',
position: 'absolute',
left: '0',
top: '4px',
transition: 'width .3s',
},
};
}); });

View File

@@ -1,4 +1,4 @@
import React, { FC, useRef } from 'react'; import { FC, useRef } from 'react';
import { AsyncBlock } from '../../editor'; import { AsyncBlock } from '../../editor';
import { PendantHistoryPanel } from '../pendant-history-panel'; import { PendantHistoryPanel } from '../pendant-history-panel';
import { import {
@@ -21,8 +21,6 @@ export const PendantPopover: FC<
pointerEnterDelay={300} pointerEnterDelay={300}
pointerLeaveDelay={200} pointerLeaveDelay={200}
placement="bottom-start" placement="bottom-start"
// visible={true}
// trigger="click"
content={ content={
<PendantHistoryPanel <PendantHistoryPanel
block={block} block={block}

View File

@@ -12,6 +12,7 @@ enum DragType {
} }
const DRAG_STATE_CHANGE_EVENT_KEY = 'dragStateChange'; const DRAG_STATE_CHANGE_EVENT_KEY = 'dragStateChange';
const MAX_GRID_BLOCK_FLOOR = 3;
export class DragDropManager { export class DragDropManager {
private _editor: Editor; private _editor: Editor;
private _enabled: boolean; private _enabled: boolean;
@@ -231,6 +232,17 @@ export class DragDropManager {
if (!(await this._canBeDrop(event))) { if (!(await this._canBeDrop(event))) {
direction = BlockDropPlacement.none; direction = BlockDropPlacement.none;
} }
if (
direction === BlockDropPlacement.left ||
direction === BlockDropPlacement.right
) {
const path = await this._editor.getBlockPath(blockId);
const gridBlocks = path.filter(block => block.type === 'grid');
// limit grid block floor counts
if (gridBlocks.length >= MAX_GRID_BLOCK_FLOOR) {
direction = BlockDropPlacement.none;
}
}
this._setBlockDragDirection(direction); this._setBlockDragDirection(direction);
return direction; return direction;
} }

View File

@@ -340,7 +340,20 @@ export class Editor implements Virgo {
const rootBlockId = this.getRootBlockId(); const rootBlockId = this.getRootBlockId();
const rootBlock = await this.getBlockById(rootBlockId); const rootBlock = await this.getBlockById(rootBlockId);
const blockList: Array<AsyncBlock> = rootBlock ? [rootBlock] : []; const blockList: Array<AsyncBlock> = rootBlock ? [rootBlock] : [];
const children = (await rootBlock?.children()) || []; return [...blockList, ...(await this.getOffspring(rootBlockId))];
}
/**
*
* get all offspring of block
* @param {string} id
* @return {*}
* @memberof Editor
*/
async getOffspring(id: string) {
const block = await this.getBlockById(id);
const blockList: Array<AsyncBlock> = [];
const children = (await block?.children()) || [];
for (const block of children) { for (const block of children) {
if (!block) { if (!block) {
continue; continue;
@@ -379,6 +392,20 @@ export class Editor implements Virgo {
return lastBlock; return lastBlock;
} }
async getBlockPath(id: string) {
const block = await this.getBlockById(id);
if (!block) {
return [];
}
const path = [block];
let parent = await block.parent();
while (parent) {
path.unshift(parent);
parent = await parent.parent();
}
return path;
}
async getBlockByPoint(point: Point) { async getBlockByPoint(point: Point) {
const blockList = await this.getBlockList(); const blockList = await this.getBlockList();

View File

@@ -4,7 +4,7 @@ import { HandleParentIcon } from '@toeverything/components/icons';
import { styled } from '@toeverything/components/ui'; import { styled } from '@toeverything/components/ui';
import { Point } from '@toeverything/utils'; import { Point } from '@toeverything/utils';
export const ICON_WIDTH = 24; export const ICON_WIDTH = 16;
type DragItemProps = { type DragItemProps = {
isShow: boolean; isShow: boolean;
@@ -30,17 +30,21 @@ export const DragItem = function ({
); );
}; };
const StyledDiv = styled('div')({ const StyledDiv = styled('div')(({ theme }) => ({
padding: '0', padding: '0',
display: 'inlineFlex', display: 'inline-flex',
width: `${ICON_WIDTH}px`, width: `${ICON_WIDTH}px`,
height: `${ICON_WIDTH}px`, height: '20px',
cursor: 'grab', cursor: 'grab',
'& svg': {
fontSize: '20px',
marginLeft: '-2px',
},
':hover': { ':hover': {
backgroundColor: '#edeef0', backgroundColor: '#F5F7F8',
borderRadius: '4px', borderRadius: '4px',
}, },
}); }));
const StyledButton = styled('div')({ const StyledButton = styled('div')({
padding: '0', padding: '0',

View File

@@ -1,10 +1,19 @@
import { useState, useEffect, FC } from 'react'; import {
useState,
useEffect,
FC,
type MouseEvent,
type DragEvent,
type ReactNode,
type CSSProperties,
} from 'react';
import { import {
Virgo, Virgo,
BlockDomInfo, BlockDomInfo,
PluginHooks, PluginHooks,
BlockDropPlacement, BlockDropPlacement,
LINE_GAP,
} from '@toeverything/framework/virgo'; } from '@toeverything/framework/virgo';
import { Button } from '@toeverything/components/common'; import { Button } from '@toeverything/components/common';
import { styled } from '@toeverything/components/ui'; import { styled } from '@toeverything/components/ui';
@@ -14,7 +23,7 @@ import { distinctUntilChanged, Subject } from 'rxjs';
import { HandleChildIcon } from '@toeverything/components/icons'; import { HandleChildIcon } from '@toeverything/components/icons';
import { MENU_WIDTH } from './menu-config'; import { MENU_WIDTH } from './menu-config';
const MENU_BUTTON_OFFSET = 12; const MENU_BUTTON_OFFSET = 4;
export type LineInfoSubject = Subject< export type LineInfoSubject = Subject<
| { | {
@@ -64,13 +73,13 @@ function Line(props: { lineInfo: LineInfo; rootRect: DOMRect }) {
}; };
const bottomLineStyle = { const bottomLineStyle = {
...horizontalLineStyle, ...horizontalLineStyle,
top: intersectionRect.bottom + 1 - rootRect.y, top: intersectionRect.bottom + 1 - rootRect.y - LINE_GAP,
}; };
const verticalLineStyle = { const verticalLineStyle = {
...lineStyle, ...lineStyle,
width: 2, width: 2,
height: intersectionRect.height, height: intersectionRect.height - LINE_GAP,
top: intersectionRect.y - rootRect.y, top: intersectionRect.y - rootRect.y,
}; };
const leftLineStyle = { const leftLineStyle = {
@@ -93,10 +102,10 @@ function Line(props: { lineInfo: LineInfo; rootRect: DOMRect }) {
} }
function DragComponent(props: { function DragComponent(props: {
children: React.ReactNode; children: ReactNode;
style: React.CSSProperties; style: CSSProperties;
onDragStart: (event: React.DragEvent<Element>) => void; onDragStart: (event: DragEvent<Element>) => void;
onDragEnd: (event: React.DragEvent<Element>) => void; onDragEnd: (event: DragEvent<Element>) => void;
}) { }) {
const { style, children, onDragStart, onDragEnd } = props; const { style, children, onDragStart, onDragEnd } = props;
return ( return (
@@ -122,7 +131,7 @@ export const LeftMenuDraggable: FC<LeftMenuProps> = props => {
const [block, setBlock] = useState<BlockDomInfo | undefined>(); const [block, setBlock] = useState<BlockDomInfo | undefined>();
const [line, setLine] = useState<LineInfo | undefined>(undefined); const [line, setLine] = useState<LineInfo | undefined>(undefined);
const handleDragStart = async (event: React.DragEvent<Element>) => { const handleDragStart = async (event: DragEvent<Element>) => {
event.stopPropagation(); event.stopPropagation();
setVisible(false); setVisible(false);
@@ -138,12 +147,12 @@ export const LeftMenuDraggable: FC<LeftMenuProps> = props => {
} }
}; };
const handleDragEnd = (event: React.DragEvent<Element>) => { const handleDragEnd = (event: DragEvent<Element>) => {
event.preventDefault(); event.preventDefault();
setLine(undefined); setLine(undefined);
}; };
const onClick = (event: React.MouseEvent) => { const onClick = (event: MouseEvent<Element>) => {
if (block == null) return; if (block == null) return;
const currentTarget = event.currentTarget; const currentTarget = event.currentTarget;
editor.selection.setSelectedNodesIds([block.blockId]); editor.selection.setSelectedNodesIds([block.blockId]);
@@ -200,11 +209,10 @@ export const LeftMenuDraggable: FC<LeftMenuProps> = props => {
style={{ style={{
position: 'absolute', position: 'absolute',
left: left:
Math.min( block.rect.left -
block.rect.left - MENU_WIDTH -
MENU_WIDTH - MENU_BUTTON_OFFSET -
MENU_BUTTON_OFFSET rootRect.left,
) - rootRect.left,
top: block.rect.top - rootRect.top, top: block.rect.top - rootRect.top,
opacity: visible ? 1 : 0, opacity: visible ? 1 : 0,
zIndex: 1, zIndex: 1,
@@ -239,15 +247,19 @@ const Draggable = styled(Button)({
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
backgroundColor: 'transparent', backgroundColor: 'transparent',
width: '24px', width: '16px',
height: '24px', height: '22px',
'& svg': {
fontSize: '20px',
marginLeft: '-2px',
},
':hover': { ':hover': {
backgroundColor: '#edeef0', backgroundColor: '#F5F7F8',
borderRadius: '4px', borderRadius: '4px',
}, },
}); });
const LigoLeftMenu = styled('div')({ const LigoLeftMenu = styled('div')({
backgroundColor: 'transparent', backgroundColor: 'transparent',
marginRight: '4px', // marginRight: '4px',
}); });

View File

@@ -1,5 +1,5 @@
import { BlockDomInfo, HookType } from '@toeverything/framework/virgo'; import { BlockDomInfo, HookType } from '@toeverything/framework/virgo';
import React, { StrictMode } from 'react'; import { StrictMode } from 'react';
import { BasePlugin } from '../../base-plugin'; import { BasePlugin } from '../../base-plugin';
import { ignoreBlockTypes } from './menu-config'; import { ignoreBlockTypes } from './menu-config';
import { LineInfoSubject, LeftMenuDraggable } from './LeftMenuDraggable'; import { LineInfoSubject, LeftMenuDraggable } from './LeftMenuDraggable';

View File

@@ -141,8 +141,7 @@ export const PlaceholderPanel = (props: PlaceholderPanelProps) => {
setOpen(false); setOpen(false);
props.onClickTips(); props.onClickTips();
}; };
const templateList: Array<TemplateMeta> = const templateList = TemplateFactory.defaultTemplateList;
TemplateFactory.defaultTemplateList;
const handleNewFromTemplate = async (template: TemplateMeta) => { const handleNewFromTemplate = async (template: TemplateMeta) => {
const pageId = await editor.getRootBlockId(); const pageId = await editor.getRootBlockId();
const newPage = await services.api.editorBlock.getBlock( const newPage = await services.api.editorBlock.getBlock(
@@ -162,33 +161,30 @@ export const PlaceholderPanel = (props: PlaceholderPanelProps) => {
setOpen(false); setOpen(false);
}; };
return ( return (
<> <PlaceholderPanelContainer
<PlaceholderPanelContainer style={{
style={{ top: point.y + 'px',
top: point.y + 'px', left: point.x + 'px',
left: point.x + 'px', display: open ? 'block' : 'none',
display: open ? 'block' : 'none', }}
}} >
> <EmptyPageTipContainer onClick={handleClickEmptyPage}>
<EmptyPageTipContainer onClick={handleClickEmptyPage}> Press Enter to continue with an empty page, or pick a template
Press Enter to continue with an empty page, or pick a </EmptyPageTipContainer>
template <div style={{ marginTop: '4px', marginLeft: '-8px' }}>
</EmptyPageTipContainer> {templateList.map((template, index) => {
<div style={{ marginTop: '4px', marginLeft: '-8px' }}> return (
{templateList.map((template, index) => { <TemplateItemContainer
return ( key={index}
<TemplateItemContainer onClick={() => {
key={index} handleNewFromTemplate(template);
onClick={() => { }}
handleNewFromTemplate(template); >
}} <BaseButton>{template.name}</BaseButton>
> </TemplateItemContainer>
<BaseButton>{template.name}</BaseButton> );
</TemplateItemContainer> })}
); </div>
})} </PlaceholderPanelContainer>
</div>
</PlaceholderPanelContainer>
</>
); );
}; };

View File

@@ -15,11 +15,11 @@ export const PopoverContainer = styled('div')<
const shadow = theme.affine.shadows.shadowSxDownLg; const shadow = theme.affine.shadows.shadowSxDownLg;
const white = theme.affine.palette.white; const white = theme.affine.palette.white;
const border_radius = const borderRadius =
border_radius_map[direction] || border_radius_map['left-top']; border_radius_map[direction] || border_radius_map['left-top'];
return { return {
boxShadow: shadow, boxShadow: shadow,
borderRadius: border_radius, borderRadius: borderRadius,
padding: '8px 4px', padding: '8px 4px',
backgroundColor: white, backgroundColor: white,
...style, ...style,

View File

@@ -1,7 +1,7 @@
import type { MuiPopperPlacementType as PopperPlacementType } from '../mui'; import type { MuiPopperPlacementType as PopperPlacementType } from '../mui';
import React, { forwardRef, type PropsWithChildren } from 'react'; import React, { forwardRef, type PropsWithChildren } from 'react';
import { type PopperHandler, Popper } from '../popper'; import { type PopperHandler, Popper } from '../popper';
import { PopoverContainer } from './container'; import { PopoverContainer } from './Container';
import type { PopoverProps, PopoverDirection } from './interface'; import type { PopoverProps, PopoverDirection } from './interface';
export const placementToContainerDirection: Record< export const placementToContainerDirection: Record<

View File

@@ -1,3 +1,3 @@
export * from './Popover'; export * from './Popover';
export * from './interface'; export * from './interface';
export { PopoverContainer } from './container'; export { PopoverContainer } from './Container';

View File

@@ -13,7 +13,7 @@ const groupTemplateMap = {
grid: gridTemplate, grid: gridTemplate,
} as GroupTemplateMap; } as GroupTemplateMap;
const defaultTemplateList = [ const defaultTemplateList: Array<TemplateMeta> = [
{ {
name: 'New From Quick Start', name: 'New From Quick Start',
groupKeys: ['todolist'], groupKeys: ['todolist'],
@@ -22,10 +22,10 @@ const defaultTemplateList = [
{ name: 'New From Blog', groupKeys: ['blog'] }, { name: 'New From Blog', groupKeys: ['blog'] },
{ name: ' New Todolist', groupKeys: ['todolist'] }, { name: ' New Todolist', groupKeys: ['todolist'] },
{ name: ' New Empty Page', groupKeys: ['empty'] }, { name: ' New Empty Page', groupKeys: ['empty'] },
] as const; ];
const TemplateFactory = { const TemplateFactory = {
defaultTemplateList: defaultTemplateList, defaultTemplateList,
generatePageTemplateByGroupKeys(props: TemplateMeta): Template { generatePageTemplateByGroupKeys(props: TemplateMeta): Template {
const newTitle = props.name || 'Get Started with AFFiNE'; const newTitle = props.name || 'Get Started with AFFiNE';
const keys: GroupTemplateKeys[] = props.groupKeys || []; const keys: GroupTemplateKeys[] = props.groupKeys || [];

View File

@@ -541,6 +541,10 @@ export class BlockClient<
this.set_page(abstract_block); this.set_page(abstract_block);
}); });
this.#block_caches.set(abstract_block.id, abstract_block); this.#block_caches.set(abstract_block.id, abstract_block);
if (root && abstract_block.flavor === BlockFlavors.page) {
root.insertChildren(abstract_block);
}
return abstract_block; return abstract_block;
} }
} }