mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00: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',
|
||||
});
|
||||
|
||||
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({
|
||||
borderRadius: '2px',
|
||||
height: '100%',
|
||||
|
||||
@@ -27,7 +27,6 @@ import {
|
||||
generateFractionalIndexingKeyBetween,
|
||||
useService,
|
||||
} from '@toeverything/infra';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { fileTypeFromBuffer, type FileTypeResult } from 'file-type';
|
||||
import { nanoid } from 'nanoid';
|
||||
import type { ForwardRefRenderFunction, MouseEvent, ReactNode } from 'react';
|
||||
@@ -41,6 +40,8 @@ import {
|
||||
|
||||
import { WorkspaceDialogService } from '../../../../modules/dialogs';
|
||||
import { useSignalValue } from '../../../../modules/doc-info/utils';
|
||||
import { CircularProgress } from '../../components/loading';
|
||||
import { progressIconContainer } from '../../components/loading.css';
|
||||
import type {
|
||||
FileCellJsonValueType,
|
||||
FileCellRawValueType,
|
||||
@@ -198,38 +199,6 @@ type FileItemUploadingType = {
|
||||
order: string;
|
||||
};
|
||||
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 {
|
||||
private readonly cell: Cell<FileCellRawValueType, FileCellJsonValueType, {}>;
|
||||
@@ -481,7 +450,7 @@ const useFilePreview = (
|
||||
if (uploadProgress != null) {
|
||||
return {
|
||||
preview: (
|
||||
<div className={styles.progressIconContainer}>
|
||||
<div className={progressIconContainer}>
|
||||
<CircularProgress progress={uploadProgress.progress} />
|
||||
</div>
|
||||
),
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
} from 'react';
|
||||
|
||||
import { useSignalValue } from '../../../../../modules/doc-info/utils';
|
||||
import { Spinner } from '../../../components/loading';
|
||||
import * as styles from './style.css';
|
||||
|
||||
type BaseOptions = {
|
||||
@@ -315,14 +316,17 @@ export const MultiMemberSelect: React.FC<MemberManagerOptions> = props => {
|
||||
<input
|
||||
ref={inputRef}
|
||||
className={styles.memberSearchInput}
|
||||
placeholder="Search members..."
|
||||
placeholder={selectedMembers.length > 0 ? '' : 'Search members...'}
|
||||
value={memberManager.userListService.searchText$.value}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.memberListContainer} ref={memberListRef}>
|
||||
{isLoading ? (
|
||||
<div className={styles.loadingContainer}>Loading...</div>
|
||||
<div className={styles.loadingContainer}>
|
||||
<Spinner />
|
||||
Loading...
|
||||
</div>
|
||||
) : filteredMemberList.length === 0 ? (
|
||||
<div className={styles.noResultContainer}>No results</div>
|
||||
) : (
|
||||
|
||||
@@ -66,6 +66,7 @@ export const memberDeleteIcon = style({
|
||||
|
||||
export const memberPreviewContainer = style({
|
||||
display: 'flex',
|
||||
gap: '4px',
|
||||
alignItems: 'center',
|
||||
overflow: 'hidden',
|
||||
padding: '2px',
|
||||
@@ -75,14 +76,6 @@ export const memberPreviewContainer = style({
|
||||
backgroundColor: cssVarV2.button.secondary,
|
||||
});
|
||||
|
||||
export const memberPreview = style({
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
fontSize: '14px',
|
||||
lineHeight: '22px',
|
||||
});
|
||||
|
||||
export const memberItem = style({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
@@ -92,20 +85,12 @@ export const memberItem = style({
|
||||
borderRadius: '4px',
|
||||
});
|
||||
|
||||
export const memberItemContent = style({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '8px',
|
||||
overflow: 'hidden',
|
||||
});
|
||||
|
||||
export const memberName = style({
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
fontSize: '12px',
|
||||
lineHeight: '20px',
|
||||
padding: '0 4px',
|
||||
fontSize: '14px',
|
||||
lineHeight: '22px',
|
||||
flex: 1,
|
||||
});
|
||||
|
||||
@@ -118,9 +103,9 @@ export const avatar = style({
|
||||
|
||||
export const loadingContainer = style({
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: '16px',
|
||||
padding: '4px 0',
|
||||
gap: '8px',
|
||||
});
|
||||
|
||||
export const noResultContainer = style({
|
||||
|
||||
Reference in New Issue
Block a user