Compare commits

..

8 Commits

Author SHA1 Message Date
EYHN
824be0d4c1 fix(core): fix viewtransition and css property missing (#7377) 2024-06-28 18:03:43 +08:00
golok727
fbf676002f fix: code block toolbar z-index issue in right sidebar (#7376)
Closes: [BS-549](https://linear.app/affine-design/issue/BS-549/code-block-%E5%9C%A8%E5%8F%B3%E4%BE%A7%E8%BE%B9%E6%A0%8F%E6%9C%89-z-index-%E9%97%AE%E9%A2%98%E8%AF%AD%E8%A8%80%E7%9A%84%E4%BF%A1%E6%81%AF%E5%87%BA%E7%8E%B0%E5%9C%A8%E4%BA%86-tab-%E4%B8%8A%E9%9D%A2),[BS-600](https://linear.app/affine-design/issue/BS-600/the-code-toolbar-remains-visible-when-it-overflows-in-the-ai-panel)
2024-06-28 07:48:50 +00:00
regischen
e877f20955 fix: add onboarding entry (#7375)
Don't know why it's missed..
https://github.com/toeverything/AFFiNE/pull/7109
2024-06-28 07:03:33 +00:00
regischen
f4f84d2793 fix: click continue with ai not work (#7374) 2024-06-28 14:43:45 +08:00
pengx17
34b6a3bf1f fix: escape key handling compatibility issue with blocksuite (#7365)
fix PD-1347

See
https://github.com/radix-ui/primitives/blob/main/packages/react/use-escape-keydown/src/useEscapeKeydown.tsx#L19-L20

This behavior in radix-ui is not possible to be prevented since escape keydown is bound to document with capturing, unless dialogs in blocksuite is also implemented with radix-ui.
2024-06-28 06:21:36 +00:00
EYHN
eca484dc28 fix(core): add loading for insert ai template (#7369) 2024-06-28 14:19:59 +08:00
Fangdun Tsai
855d555480 fix(core): should return a cleanup function (#7371) 2024-06-28 14:18:24 +08:00
forehalo
d51fd8b54b fix(core): correct image action icon (#7370)
fix AF-1002

![image.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/5c0ymolP9B7QStCsS1RP/b2e7afb1-e6bf-4589-8c60-32bede366350.png)
2024-06-28 05:24:06 +00:00
14 changed files with 143 additions and 46 deletions

View File

@@ -107,7 +107,6 @@ export function fromPromise<T>(
.catch(error => {
subscriber.error(error);
});
return () => abortController.abort('Aborted');
});
}

View File

@@ -432,7 +432,7 @@ export function buildAIImageItemGroups(): AIItemGroupConfig[] {
items: [
{
name: 'Explain this image',
icon: ExplainIcon,
icon: AIImageIcon,
showWhen: () => true,
handler: actionToHandler(
'explainImage',
@@ -457,14 +457,6 @@ export function buildAIImageItemGroups(): AIItemGroupConfig[] {
blockActionTrackerOptions
),
},
{
name: 'AI image filter',
icon: ImproveWritingIcon,
showWhen: () => true,
subItem: createImageFilterSubItem(blockActionTrackerOptions),
subItemOffset: [12, -4],
beta: true,
},
{
name: 'Image processing',
icon: AIImageIcon,
@@ -473,6 +465,14 @@ export function buildAIImageItemGroups(): AIItemGroupConfig[] {
subItemOffset: [12, -6],
beta: true,
},
{
name: 'AI image filter',
icon: ImproveWritingIcon,
showWhen: () => true,
subItem: createImageFilterSubItem(blockActionTrackerOptions),
subItemOffset: [12, -4],
beta: true,
},
{
name: 'Generate a caption',
icon: AIPenIcon,

View File

@@ -119,6 +119,9 @@ export class ChatCards extends WithDisposable(LitElement) {
@property({ attribute: false })
accessor temporaryParams: AIChatParams | null = null;
@property({ attribute: false })
accessor isEmpty!: boolean;
@state()
accessor cards: Card[] = [];
@@ -508,6 +511,8 @@ export class ChatCards extends WithDisposable(LitElement) {
}
protected override render() {
if (!this.isEmpty) return nothing;
return repeat(
this.cards,
card => card.id,

View File

@@ -265,23 +265,18 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
>
${items.length === 0
? html`<div class="chat-panel-messages-placeholder">
${AffineIcon(
isLoading
? 'var(--affine-icon-secondary)'
: 'var(--affine-primary-color)'
)}
<div>
${this.isLoading
? 'AFFiNE AI is loading history...'
: 'What can I help you with?'}
</div>
${this._renderAIOnboarding()}
${AffineIcon(
isLoading
? 'var(--affine-icon-secondary)'
: 'var(--affine-primary-color)'
)}
<div>
${this.isLoading
? 'AFFiNE AI is loading history...'
: 'What can I help you with?'}
</div>
<chat-cards
.updateContext=${this.updateContext}
.host=${this.host}
?data-show=${this.showChatCards}
></chat-cards>`
${this._renderAIOnboarding()}
</div> `
: repeat(filteredItems, (item, index) => {
const isLast = index === filteredItems.length - 1;
return html`<div class="message">
@@ -289,6 +284,12 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
<div class="item-wrapper">${this.renderItem(item, isLast)}</div>
</div>`;
})}
<chat-cards
.updateContext=${this.updateContext}
.host=${this.host}
.isEmpty=${items.length === 0}
?data-show=${this.showChatCards}
></chat-cards>
</div>
${this.showDownIndicator
? html`<div class="down-indicator" @click=${() => this.scrollToDown()}>

View File

@@ -33,12 +33,15 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) {
}
.chat-panel-title {
background: var(--affine-background-primary-color);
position: relative;
padding: 8px 0px;
width: 100%;
height: 36px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 1;
div:first-child {
font-size: 14px;

View File

@@ -20,9 +20,9 @@ export function setupCodeToolbarEntry(codeToolbar: AffineCodeToolbarWidget) {
const onAskAIClick = () => {
const { host } = codeToolbar;
const { selection } = host;
const imageBlock = codeToolbar.blockElement;
const codeBlock = codeToolbar.blockElement;
selection.setGroup('note', [
selection.create('block', { blockId: imageBlock.blockId }),
selection.create('block', { blockId: codeBlock.blockId }),
]);
};
codeToolbar.setupDefaultConfig();

View File

@@ -139,6 +139,9 @@ export class AIAnswerText extends WithDisposable(LitElement) {
editor-host * {
box-sizing: border-box;
}
editor-host {
isolation: isolate;
}
}
${textBlockStyles}

View File

@@ -1,6 +1,7 @@
import { notify } from '@affine/component';
import { authAtom, openSettingModalAtom } from '@affine/core/atoms';
import { AIProvider } from '@affine/core/blocksuite/presets/ai';
import { toggleGeneralAIOnboarding } from '@affine/core/components/affine/ai-onboarding/apis';
import { mixpanel } from '@affine/core/utils';
import { getBaseUrl } from '@affine/graphql';
import { Trans } from '@affine/i18n';
@@ -398,6 +399,8 @@ Could you make a new website based on these notes and send back just the html fi
},
});
AIProvider.provide('onboarding', toggleGeneralAIOnboarding);
AIProvider.slots.requestUpgradePlan.on(() => {
getCurrentStore().set(openSettingModalAtom, {
activeTab: 'billing',

View File

@@ -13,7 +13,11 @@ import {
borderAngle3,
} from './styles.css';
if (typeof window !== 'undefined' && window.CSS) {
if (
typeof window !== 'undefined' &&
window.CSS &&
window.CSS.registerProperty
) {
const getName = (nameWithVar: string) => nameWithVar.slice(4, -1);
const registerAngle = (varName: string, initialValue: number) => {
window.CSS.registerProperty({

View File

@@ -1,3 +1,9 @@
import { toast } from '@affine/component';
import {
pushGlobalLoadingEventAtom,
resolveGlobalLoadingEventAtom,
} from '@affine/component/global-loading';
import { useI18n } from '@affine/i18n';
import { ZipTransformer } from '@blocksuite/blocks';
import { assertExists } from '@blocksuite/global/utils';
import {
@@ -9,8 +15,13 @@ import {
useSensors,
} from '@dnd-kit/core';
import {
type DocMode,
DocsService,
effect,
fromPromise,
GlobalContextService,
onStart,
throwIfAborted,
useLiveData,
useService,
WorkspaceService,
@@ -19,6 +30,14 @@ import { useAtomValue, useSetAtom } from 'jotai';
import type { PropsWithChildren, ReactNode } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { createPortal } from 'react-dom';
import {
catchError,
EMPTY,
finalize,
mergeMap,
switchMap,
timeout,
} from 'rxjs';
import { Map as YMap } from 'yjs';
import { openSettingModalAtom } from '../atoms';
@@ -103,6 +122,9 @@ export const WorkspaceLayout = function WorkspaceLayout({
};
export const WorkspaceLayoutInner = ({ children }: PropsWithChildren) => {
const t = useI18n();
const pushGlobalLoadingEvent = useSetAtom(pushGlobalLoadingEventAtom);
const resolveGlobalLoadingEvent = useSetAtom(resolveGlobalLoadingEventAtom);
const currentWorkspace = useService(WorkspaceService).workspace;
const docsList = useService(DocsService).list;
const { openPage } = useNavigateHelper();
@@ -120,26 +142,60 @@ export const WorkspaceLayoutInner = ({ children }: PropsWithChildren) => {
);
useEffect(() => {
const disposable = AIProvider.slots.requestInsertTemplate.on(
({ template, mode }) => {
(async () => {
const templateZip = await fetch(template);
const insertTemplate = effect(
switchMap(({ template, mode }: { template: string; mode: string }) => {
return fromPromise(async abort => {
const templateZip = await fetch(template, { signal: abort });
const templateBlob = await templateZip.blob();
throwIfAborted(abort);
const [doc] = await ZipTransformer.importDocs(
currentWorkspace.docCollection,
templateBlob
);
doc.resetHistory();
docsList.setMode(doc.id, mode);
workbench.openPage(doc.id);
})().catch(err => {
console.error(err);
});
return { doc, mode };
}).pipe(
timeout(10000 /* 10s */),
mergeMap(({ mode, doc }) => {
docsList.setMode(doc.id, mode as DocMode);
workbench.openPage(doc.id);
return EMPTY;
}),
onStart(() => {
pushGlobalLoadingEvent({
key: 'insert-template',
});
}),
catchError(err => {
console.error(err);
toast(t['com.affine.ai.template-insert.failed']());
return EMPTY;
}),
finalize(() => {
resolveGlobalLoadingEvent('insert-template');
})
);
})
);
const disposable = AIProvider.slots.requestInsertTemplate.on(
({ template, mode }) => {
insertTemplate({ template, mode });
}
);
return () => disposable.dispose();
}, [currentWorkspace.docCollection, docsList, workbench]);
return () => {
disposable.dispose();
insertTemplate.unsubscribe();
};
}, [
currentWorkspace.docCollection,
docsList,
pushGlobalLoadingEvent,
resolveGlobalLoadingEvent,
t,
workbench,
]);
useRegisterWorkspaceCommands();
useRegisterNavigationCommands();

View File

@@ -22,6 +22,11 @@ const contentOptions: Dialog.DialogContentProps = {
e.preventDefault();
}
},
onEscapeKeyDown: e => {
// prevent closing the modal when pressing escape key by default
// this is because radix-ui register the escape key event on the document using capture, which is not possible to prevent in blocksuite
e.preventDefault();
},
style: {
padding: 0,
backgroundColor: 'transparent',
@@ -98,13 +103,29 @@ export const PeekViewModalContainer = forwardRef<
) {
const [vtOpen, setVtOpen] = useState(open);
useEffect(() => {
document.startViewTransition(() => {
flushSync(() => {
setVtOpen(open);
if (document.startViewTransition) {
document.startViewTransition(() => {
flushSync(() => {
setVtOpen(open);
});
});
});
} else {
setVtOpen(open);
}
}, [open]);
useEffect(() => {
const onKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
onOpenChange(false);
}
};
document.addEventListener('keydown', onKeyDown);
return () => {
document.removeEventListener('keydown', onKeyDown);
};
}, [onOpenChange]);
useEffect(() => {
const bondingBox = target ? getElementScreenPositionCenter(target) : null;
const offsetLeft =

View File

@@ -8,6 +8,7 @@ export const header = style({
alignItems: 'center',
flexShrink: 0,
padding: '0 16px',
zIndex: 1,
gap: '12px',
background: cssVar('backgroundPrimaryColor'),
selectors: {

View File

@@ -115,7 +115,7 @@ const DetailPageImpl = memo(function DetailPageImpl() {
setTabOnLoad(null);
}
});
return disposable.dispose();
return () => disposable.dispose();
}, [activeTabName, rightSidebar, setActiveTabName]);
useEffect(() => {

View File

@@ -1342,5 +1342,6 @@
"will be moved to Trash": "{{title}} will be moved to Trash",
"will delete member": "will delete member",
"com.affine.user-info.usage.ai": "AI Usage",
"com.affine.user-info.usage.cloud": "Cloud Storage"
"com.affine.user-info.usage.cloud": "Cloud Storage",
"com.affine.ai.template-insert.failed": "Failed to insert template, please try again."
}