mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
feat(core): web-clipper integration entrance (#11883)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a new "Web Clipper" integration, allowing users to import web pages into AFFiNE via a direct link to the Chrome Web Store. - **Improvements** - Integration cards can now display as clickable links or settings panels, depending on the integration. - **Localization** - Added English translations for the "Web Clipper" integration name and description. - **Style** - Improved card styling to ensure consistent text color, including for visited links. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -13,6 +13,12 @@ export const card = style({
|
||||
flexDirection: 'column',
|
||||
background: cssVarV2.layer.background.overlayPanel,
|
||||
cursor: 'pointer',
|
||||
color: 'unset',
|
||||
selectors: {
|
||||
'&:visited': {
|
||||
color: 'unset',
|
||||
},
|
||||
},
|
||||
});
|
||||
export const cardHeader = style({
|
||||
display: 'flex',
|
||||
|
||||
@@ -14,9 +14,22 @@ import {
|
||||
|
||||
export const IntegrationCard = ({
|
||||
className,
|
||||
link,
|
||||
...props
|
||||
}: HTMLAttributes<HTMLDivElement>) => {
|
||||
return <div className={clsx(className, card)} {...props} />;
|
||||
}: HTMLAttributes<HTMLElement> & {
|
||||
link?: string;
|
||||
}) => {
|
||||
return link ? (
|
||||
<a
|
||||
className={clsx(className, card)}
|
||||
{...props}
|
||||
href={link}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
/>
|
||||
) : (
|
||||
<div className={clsx(className, card)} {...props} />
|
||||
);
|
||||
};
|
||||
|
||||
export const IntegrationCardIcon = ({
|
||||
|
||||
@@ -1,20 +1,26 @@
|
||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import { IntegrationTypeIcon } from '@affine/core/modules/integration';
|
||||
import type { I18nString } from '@affine/i18n';
|
||||
import { TodayIcon } from '@blocksuite/icons/rc';
|
||||
import { Logo1Icon, TodayIcon } from '@blocksuite/icons/rc';
|
||||
import { LiveData } from '@toeverything/infra';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
import { CalendarSettingPanel } from './calendar/setting-panel';
|
||||
import { ReadwiseSettingPanel } from './readwise/setting-panel';
|
||||
|
||||
interface IntegrationCard {
|
||||
type IntegrationCard = {
|
||||
id: string;
|
||||
name: I18nString;
|
||||
desc: I18nString;
|
||||
icon: ReactNode;
|
||||
setting: ReactNode;
|
||||
}
|
||||
} & (
|
||||
| {
|
||||
setting: ReactNode;
|
||||
}
|
||||
| {
|
||||
link: string;
|
||||
}
|
||||
);
|
||||
|
||||
const INTEGRATION_LIST = [
|
||||
{
|
||||
@@ -31,6 +37,13 @@ const INTEGRATION_LIST = [
|
||||
icon: <TodayIcon />,
|
||||
setting: <CalendarSettingPanel />,
|
||||
},
|
||||
{
|
||||
id: 'web-clipper' as const,
|
||||
name: 'com.affine.integration.web-clipper.name',
|
||||
desc: 'com.affine.integration.web-clipper.desc',
|
||||
icon: <Logo1Icon />,
|
||||
link: 'https://chromewebstore.google.com/detail/affine-web-clipper/mpbbkmbdpleomiogkbkkpfoljjpahmoi',
|
||||
},
|
||||
] satisfies (IntegrationCard | false)[];
|
||||
|
||||
type IntegrationId = Exclude<
|
||||
|
||||
@@ -2,7 +2,7 @@ import { SettingHeader } from '@affine/component/setting-components';
|
||||
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { type ReactNode, useMemo, useState } from 'react';
|
||||
import { type ReactNode, useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { SubPageProvider, useSubPageIsland } from '../../sub-page';
|
||||
import {
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
IntegrationCardHeader,
|
||||
} from './card';
|
||||
import { getAllowedIntegrationList$ } from './constants';
|
||||
import { type IntegrationItem } from './constants';
|
||||
import { list } from './index.css';
|
||||
|
||||
export const IntegrationSetting = () => {
|
||||
@@ -25,6 +26,12 @@ export const IntegrationSetting = () => {
|
||||
)
|
||||
);
|
||||
|
||||
const handleCardClick = useCallback((card: IntegrationItem) => {
|
||||
if ('setting' in card && card.setting) {
|
||||
setOpened(card.id);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingHeader
|
||||
@@ -49,16 +56,22 @@ export const IntegrationSetting = () => {
|
||||
: t[item.desc.i18nKey]();
|
||||
return (
|
||||
<li key={item.id}>
|
||||
<IntegrationCard onClick={() => setOpened(item.id)}>
|
||||
<IntegrationCard
|
||||
onClick={() => handleCardClick(item)}
|
||||
link={'link' in item ? item.link : undefined}
|
||||
>
|
||||
<IntegrationCardHeader icon={item.icon} title={title} />
|
||||
<IntegrationCardContent desc={desc} />
|
||||
</IntegrationCard>
|
||||
<IntegrationSettingPage
|
||||
open={opened === item.id}
|
||||
onClose={() => setOpened(null)}
|
||||
>
|
||||
{item.setting}
|
||||
</IntegrationSettingPage>
|
||||
|
||||
{'setting' in item && item.setting ? (
|
||||
<IntegrationSettingPage
|
||||
open={opened === item.id}
|
||||
onClose={() => setOpened(null)}
|
||||
>
|
||||
{item.setting}
|
||||
</IntegrationSettingPage>
|
||||
) : null}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -7415,6 +7415,14 @@ export function useAFFiNEI18N(): {
|
||||
* `Integrations`
|
||||
*/
|
||||
["com.affine.integration.integrations"](): string;
|
||||
/**
|
||||
* `Web Clipper`
|
||||
*/
|
||||
["com.affine.integration.web-clipper.name"](): string;
|
||||
/**
|
||||
* `Import web pages to AFFiNE`
|
||||
*/
|
||||
["com.affine.integration.web-clipper.desc"](): string;
|
||||
/**
|
||||
* `Elevate your AFFiNE experience with diverse add-ons and seamless integrations.`
|
||||
*/
|
||||
|
||||
@@ -1854,6 +1854,8 @@
|
||||
"com.affine.failed-to-send-request.description": "Unable to process your request to join <1/> <2>{{workspaceName}}</2> with <3>{{userEmail}}</3>, the workspace has reached its member limit. Please contact the workspace owner for available seats.",
|
||||
"com.affine.integration.name.readwise": "Readwise",
|
||||
"com.affine.integration.integrations": "Integrations",
|
||||
"com.affine.integration.web-clipper.name": "Web Clipper",
|
||||
"com.affine.integration.web-clipper.desc": "Import web pages to AFFiNE",
|
||||
"com.affine.integration.setting.description": "Elevate your AFFiNE experience with diverse add-ons and seamless integrations.",
|
||||
"com.affine.integration.setting.learn": "Learn how to develop a integration for AFFiNE",
|
||||
"com.affine.integration.readwise.name": "Readwise",
|
||||
|
||||
Reference in New Issue
Block a user