mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-17 14:27:02 +08:00
@@ -0,0 +1,23 @@
|
|||||||
|
import { keyframes, style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
|
export const progressSvg = style({
|
||||||
|
transform: 'rotate(-90deg)',
|
||||||
|
});
|
||||||
|
export const progressIconContainer = style({
|
||||||
|
position: 'relative',
|
||||||
|
width: '24px',
|
||||||
|
height: '24px',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
});
|
||||||
|
export const progressCircle = style({
|
||||||
|
transition: 'stroke-dasharray 0.3s ease-in-out',
|
||||||
|
});
|
||||||
|
const spin = keyframes({
|
||||||
|
from: { transform: 'rotate(0deg)' },
|
||||||
|
to: { transform: 'rotate(360deg)' },
|
||||||
|
});
|
||||||
|
export const spinnerAnimation = style({
|
||||||
|
animation: `${spin} 1s linear infinite`,
|
||||||
|
});
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||||
|
|
||||||
|
import { progressCircle, progressSvg, spinnerAnimation } from './loading.css';
|
||||||
|
|
||||||
|
export const CircularProgress = ({ progress }: { progress: number }) => {
|
||||||
|
const circumference = 2 * Math.PI * 10;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" className={progressSvg}>
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
fill="none"
|
||||||
|
stroke={cssVarV2.loading.background}
|
||||||
|
strokeWidth="4"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
fill="none"
|
||||||
|
stroke={cssVarV2.loading.foreground}
|
||||||
|
strokeWidth="4"
|
||||||
|
strokeDasharray={`${(progress / 100) * circumference} ${circumference}`}
|
||||||
|
strokeLinecap="round"
|
||||||
|
className={progressCircle}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Spinner = () => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
className={spinnerAnimation}
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
fill="none"
|
||||||
|
stroke={cssVarV2.loading.background}
|
||||||
|
strokeWidth="4"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
fill="none"
|
||||||
|
stroke={cssVarV2.loading.foreground}
|
||||||
|
strokeWidth="4"
|
||||||
|
strokeDasharray="15 85"
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -104,23 +104,6 @@ export const fileItemImagePreview = style({
|
|||||||
borderRadius: '2px',
|
borderRadius: '2px',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const progressIconContainer = style({
|
|
||||||
position: 'relative',
|
|
||||||
width: '24px',
|
|
||||||
height: '24px',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
});
|
|
||||||
|
|
||||||
export const progressSvg = style({
|
|
||||||
transform: 'rotate(-90deg)',
|
|
||||||
});
|
|
||||||
|
|
||||||
export const progressCircle = style({
|
|
||||||
transition: 'stroke-dasharray 0.3s ease-in-out',
|
|
||||||
});
|
|
||||||
|
|
||||||
export const imagePreviewIcon = style({
|
export const imagePreviewIcon = style({
|
||||||
borderRadius: '2px',
|
borderRadius: '2px',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import {
|
|||||||
generateFractionalIndexingKeyBetween,
|
generateFractionalIndexingKeyBetween,
|
||||||
useService,
|
useService,
|
||||||
} from '@toeverything/infra';
|
} from '@toeverything/infra';
|
||||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
|
||||||
import { fileTypeFromBuffer, type FileTypeResult } from 'file-type';
|
import { fileTypeFromBuffer, type FileTypeResult } from 'file-type';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import type { ForwardRefRenderFunction, MouseEvent, ReactNode } from 'react';
|
import type { ForwardRefRenderFunction, MouseEvent, ReactNode } from 'react';
|
||||||
@@ -41,6 +40,8 @@ import {
|
|||||||
|
|
||||||
import { WorkspaceDialogService } from '../../../../modules/dialogs';
|
import { WorkspaceDialogService } from '../../../../modules/dialogs';
|
||||||
import { useSignalValue } from '../../../../modules/doc-info/utils';
|
import { useSignalValue } from '../../../../modules/doc-info/utils';
|
||||||
|
import { CircularProgress } from '../../components/loading';
|
||||||
|
import { progressIconContainer } from '../../components/loading.css';
|
||||||
import type {
|
import type {
|
||||||
FileCellJsonValueType,
|
FileCellJsonValueType,
|
||||||
FileCellRawValueType,
|
FileCellRawValueType,
|
||||||
@@ -198,38 +199,6 @@ type FileItemUploadingType = {
|
|||||||
order: string;
|
order: string;
|
||||||
};
|
};
|
||||||
type FileItemRenderType = FileItemDoneType | FileItemUploadingType;
|
type FileItemRenderType = FileItemDoneType | FileItemUploadingType;
|
||||||
const CircularProgress = ({ progress }: { progress: number }) => {
|
|
||||||
const circumference = 2 * Math.PI * 10;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
width="18"
|
|
||||||
height="18"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
className={styles.progressSvg}
|
|
||||||
>
|
|
||||||
<circle
|
|
||||||
cx="12"
|
|
||||||
cy="12"
|
|
||||||
r="10"
|
|
||||||
fill="none"
|
|
||||||
stroke={cssVarV2.loading.background}
|
|
||||||
strokeWidth="4"
|
|
||||||
/>
|
|
||||||
<circle
|
|
||||||
cx="12"
|
|
||||||
cy="12"
|
|
||||||
r="10"
|
|
||||||
fill="none"
|
|
||||||
stroke={cssVarV2.loading.foreground}
|
|
||||||
strokeWidth="4"
|
|
||||||
strokeDasharray={`${(progress / 100) * circumference} ${circumference}`}
|
|
||||||
strokeLinecap="round"
|
|
||||||
className={styles.progressCircle}
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
class FileCellManager {
|
class FileCellManager {
|
||||||
private readonly cell: Cell<FileCellRawValueType, FileCellJsonValueType, {}>;
|
private readonly cell: Cell<FileCellRawValueType, FileCellJsonValueType, {}>;
|
||||||
@@ -481,7 +450,7 @@ const useFilePreview = (
|
|||||||
if (uploadProgress != null) {
|
if (uploadProgress != null) {
|
||||||
return {
|
return {
|
||||||
preview: (
|
preview: (
|
||||||
<div className={styles.progressIconContainer}>
|
<div className={progressIconContainer}>
|
||||||
<CircularProgress progress={uploadProgress.progress} />
|
<CircularProgress progress={uploadProgress.progress} />
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
import { useSignalValue } from '../../../../../modules/doc-info/utils';
|
import { useSignalValue } from '../../../../../modules/doc-info/utils';
|
||||||
|
import { Spinner } from '../../../components/loading';
|
||||||
import * as styles from './style.css';
|
import * as styles from './style.css';
|
||||||
|
|
||||||
type BaseOptions = {
|
type BaseOptions = {
|
||||||
@@ -315,14 +316,17 @@ export const MultiMemberSelect: React.FC<MemberManagerOptions> = props => {
|
|||||||
<input
|
<input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
className={styles.memberSearchInput}
|
className={styles.memberSearchInput}
|
||||||
placeholder="Search members..."
|
placeholder={selectedMembers.length > 0 ? '' : 'Search members...'}
|
||||||
value={memberManager.userListService.searchText$.value}
|
value={memberManager.userListService.searchText$.value}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.memberListContainer} ref={memberListRef}>
|
<div className={styles.memberListContainer} ref={memberListRef}>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className={styles.loadingContainer}>Loading...</div>
|
<div className={styles.loadingContainer}>
|
||||||
|
<Spinner />
|
||||||
|
Loading...
|
||||||
|
</div>
|
||||||
) : filteredMemberList.length === 0 ? (
|
) : filteredMemberList.length === 0 ? (
|
||||||
<div className={styles.noResultContainer}>No results</div>
|
<div className={styles.noResultContainer}>No results</div>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ export const memberDeleteIcon = style({
|
|||||||
|
|
||||||
export const memberPreviewContainer = style({
|
export const memberPreviewContainer = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
gap: '4px',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
padding: '2px',
|
padding: '2px',
|
||||||
@@ -75,14 +76,6 @@ export const memberPreviewContainer = style({
|
|||||||
backgroundColor: cssVarV2.button.secondary,
|
backgroundColor: cssVarV2.button.secondary,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const memberPreview = style({
|
|
||||||
overflow: 'hidden',
|
|
||||||
textOverflow: 'ellipsis',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
fontSize: '14px',
|
|
||||||
lineHeight: '22px',
|
|
||||||
});
|
|
||||||
|
|
||||||
export const memberItem = style({
|
export const memberItem = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@@ -92,20 +85,12 @@ export const memberItem = style({
|
|||||||
borderRadius: '4px',
|
borderRadius: '4px',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const memberItemContent = style({
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '8px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
});
|
|
||||||
|
|
||||||
export const memberName = style({
|
export const memberName = style({
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
fontSize: '12px',
|
fontSize: '14px',
|
||||||
lineHeight: '20px',
|
lineHeight: '22px',
|
||||||
padding: '0 4px',
|
|
||||||
flex: 1,
|
flex: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -118,9 +103,9 @@ export const avatar = style({
|
|||||||
|
|
||||||
export const loadingContainer = style({
|
export const loadingContainer = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: '16px',
|
padding: '4px 0',
|
||||||
|
gap: '8px',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const noResultContainer = style({
|
export const noResultContainer = style({
|
||||||
|
|||||||
Reference in New Issue
Block a user