mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
feat(core): adjust history modal styles (#11675)
- add avatar/name info to each history snapshot item - add avatar to audio transcription job owner fix AF-2483 
This commit is contained in:
@@ -1,18 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const useBlobUrl = (buffer?: Buffer) => {
|
||||
const [blobUrl, setBlobUrl] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
const url = URL.createObjectURL(new Blob([buffer]));
|
||||
setBlobUrl(url);
|
||||
return () => {
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
}, [buffer]);
|
||||
|
||||
return blobUrl;
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Loading, Scrollable } from '@affine/component';
|
||||
import { Avatar, Loading, Scrollable } from '@affine/component';
|
||||
import { EditorLoading } from '@affine/component/page-detail-skeleton';
|
||||
import { Button, IconButton } from '@affine/component/ui/button';
|
||||
import { Modal, useConfirmModal } from '@affine/component/ui/modal';
|
||||
@@ -304,6 +304,7 @@ const PageHistoryList = ({
|
||||
<PlanPrompt />
|
||||
{historyListByDay.map(([day, list], i) => {
|
||||
const collapsed = collapsedMap[i];
|
||||
const isLastGroup = i === historyListByDay.length - 1;
|
||||
return (
|
||||
<Collapsible.Root
|
||||
open={!collapsed}
|
||||
@@ -328,8 +329,9 @@ const PageHistoryList = ({
|
||||
</div>
|
||||
{day}
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content>
|
||||
<Collapsible.Content className={styles.historyItemGroupContent}>
|
||||
{list.map((history, idx) => {
|
||||
const isLastItem = idx === list.length - 1;
|
||||
return (
|
||||
<Fragment key={history.timestamp}>
|
||||
<div
|
||||
@@ -341,14 +343,43 @@ const PageHistoryList = ({
|
||||
}}
|
||||
data-active={activeVersion === history.timestamp}
|
||||
>
|
||||
<button>
|
||||
<span className={styles.historyItemTimestamp}>
|
||||
{i18nTime(history.timestamp, {
|
||||
absolute: { noDate: true, accuracy: 'minute' },
|
||||
})}
|
||||
</button>
|
||||
{activeVersion === history.timestamp ? (
|
||||
<>
|
||||
<span>·</span>
|
||||
<div className={styles.historyItemCurrent}>
|
||||
{t['current']()}
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</span>
|
||||
<div className={styles.historyItemNameWrapper}>
|
||||
<Avatar
|
||||
className={styles.historyItemAvatar}
|
||||
url={history.editor?.avatarUrl ?? ''}
|
||||
name={history.editor?.name ?? ''}
|
||||
size={22}
|
||||
/>
|
||||
<span className={styles.historyItemName}>
|
||||
{history.editor?.name ?? t['unnamed']()}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{idx > list.length - 1 ? (
|
||||
<div className={styles.historyItemGap} />
|
||||
{isLastGroup && isLastItem && onLoadMore ? (
|
||||
<Button
|
||||
variant="plain"
|
||||
loading={loadingMore}
|
||||
disabled={loadingMore}
|
||||
className={styles.historyItemLoadMore}
|
||||
onClick={onLoadMore}
|
||||
>
|
||||
{t[
|
||||
'com.affine.history.confirm-restore-modal.load-more'
|
||||
]()}
|
||||
</Button>
|
||||
) : null}
|
||||
</Fragment>
|
||||
);
|
||||
@@ -357,17 +388,6 @@ const PageHistoryList = ({
|
||||
</Collapsible.Root>
|
||||
);
|
||||
})}
|
||||
{onLoadMore ? (
|
||||
<Button
|
||||
variant="plain"
|
||||
loading={loadingMore}
|
||||
disabled={loadingMore}
|
||||
className={styles.historyItemLoadMore}
|
||||
onClick={onLoadMore}
|
||||
>
|
||||
{t['com.affine.history.confirm-restore-modal.load-more']()}
|
||||
</Button>
|
||||
) : null}
|
||||
</Scrollable.Viewport>
|
||||
<Scrollable.Scrollbar />
|
||||
</Scrollable.Root>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { createVar, globalStyle, style } from '@vanilla-extract/css';
|
||||
import { range } from 'lodash-es';
|
||||
|
||||
@@ -9,6 +10,7 @@ const previewTopOffset = createVar('preview-top-offset');
|
||||
export const root = style({
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
fontFamily: 'Inter',
|
||||
vars: {
|
||||
[headerHeight]: '52px',
|
||||
[footerHeight]: '68px',
|
||||
@@ -119,32 +121,8 @@ export const editor = style({
|
||||
});
|
||||
export const rowWrapper = style({
|
||||
display: 'flex',
|
||||
height: '100%',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
':before': {
|
||||
content: '""',
|
||||
width: 1,
|
||||
height: '100%',
|
||||
backgroundColor: cssVar('borderColor'),
|
||||
position: 'absolute',
|
||||
left: 16,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
transform: 'translate(-50%)',
|
||||
},
|
||||
selectors: {
|
||||
'&:is(:last-of-type, :first-of-type):not(:last-of-type:first-of-type)::before':
|
||||
{
|
||||
height: '50%',
|
||||
},
|
||||
'&:last-of-type:first-of-type::before': {
|
||||
display: 'none',
|
||||
},
|
||||
'&:first-of-type::before': {
|
||||
top: '50%',
|
||||
},
|
||||
},
|
||||
});
|
||||
export const loadingContainer = style({
|
||||
display: 'flex',
|
||||
@@ -166,6 +144,8 @@ export const historyListScrollable = style({
|
||||
export const historyListScrollableInner = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
paddingBottom: 16,
|
||||
height: '-webkit-fill-available',
|
||||
});
|
||||
export const historyListHeader = style({
|
||||
display: 'flex',
|
||||
@@ -179,71 +159,101 @@ export const historyListHeader = style({
|
||||
export const historyItemGroup = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: '0 8px',
|
||||
gap: 8,
|
||||
marginTop: 4,
|
||||
marginBottom: 4,
|
||||
});
|
||||
export const historyItemGroupContent = style({
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 8,
|
||||
paddingLeft: 24,
|
||||
'::before': {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 15.5,
|
||||
content: '""',
|
||||
display: 'block',
|
||||
height: '100%',
|
||||
width: '1px',
|
||||
borderLeft: `1px solid ${cssVar('borderColor')}`,
|
||||
},
|
||||
});
|
||||
export const historyItemGroupTitle = style({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
padding: '0 12px 0 4px',
|
||||
borderRadius: 4,
|
||||
whiteSpace: 'nowrap',
|
||||
color: cssVar('textSecondaryColor'),
|
||||
fontSize: cssVar('fontXs'),
|
||||
color: cssVarV2('text/secondary'),
|
||||
fontWeight: 500,
|
||||
textTransform: 'capitalize',
|
||||
gap: 4,
|
||||
backgroundColor: cssVar('backgroundPrimaryColor'),
|
||||
height: 28,
|
||||
backgroundColor: cssVarV2('layer/background/primary'),
|
||||
height: 24,
|
||||
':hover': {
|
||||
background: cssVar('hoverColor'),
|
||||
background: cssVarV2('layer/background/hoverOverlay'),
|
||||
},
|
||||
});
|
||||
export const historyItem = style([
|
||||
rowWrapper,
|
||||
{
|
||||
borderRadius: 4,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
padding: '0 32px',
|
||||
height: 30,
|
||||
gap: 4,
|
||||
flexDirection: 'column',
|
||||
padding: '4px 8px',
|
||||
cursor: 'pointer',
|
||||
selectors: {
|
||||
'&:hover, &[data-active=true]': {
|
||||
backgroundColor: cssVar('hoverColor'),
|
||||
},
|
||||
// draw circle
|
||||
'&::after': {
|
||||
content: '""',
|
||||
width: 7,
|
||||
height: 7,
|
||||
backgroundColor: cssVar('backgroundSecondaryColor'),
|
||||
borderRadius: '50%',
|
||||
border: `1px solid ${cssVar('borderColor')}`,
|
||||
position: 'absolute',
|
||||
left: 16,
|
||||
top: '50%',
|
||||
bottom: 0,
|
||||
transform: 'translate(-50%, -50%)',
|
||||
},
|
||||
'&[data-active=true]::after': {
|
||||
backgroundColor: cssVar('primaryColor'),
|
||||
borderColor: cssVar('black30'),
|
||||
},
|
||||
':hover': {
|
||||
background: cssVarV2('layer/background/hoverOverlay'),
|
||||
},
|
||||
},
|
||||
]);
|
||||
export const historyItemGap = style([
|
||||
rowWrapper,
|
||||
{
|
||||
height: 16,
|
||||
},
|
||||
]);
|
||||
|
||||
export const historyItemTimestamp = style({
|
||||
color: cssVarV2('text/primary'),
|
||||
borderRadius: 4,
|
||||
fontSize: cssVar('fontXs'),
|
||||
fontWeight: 500,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '0.5em',
|
||||
});
|
||||
|
||||
export const historyItemCurrent = style({
|
||||
color: cssVarV2('text/emphasis'),
|
||||
textTransform: 'capitalize',
|
||||
});
|
||||
|
||||
export const historyItemNameWrapper = style({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 4,
|
||||
color: cssVarV2('text/secondary'),
|
||||
fontSize: cssVar('fontXs'),
|
||||
});
|
||||
|
||||
export const historyItemAvatar = style({
|
||||
backgroundColor: cssVarV2('layer/background/secondary'),
|
||||
});
|
||||
|
||||
export const historyItemName = style({
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
});
|
||||
|
||||
export const historyItemLoadMore = style([
|
||||
historyItem,
|
||||
{
|
||||
cursor: 'pointer',
|
||||
color: cssVar('textSecondaryColor'),
|
||||
color: cssVarV2('text/secondary'),
|
||||
flexShrink: 0,
|
||||
borderRadius: 0,
|
||||
selectors: {
|
||||
'&:hover': {
|
||||
backgroundColor: cssVar('hoverColor'),
|
||||
},
|
||||
},
|
||||
textAlign: 'left',
|
||||
alignItems: 'flex-start',
|
||||
},
|
||||
]);
|
||||
globalStyle(`${historyItem} button`, {
|
||||
@@ -302,7 +312,7 @@ export const collapsedIconContainer = style({
|
||||
color: 'inherit',
|
||||
});
|
||||
export const planPromptWrapper = style({
|
||||
padding: '4px 12px',
|
||||
padding: '4px 8px',
|
||||
});
|
||||
export const planPrompt = style({
|
||||
gap: 6,
|
||||
|
||||
@@ -2,6 +2,8 @@ import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const publicUserLabel = style({
|
||||
fontSize: 'inherit',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
});
|
||||
|
||||
export const publicUserLabelLoading = style([
|
||||
@@ -18,3 +20,7 @@ export const publicUserLabelRemoved = style([
|
||||
textDecoration: 'line-through',
|
||||
},
|
||||
]);
|
||||
|
||||
export const publicUserLabelAvatar = style({
|
||||
marginRight: '0.5em',
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Avatar } from '@affine/component';
|
||||
import { useCurrentServerService } from '@affine/core/components/providers/current-server-scope';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { useLiveData } from '@toeverything/infra';
|
||||
@@ -34,5 +35,15 @@ export const PublicUserLabel = ({ id }: { id: string }) => {
|
||||
);
|
||||
}
|
||||
|
||||
return <span className={styles.publicUserLabel}>{user?.name}</span>;
|
||||
return (
|
||||
<span className={styles.publicUserLabel}>
|
||||
<Avatar
|
||||
url={user?.avatar}
|
||||
name={user?.name ?? ''}
|
||||
size={20}
|
||||
className={styles.publicUserLabelAvatar}
|
||||
/>
|
||||
{user?.name}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -585,6 +585,10 @@ export function useAFFiNEI18N(): {
|
||||
* `all`
|
||||
*/
|
||||
all(): string;
|
||||
/**
|
||||
* `current`
|
||||
*/
|
||||
current(): string;
|
||||
/**
|
||||
* `Automatically check for new updates periodically.`
|
||||
*/
|
||||
|
||||
@@ -135,6 +135,7 @@
|
||||
"Unknown User": "Unknown User",
|
||||
"Deleted User": "Deleted User",
|
||||
"all": "all",
|
||||
"current": "current",
|
||||
"com.affine.aboutAFFiNE.autoCheckUpdate.description": "Automatically check for new updates periodically.",
|
||||
"com.affine.aboutAFFiNE.autoCheckUpdate.title": "Check for updates automatically",
|
||||
"com.affine.aboutAFFiNE.autoDownloadUpdate.description": "Automatically download updates (to this device).",
|
||||
|
||||
Reference in New Issue
Block a user