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 { EditorLoading } from '@affine/component/page-detail-skeleton';
|
||||||
import { Button, IconButton } from '@affine/component/ui/button';
|
import { Button, IconButton } from '@affine/component/ui/button';
|
||||||
import { Modal, useConfirmModal } from '@affine/component/ui/modal';
|
import { Modal, useConfirmModal } from '@affine/component/ui/modal';
|
||||||
@@ -304,6 +304,7 @@ const PageHistoryList = ({
|
|||||||
<PlanPrompt />
|
<PlanPrompt />
|
||||||
{historyListByDay.map(([day, list], i) => {
|
{historyListByDay.map(([day, list], i) => {
|
||||||
const collapsed = collapsedMap[i];
|
const collapsed = collapsedMap[i];
|
||||||
|
const isLastGroup = i === historyListByDay.length - 1;
|
||||||
return (
|
return (
|
||||||
<Collapsible.Root
|
<Collapsible.Root
|
||||||
open={!collapsed}
|
open={!collapsed}
|
||||||
@@ -328,8 +329,9 @@ const PageHistoryList = ({
|
|||||||
</div>
|
</div>
|
||||||
{day}
|
{day}
|
||||||
</Collapsible.Trigger>
|
</Collapsible.Trigger>
|
||||||
<Collapsible.Content>
|
<Collapsible.Content className={styles.historyItemGroupContent}>
|
||||||
{list.map((history, idx) => {
|
{list.map((history, idx) => {
|
||||||
|
const isLastItem = idx === list.length - 1;
|
||||||
return (
|
return (
|
||||||
<Fragment key={history.timestamp}>
|
<Fragment key={history.timestamp}>
|
||||||
<div
|
<div
|
||||||
@@ -341,14 +343,43 @@ const PageHistoryList = ({
|
|||||||
}}
|
}}
|
||||||
data-active={activeVersion === history.timestamp}
|
data-active={activeVersion === history.timestamp}
|
||||||
>
|
>
|
||||||
<button>
|
<span className={styles.historyItemTimestamp}>
|
||||||
{i18nTime(history.timestamp, {
|
{i18nTime(history.timestamp, {
|
||||||
absolute: { noDate: true, accuracy: 'minute' },
|
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>
|
</div>
|
||||||
{idx > list.length - 1 ? (
|
{isLastGroup && isLastItem && onLoadMore ? (
|
||||||
<div className={styles.historyItemGap} />
|
<Button
|
||||||
|
variant="plain"
|
||||||
|
loading={loadingMore}
|
||||||
|
disabled={loadingMore}
|
||||||
|
className={styles.historyItemLoadMore}
|
||||||
|
onClick={onLoadMore}
|
||||||
|
>
|
||||||
|
{t[
|
||||||
|
'com.affine.history.confirm-restore-modal.load-more'
|
||||||
|
]()}
|
||||||
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
@@ -357,17 +388,6 @@ const PageHistoryList = ({
|
|||||||
</Collapsible.Root>
|
</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.Viewport>
|
||||||
<Scrollable.Scrollbar />
|
<Scrollable.Scrollbar />
|
||||||
</Scrollable.Root>
|
</Scrollable.Root>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { cssVar } from '@toeverything/theme';
|
import { cssVar } from '@toeverything/theme';
|
||||||
|
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||||
import { createVar, globalStyle, style } from '@vanilla-extract/css';
|
import { createVar, globalStyle, style } from '@vanilla-extract/css';
|
||||||
import { range } from 'lodash-es';
|
import { range } from 'lodash-es';
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@ const previewTopOffset = createVar('preview-top-offset');
|
|||||||
export const root = style({
|
export const root = style({
|
||||||
height: '100%',
|
height: '100%',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
fontFamily: 'Inter',
|
||||||
vars: {
|
vars: {
|
||||||
[headerHeight]: '52px',
|
[headerHeight]: '52px',
|
||||||
[footerHeight]: '68px',
|
[footerHeight]: '68px',
|
||||||
@@ -119,32 +121,8 @@ export const editor = style({
|
|||||||
});
|
});
|
||||||
export const rowWrapper = style({
|
export const rowWrapper = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
height: '100%',
|
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
overflow: 'hidden',
|
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({
|
export const loadingContainer = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -166,6 +144,8 @@ export const historyListScrollable = style({
|
|||||||
export const historyListScrollableInner = style({
|
export const historyListScrollableInner = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
paddingBottom: 16,
|
||||||
|
height: '-webkit-fill-available',
|
||||||
});
|
});
|
||||||
export const historyListHeader = style({
|
export const historyListHeader = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -179,71 +159,101 @@ export const historyListHeader = style({
|
|||||||
export const historyItemGroup = style({
|
export const historyItemGroup = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
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({
|
export const historyItemGroupTitle = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: '0 12px 0 4px',
|
padding: '0 12px 0 4px',
|
||||||
|
borderRadius: 4,
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
color: cssVar('textSecondaryColor'),
|
fontSize: cssVar('fontXs'),
|
||||||
|
color: cssVarV2('text/secondary'),
|
||||||
|
fontWeight: 500,
|
||||||
|
textTransform: 'capitalize',
|
||||||
gap: 4,
|
gap: 4,
|
||||||
backgroundColor: cssVar('backgroundPrimaryColor'),
|
backgroundColor: cssVarV2('layer/background/primary'),
|
||||||
height: 28,
|
height: 24,
|
||||||
':hover': {
|
':hover': {
|
||||||
background: cssVar('hoverColor'),
|
background: cssVarV2('layer/background/hoverOverlay'),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
export const historyItem = style([
|
export const historyItem = style([
|
||||||
rowWrapper,
|
rowWrapper,
|
||||||
{
|
{
|
||||||
|
borderRadius: 4,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
gap: 4,
|
||||||
padding: '0 32px',
|
flexDirection: 'column',
|
||||||
height: 30,
|
padding: '4px 8px',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
selectors: {
|
':hover': {
|
||||||
'&:hover, &[data-active=true]': {
|
background: cssVarV2('layer/background/hoverOverlay'),
|
||||||
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'),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
export const historyItemGap = style([
|
|
||||||
rowWrapper,
|
export const historyItemTimestamp = style({
|
||||||
{
|
color: cssVarV2('text/primary'),
|
||||||
height: 16,
|
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([
|
export const historyItemLoadMore = style([
|
||||||
historyItem,
|
historyItem,
|
||||||
{
|
{
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
color: cssVar('textSecondaryColor'),
|
color: cssVarV2('text/secondary'),
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
borderRadius: 0,
|
textAlign: 'left',
|
||||||
selectors: {
|
alignItems: 'flex-start',
|
||||||
'&:hover': {
|
|
||||||
backgroundColor: cssVar('hoverColor'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
globalStyle(`${historyItem} button`, {
|
globalStyle(`${historyItem} button`, {
|
||||||
@@ -302,7 +312,7 @@ export const collapsedIconContainer = style({
|
|||||||
color: 'inherit',
|
color: 'inherit',
|
||||||
});
|
});
|
||||||
export const planPromptWrapper = style({
|
export const planPromptWrapper = style({
|
||||||
padding: '4px 12px',
|
padding: '4px 8px',
|
||||||
});
|
});
|
||||||
export const planPrompt = style({
|
export const planPrompt = style({
|
||||||
gap: 6,
|
gap: 6,
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { style } from '@vanilla-extract/css';
|
|||||||
|
|
||||||
export const publicUserLabel = style({
|
export const publicUserLabel = style({
|
||||||
fontSize: 'inherit',
|
fontSize: 'inherit',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const publicUserLabelLoading = style([
|
export const publicUserLabelLoading = style([
|
||||||
@@ -18,3 +20,7 @@ export const publicUserLabelRemoved = style([
|
|||||||
textDecoration: 'line-through',
|
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 { useCurrentServerService } from '@affine/core/components/providers/current-server-scope';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { useLiveData } from '@toeverything/infra';
|
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`
|
||||||
*/
|
*/
|
||||||
all(): string;
|
all(): string;
|
||||||
|
/**
|
||||||
|
* `current`
|
||||||
|
*/
|
||||||
|
current(): string;
|
||||||
/**
|
/**
|
||||||
* `Automatically check for new updates periodically.`
|
* `Automatically check for new updates periodically.`
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -135,6 +135,7 @@
|
|||||||
"Unknown User": "Unknown User",
|
"Unknown User": "Unknown User",
|
||||||
"Deleted User": "Deleted User",
|
"Deleted User": "Deleted User",
|
||||||
"all": "all",
|
"all": "all",
|
||||||
|
"current": "current",
|
||||||
"com.affine.aboutAFFiNE.autoCheckUpdate.description": "Automatically check for new updates periodically.",
|
"com.affine.aboutAFFiNE.autoCheckUpdate.description": "Automatically check for new updates periodically.",
|
||||||
"com.affine.aboutAFFiNE.autoCheckUpdate.title": "Check for updates automatically",
|
"com.affine.aboutAFFiNE.autoCheckUpdate.title": "Check for updates automatically",
|
||||||
"com.affine.aboutAFFiNE.autoDownloadUpdate.description": "Automatically download updates (to this device).",
|
"com.affine.aboutAFFiNE.autoDownloadUpdate.description": "Automatically download updates (to this device).",
|
||||||
|
|||||||
Reference in New Issue
Block a user