diff --git a/packages/frontend/component/src/components/attachment-viewer/error.tsx b/packages/frontend/component/src/components/attachment-viewer/error.tsx new file mode 100644 index 0000000000000..1a62a502a2f1e --- /dev/null +++ b/packages/frontend/component/src/components/attachment-viewer/error.tsx @@ -0,0 +1,26 @@ +import { ArrowDownBigIcon, PageIcon } from '@blocksuite/icons/rc'; +import clsx from 'clsx'; +import type { ReactElement } from 'react'; + +import { Button } from '../../ui/button'; +import * as styles from './styles.css'; + +interface ErrorProps { + isPDF: boolean; +} + +export const Error = (_: ErrorProps): ReactElement => { + return ( +
+ +

Unable to preview this file

+

.dmg file type not supported.

+
+ + +
+
+ ); +}; diff --git a/packages/frontend/component/src/components/attachment-viewer/index.tsx b/packages/frontend/component/src/components/attachment-viewer/index.tsx new file mode 100644 index 0000000000000..9c61e610fc39d --- /dev/null +++ b/packages/frontend/component/src/components/attachment-viewer/index.tsx @@ -0,0 +1,25 @@ +import { type ReactElement, useState } from 'react'; + +import { Error } from './error'; +import * as styles from './styles.css'; +import { Titlebar } from './titlebar'; +import { Viewer } from './viewer'; + +export const AttachmentViewer = (): ReactElement => { + const [isPDF] = useState(true); + + return ( +
+ + {isPDF ? : } +
+ ); +}; diff --git a/packages/frontend/component/src/components/attachment-viewer/styles.css.ts b/packages/frontend/component/src/components/attachment-viewer/styles.css.ts new file mode 100644 index 0000000000000..1f5a3d5789342 --- /dev/null +++ b/packages/frontend/component/src/components/attachment-viewer/styles.css.ts @@ -0,0 +1,164 @@ +import { cssVarV2 } from '@toeverything/theme/v2'; +import { style } from '@vanilla-extract/css'; + +export const viewerContainer = style({ + position: 'relative', + display: 'flex', + flexDirection: 'column', + width: '100%', +}); + +export const titlebar = style({ + display: 'flex', + justifyContent: 'space-between', + height: '52px', + padding: '10px 8px', + background: cssVarV2('layer/background/primary'), + fontSize: '12px', + fontWeight: 400, + color: cssVarV2('text/secondary'), + borderTopWidth: '0.5px', + borderTopStyle: 'solid', + borderTopColor: cssVarV2('layer/insideBorder/border'), +}); + +export const titlebarChild = style({ + selectors: { + [`${titlebar} > &`]: { + display: 'flex', + gap: '12px', + alignItems: 'center', + paddingLeft: '12px', + paddingRight: '12px', + }, + '&.zoom:not(.show)': { + display: 'none', + }, + }, +}); + +export const titlebarName = style({ + display: 'flex', +}); + +export const body = style({ + display: 'flex', + flex: 1, + position: 'relative', + selectors: { + '&:before': { + position: 'absolute', + content: '', + width: '100%', + height: '100%', + zIndex: -1, + }, + '&:not(.gridding):before': { + backgroundColor: cssVarV2('layer/background/secondary'), + }, + '&.gridding:before': { + opacity: 0.25, + backgroundSize: '20px 20px', + backgroundImage: `linear-gradient(${cssVarV2('button/grabber/default')} 1px, transparent 1px), linear-gradient(to right, ${cssVarV2('button/grabber/default')} 1px, transparent 1px)`, + }, + '&.scrollable': { + overflowY: 'auto', + }, + }, +}); + +export const error = style({ + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + gap: '4px', +}); + +export const errorTitle = style({ + fontSize: '15px', + fontWeight: 500, + lineHeight: '24px', + color: cssVarV2('text/primary'), + marginTop: '12px', +}); + +export const errorMessage = style({ + fontSize: '12px', + fontWeight: 500, + lineHeight: '20px', + color: cssVarV2('text/tertiary'), +}); + +export const errorBtns = style({ + display: 'flex', + flexDirection: 'column', + gap: '10px', + marginTop: '28px', +}); + +export const viewer = style({}); + +export const viewerViewport = style({}); + +export const viewerPage = style({ + margin: '20px auto', + background: cssVarV2('layer/white'), + borderWidth: '1px', + borderStyle: 'solid', + borderColor: cssVarV2('layer/insideBorder/border'), + boxShadow: + '0px 4px 20px 0px var(--transparent-black-200, rgba(0, 0, 0, 0.10))', +}); + +export const thumbnails = style({ + position: 'absolute', + boxSizing: 'border-box', + width: '120px', + padding: '12px', + right: '30px', + bottom: '30px', + borderRadius: '8px', + borderWidth: '1px', + borderStyle: 'solid', + borderColor: cssVarV2('layer/insideBorder/border'), + backgroundColor: cssVarV2('layer/background/primary'), + boxShadow: cssVarV2('shadow/overlayPanelShadow/2-color'), + fontSize: '12px', + fontWeight: 500, + lineHeight: '20px', + color: cssVarV2('text/secondary'), +}); + +export const thumbnailsPages = style({ + display: 'flex', + flexDirection: 'column', + gap: '12px', + selectors: { + '&.collapsed': { + display: 'none', + }, + '&:not(.collapsed)': { + marginBottom: '8px', + }, + }, +}); + +export const thumbnailsPage = style({ + display: 'flex', + width: '100%', + borderRadius: '4px', + borderWidth: '1px', + borderStyle: 'solid', + borderColor: cssVarV2('layer/insideBorder/border'), + selectors: { + '&.selected': { + borderColor: '#29A3FA', + }, + }, +}); + +export const thumbnailsIndicator = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', +}); diff --git a/packages/frontend/component/src/components/attachment-viewer/thumbnails.tsx b/packages/frontend/component/src/components/attachment-viewer/thumbnails.tsx new file mode 100644 index 0000000000000..f0abf93da01ea --- /dev/null +++ b/packages/frontend/component/src/components/attachment-viewer/thumbnails.tsx @@ -0,0 +1,44 @@ +import { CollapseIcon, ExpandIcon } from '@blocksuite/icons/rc'; +import clsx from 'clsx'; +import { type ReactElement,useState } from 'react'; + +import { IconButton } from '../../ui/button'; +import * as styles from './styles.css'; + +export const Thumbnails = (): ReactElement => { + const [collapsed, setCollapsed] = useState(true); + + return ( +
+
+
+
+
+
+
+
+ 1/3 +
+ : } + onClick={() => setCollapsed(state => !state)} + /> +
+
+ ); +}; diff --git a/packages/frontend/component/src/components/pdf-viewer/titlebar.tsx b/packages/frontend/component/src/components/attachment-viewer/titlebar.tsx similarity index 79% rename from packages/frontend/component/src/components/pdf-viewer/titlebar.tsx rename to packages/frontend/component/src/components/attachment-viewer/titlebar.tsx index 7db36c3c269a9..a2a471ed1c14c 100644 --- a/packages/frontend/component/src/components/pdf-viewer/titlebar.tsx +++ b/packages/frontend/component/src/components/attachment-viewer/titlebar.tsx @@ -5,6 +5,7 @@ import { ZoomDownIcon, ZoomUpIcon, } from '@blocksuite/icons/rc'; +import clsx from 'clsx'; import { useState } from 'react'; import { IconButton } from '../../ui/button'; @@ -16,7 +17,9 @@ export interface TitlebarProps { name: string; ext: string; size: number; + unit: string; zoom: number; + isPDF: boolean; } const items = [ @@ -39,7 +42,14 @@ export const MenuItems = () => )); -export const Titlebar = ({ name, ext, size, zoom = 100 }: TitlebarProps) => { +export const Titlebar = ({ + name, + ext, + size, + unit, + isPDF = false, + zoom = 100, +}: TitlebarProps) => { const [openMenu, setOpenMenu] = useState(false); return ( @@ -49,7 +59,10 @@ export const Titlebar = ({ name, ext, size, zoom = 100 }: TitlebarProps) => {
{name}
{ext} -
{size}MB
+
+ {size} + {unit} +
}> } @@ -59,13 +72,22 @@ export const Titlebar = ({ name, ext, size, zoom = 100 }: TitlebarProps) => { }} contentOptions={{ side: 'bottom', + align: 'center', avoidCollisions: false, }} > }> -
+
}>
{zoom}%
}> diff --git a/packages/frontend/component/src/components/attachment-viewer/viewer.tsx b/packages/frontend/component/src/components/attachment-viewer/viewer.tsx new file mode 100644 index 0000000000000..bffc3ae0884c1 --- /dev/null +++ b/packages/frontend/component/src/components/attachment-viewer/viewer.tsx @@ -0,0 +1,101 @@ +import clsx from 'clsx'; +import type { ReactElement } from 'react'; + +import { Scrollable } from '../../ui/scrollbar'; +import * as styles from './styles.css'; +import { Thumbnails } from './thumbnails'; + +interface ViewerProps {} + +export const Viewer = (_: ViewerProps): ReactElement => { + return ( + <> + + +
+ 1 +
+
+ 2 +
+
+ 3 +
+
+ 4 +
+
+ 5 +
+
+ 6 +
+
+ 7 +
+
+ 8 +
+
+ 9 +
+
+ 10 +
+
+ 11 +
+
+ 12 +
+
+ +
+ + + ); +}; diff --git a/packages/frontend/component/src/components/pdf-viewer/index.tsx b/packages/frontend/component/src/components/pdf-viewer/index.tsx deleted file mode 100644 index a8f5177575d8a..0000000000000 --- a/packages/frontend/component/src/components/pdf-viewer/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import type { ReactElement } from 'react'; - -import { Titlebar } from './titlebar'; - -export const PDFViewer = (): ReactElement => { - return ( - <> - -
{'PDF Viewer'}
-
{'PDF ...'}
- - ); -}; diff --git a/packages/frontend/component/src/components/pdf-viewer/styles.css.ts b/packages/frontend/component/src/components/pdf-viewer/styles.css.ts deleted file mode 100644 index 6228cc21a09ee..0000000000000 --- a/packages/frontend/component/src/components/pdf-viewer/styles.css.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { cssVarV2 } from '@toeverything/theme/v2'; -import { style } from '@vanilla-extract/css'; - -export const titlebar = style({ - display: 'flex', - justifyContent: 'space-between', - width: '100%', - height: '52px', - padding: '10px 0 10px 8px', - background: cssVarV2('layer/background/primary'), - fontSize: '12px', - fontWeight: 400, - color: cssVarV2('text/secondary'), - borderTopWidth: '0.5px', - borderTopStyle: 'solid', - borderTopColor: cssVarV2('layer/insideBorder/border'), -}); - -export const titlebarChild = style({ - selectors: { - [`${titlebar} > &`]: { - display: 'flex', - gap: '12px', - alignItems: 'center', - paddingLeft: '12px', - paddingRight: '12px', - }, - }, -}); - -export const titlebarName = style({ - display: 'flex', -}); diff --git a/packages/frontend/core/src/desktop/pages/workspace/attachment/index.tsx b/packages/frontend/core/src/desktop/pages/workspace/attachment/index.tsx index ebf87001d8a8f..91ebbb2c15221 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/attachment/index.tsx +++ b/packages/frontend/core/src/desktop/pages/workspace/attachment/index.tsx @@ -1,11 +1,23 @@ -import { PDFViewer } from '@affine/component/pdf-viewer'; +import { AttachmentViewer } from '@affine/component/attachment-viewer'; import type { ReactElement } from 'react'; +import { + // useIsActiveView, + ViewBody, + ViewHeader, + ViewIcon, + ViewTitle, +} from '../../../../modules/workbench'; + export const AttachmentPage = (): ReactElement => { return ( <> - -
{'Attachment Viewer'}
+ + + + + + ); }; diff --git a/packages/frontend/core/src/modules/workbench/constants.tsx b/packages/frontend/core/src/modules/workbench/constants.tsx index 719d816fd4701..7439354f5e8a8 100644 --- a/packages/frontend/core/src/modules/workbench/constants.tsx +++ b/packages/frontend/core/src/modules/workbench/constants.tsx @@ -1,7 +1,9 @@ import { AllDocsIcon, + AttachmentIcon, DeleteIcon, EdgelessIcon, + ExportToPdfIcon, PageIcon, TagIcon, TodayIcon, @@ -18,6 +20,8 @@ export const iconNameToIcon = { journal: , tag: , trash: , + attachment: , + pdf: , } satisfies Record; export type ViewIconName = keyof typeof iconNameToIcon;