mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-11 20:08:37 +00:00
style: enable no-non-null-assertion rule (#2723)
Co-authored-by: Peng Xiao <pengxiao@outlook.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { CloseIcon, NewIcon, ResetIcon } from '@blocksuite/icons';
|
||||
import clsx from 'clsx';
|
||||
import { atom, useAtomValue, useSetAtom } from 'jotai';
|
||||
import { startTransition } from 'react';
|
||||
import { startTransition, useCallback } from 'react';
|
||||
|
||||
import * as styles from './index.css';
|
||||
import {
|
||||
@@ -50,53 +50,67 @@ export function AppUpdaterButton({ className, style }: AddPageButtonProps) {
|
||||
const downloadProgress = useAtomValue(downloadProgressAtom);
|
||||
const setChangelogCheckAtom = useSetAtom(changelogCheckedAtom);
|
||||
|
||||
const onDismissCurrentChangelog = () => {
|
||||
const onDismissCurrentChangelog = useCallback(() => {
|
||||
if (!currentVersion) {
|
||||
return;
|
||||
}
|
||||
startTransition(() =>
|
||||
setChangelogCheckAtom(mapping => {
|
||||
return {
|
||||
...mapping,
|
||||
[currentVersion!]: true,
|
||||
[currentVersion]: true,
|
||||
};
|
||||
})
|
||||
);
|
||||
};
|
||||
}, [currentVersion, setChangelogCheckAtom]);
|
||||
const onClickUpdate = useCallback(() => {
|
||||
if (updateReady) {
|
||||
window.apis?.updater.quitAndInstall();
|
||||
} else if (updateAvailable) {
|
||||
if (updateAvailable.allowAutoUpdate) {
|
||||
// wait for download to finish
|
||||
} else {
|
||||
window.open(
|
||||
`https://github.com/toeverything/AFFiNE/releases/tag/v${currentVersion}`,
|
||||
'_blank'
|
||||
);
|
||||
}
|
||||
} else if (currentChangelogUnread) {
|
||||
window.open(config.changelogUrl, '_blank');
|
||||
onDismissCurrentChangelog();
|
||||
} else {
|
||||
throw new Unreachable();
|
||||
}
|
||||
}, [
|
||||
currentChangelogUnread,
|
||||
currentVersion,
|
||||
onDismissCurrentChangelog,
|
||||
updateAvailable,
|
||||
updateReady,
|
||||
]);
|
||||
|
||||
if (!updateAvailable && !currentChangelogUnread) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updateAvailableNode = updateAvailable
|
||||
? updateAvailable.allowAutoUpdate
|
||||
? renderUpdateAvailableAllowAutoUpdate()
|
||||
: renderUpdateAvailableNotAllowAutoUpdate()
|
||||
: null;
|
||||
const whatsNew =
|
||||
!updateAvailable && currentChangelogUnread ? renderWhatsNew() : null;
|
||||
|
||||
return (
|
||||
<button
|
||||
style={style}
|
||||
className={clsx([styles.root, className])}
|
||||
data-has-update={updateAvailable ? 'true' : 'false'}
|
||||
data-disabled={updateAvailable?.allowAutoUpdate && !updateReady}
|
||||
onClick={() => {
|
||||
if (updateReady) {
|
||||
window.apis?.updater.quitAndInstall();
|
||||
} else if (updateAvailable) {
|
||||
if (updateAvailable.allowAutoUpdate) {
|
||||
// wait for download to finish
|
||||
} else {
|
||||
window.open(
|
||||
`https://github.com/toeverything/AFFiNE/releases/tag/v${currentVersion}`,
|
||||
'_blank'
|
||||
);
|
||||
}
|
||||
} else if (currentChangelogUnread) {
|
||||
window.open(config.changelogUrl, '_blank');
|
||||
onDismissCurrentChangelog();
|
||||
} else {
|
||||
throw new Unreachable();
|
||||
}
|
||||
}}
|
||||
onClick={onClickUpdate}
|
||||
>
|
||||
{updateAvailable &&
|
||||
(updateAvailable.allowAutoUpdate
|
||||
? renderUpdateAvailableAllowAutoUpdate()
|
||||
: renderUpdateAvailableNotAllowAutoUpdate())}
|
||||
|
||||
{!updateAvailable && currentChangelogUnread && renderWhatsNew()}
|
||||
{updateAvailableNode}
|
||||
{whatsNew}
|
||||
<div className={styles.particles} aria-hidden="true"></div>
|
||||
<span className={styles.halo} aria-hidden="true"></span>
|
||||
</button>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
ExportToMarkdownIcon,
|
||||
ExportToPdfIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { useRef } from 'react';
|
||||
import { useCallback, useRef } from 'react';
|
||||
|
||||
import { Menu, MenuItem } from '../../..';
|
||||
import type { CommonMenuItemProps } from './types';
|
||||
@@ -18,35 +18,39 @@ const ExportToPdfMenuItem = ({
|
||||
}: CommonMenuItemProps<{ type: 'pdf' }>) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const contentParserRef = useRef<ContentParser>();
|
||||
return (
|
||||
<>
|
||||
{globalThis.currentEditor!.mode === 'page' && (
|
||||
<MenuItem
|
||||
data-testid="export-to-pdf"
|
||||
onClick={async () => {
|
||||
if (!contentParserRef.current) {
|
||||
contentParserRef.current = new ContentParser(
|
||||
globalThis.currentEditor!.page
|
||||
);
|
||||
}
|
||||
const result = await window.apis?.export.savePDFFileAs(
|
||||
(
|
||||
globalThis.currentEditor!.page.root as PageBlockModel
|
||||
).title.toString()
|
||||
);
|
||||
if (result !== undefined) {
|
||||
return;
|
||||
}
|
||||
contentParserRef.current.exportPdf();
|
||||
onSelect?.({ type: 'pdf' });
|
||||
}}
|
||||
icon={<ExportToPdfIcon />}
|
||||
>
|
||||
{t['Export to PDF']()}
|
||||
</MenuItem>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
const { currentEditor } = globalThis;
|
||||
const onClickDownloadPDF = useCallback(() => {
|
||||
if (!currentEditor) {
|
||||
return;
|
||||
}
|
||||
const contentParser =
|
||||
contentParserRef.current ??
|
||||
(contentParserRef.current = new ContentParser(currentEditor.page));
|
||||
|
||||
window.apis?.export
|
||||
.savePDFFileAs(
|
||||
(currentEditor.page.root as PageBlockModel).title.toString()
|
||||
)
|
||||
.then(result => {
|
||||
if (result !== undefined) {
|
||||
return;
|
||||
}
|
||||
contentParser.exportPdf();
|
||||
onSelect?.({ type: 'pdf' });
|
||||
});
|
||||
}, [currentEditor, onSelect]);
|
||||
if (currentEditor && currentEditor.mode === 'page') {
|
||||
return (
|
||||
<MenuItem
|
||||
data-testid="export-to-pdf"
|
||||
onClick={onClickDownloadPDF}
|
||||
icon={<ExportToPdfIcon />}
|
||||
>
|
||||
{t['Export to PDF']()}
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const ExportToHtmlMenuItem = ({
|
||||
@@ -54,19 +58,22 @@ const ExportToHtmlMenuItem = ({
|
||||
}: CommonMenuItemProps<{ type: 'html' }>) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const contentParserRef = useRef<ContentParser>();
|
||||
const { currentEditor } = globalThis;
|
||||
const onClickExportHtml = useCallback(() => {
|
||||
if (!currentEditor) {
|
||||
return;
|
||||
}
|
||||
if (!contentParserRef.current) {
|
||||
contentParserRef.current = new ContentParser(currentEditor.page);
|
||||
}
|
||||
contentParserRef.current.exportHtml();
|
||||
onSelect?.({ type: 'html' });
|
||||
}, [onSelect, currentEditor]);
|
||||
return (
|
||||
<>
|
||||
<MenuItem
|
||||
data-testid="export-to-html"
|
||||
onClick={() => {
|
||||
if (!contentParserRef.current) {
|
||||
contentParserRef.current = new ContentParser(
|
||||
globalThis.currentEditor!.page
|
||||
);
|
||||
}
|
||||
contentParserRef.current.exportHtml();
|
||||
onSelect?.({ type: 'html' });
|
||||
}}
|
||||
onClick={onClickExportHtml}
|
||||
icon={<ExportToHtmlIcon />}
|
||||
>
|
||||
{t['Export to HTML']()}
|
||||
@@ -108,19 +115,22 @@ const ExportToMarkdownMenuItem = ({
|
||||
}: CommonMenuItemProps<{ type: 'markdown' }>) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const contentParserRef = useRef<ContentParser>();
|
||||
const { currentEditor } = globalThis;
|
||||
const onClickExportMarkdown = useCallback(() => {
|
||||
if (!currentEditor) {
|
||||
return;
|
||||
}
|
||||
if (!contentParserRef.current) {
|
||||
contentParserRef.current = new ContentParser(currentEditor.page);
|
||||
}
|
||||
contentParserRef.current.exportMarkdown();
|
||||
onSelect?.({ type: 'markdown' });
|
||||
}, [onSelect, currentEditor]);
|
||||
return (
|
||||
<>
|
||||
<MenuItem
|
||||
data-testid="export-to-markdown"
|
||||
onClick={() => {
|
||||
if (!contentParserRef.current) {
|
||||
contentParserRef.current = new ContentParser(
|
||||
globalThis.currentEditor!.page
|
||||
);
|
||||
}
|
||||
contentParserRef.current.exportMarkdown();
|
||||
onSelect?.({ type: 'markdown' });
|
||||
}}
|
||||
onClick={onClickExportMarkdown}
|
||||
icon={<ExportToMarkdownIcon />}
|
||||
>
|
||||
{t['Export to Markdown']()}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useCallback, useState } from 'react';
|
||||
import useCollapsed from './hooks/use-collapsed';
|
||||
import useSelectWithKeyboard from './hooks/use-select-with-keyboard';
|
||||
import { TreeNode, TreeNodeWithDnd } from './tree-node';
|
||||
import type { TreeViewProps } from './types';
|
||||
import type { Node, TreeViewProps } from './types';
|
||||
import { findNode } from './utils';
|
||||
export const TreeView = <RenderProps,>({
|
||||
data,
|
||||
@@ -58,6 +58,39 @@ export const TreeView = <RenderProps,>({
|
||||
setDraggingId(e.active.id as string);
|
||||
}, []);
|
||||
if (enableDnd) {
|
||||
const treeNodes = data.map((node, index) => (
|
||||
<TreeNodeWithDnd
|
||||
key={node.id}
|
||||
index={index}
|
||||
collapsedIds={collapsedIds}
|
||||
setCollapsed={setCollapsed}
|
||||
node={node}
|
||||
selectedId={selectedId}
|
||||
enableDnd={enableDnd}
|
||||
disableCollapse={disableCollapse}
|
||||
draggingId={draggingId}
|
||||
{...otherProps}
|
||||
/>
|
||||
));
|
||||
const draggingNode = (function () {
|
||||
let draggingNode: Node<RenderProps> | undefined;
|
||||
if (draggingId) {
|
||||
draggingNode = findNode(draggingId, data);
|
||||
}
|
||||
if (draggingNode) {
|
||||
return (
|
||||
<TreeNode
|
||||
node={draggingNode}
|
||||
index={0}
|
||||
allowDrop={false}
|
||||
collapsedIds={collapsedIds}
|
||||
setCollapsed={() => {}}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})();
|
||||
return (
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
@@ -65,33 +98,8 @@ export const TreeView = <RenderProps,>({
|
||||
onDragMove={onDragMove}
|
||||
onDragEnd={onDragEnd}
|
||||
>
|
||||
{data.map((node, index) => (
|
||||
<TreeNodeWithDnd
|
||||
key={node.id}
|
||||
index={index}
|
||||
collapsedIds={collapsedIds}
|
||||
setCollapsed={setCollapsed}
|
||||
node={node}
|
||||
selectedId={selectedId}
|
||||
enableDnd={enableDnd}
|
||||
disableCollapse={disableCollapse}
|
||||
draggingId={draggingId}
|
||||
{...otherProps}
|
||||
/>
|
||||
))}
|
||||
|
||||
<DragOverlay>
|
||||
{draggingId && (
|
||||
<TreeNode
|
||||
node={findNode(draggingId, data)!}
|
||||
index={0}
|
||||
allowDrop={false}
|
||||
collapsedIds={collapsedIds}
|
||||
setCollapsed={() => {}}
|
||||
{...otherProps}
|
||||
/>
|
||||
)}
|
||||
</DragOverlay>
|
||||
{treeNodes}
|
||||
<DragOverlay>{draggingNode}</DragOverlay>
|
||||
</DndContext>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user