feat: support use template on web (#22)

This commit is contained in:
Kilu.He 2025-01-14 15:18:08 +08:00 committed by GitHub
parent fa43205569
commit b28f566f0a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 54 additions and 25 deletions

View File

@ -3056,5 +3056,10 @@
"AISearchPlaceholder": "Search or ask a question...", "AISearchPlaceholder": "Search or ask a question...",
"searchLabel": "Search", "searchLabel": "Search",
"publishSelectedViews": "Publish {{count}} selected views", "publishSelectedViews": "Publish {{count}} selected views",
"untitled": "Untitled" "untitled": "Untitled",
"addToWorkspace": "Added to your workspace",
"downloadTip": "Don't have AppFlowy Apps installed? Download <link/>.",
"here": "here",
"openInBrowser": "Open in browser",
"openInApp": "Open in app"
} }

View File

@ -972,11 +972,14 @@ export async function duplicatePublishView (workspaceId: string, payload: Duplic
const res = await axiosInstance?.post<{ const res = await axiosInstance?.post<{
code: number; code: number;
data: {
view_id: string;
};
message: string; message: string;
}>(url, payload); }>(url, payload);
if (res?.data.code === 0) { if (res?.data.code === 0) {
return; return res.data.data.view_id;
} }
return Promise.reject(res?.data.message); return Promise.reject(res?.data.message);

View File

@ -168,6 +168,6 @@ export interface PublishService {
getPublishViewReactions: (viewId: string, commentId?: string) => Promise<Record<string, Reaction[]>>; getPublishViewReactions: (viewId: string, commentId?: string) => Promise<Record<string, Reaction[]>>;
addPublishViewReaction: (viewId: string, commentId: string, reactionType: string) => Promise<void>; addPublishViewReaction: (viewId: string, commentId: string, reactionType: string) => Promise<void>;
removePublishViewReaction: (viewId: string, commentId: string, reactionType: string) => Promise<void>; removePublishViewReaction: (viewId: string, commentId: string, reactionType: string) => Promise<void>;
duplicatePublishView: (params: DuplicatePublishView) => Promise<void>; duplicatePublishView: (params: DuplicatePublishView) => Promise<string>;
} }

View File

@ -1,12 +1,12 @@
import { IconButton, Tooltip } from '@mui/material'; import { IconButton, Tooltip } from '@mui/material';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
// import { ReactComponent as TemplateIcon } from '@/assets/template.svg'; import { ReactComponent as TemplateIcon } from '@/assets/template.svg';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ReactComponent as TrashIcon } from '@/assets/trash.svg'; import { ReactComponent as TrashIcon } from '@/assets/trash.svg';
import { QuickNote } from '@/components/quick-note'; import { QuickNote } from '@/components/quick-note';
function SideBarBottom() { function SideBarBottom () {
const { t } = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
@ -18,16 +18,16 @@ function SideBarBottom() {
className={'flex py-4 border-t border-line-divider gap-1 justify-around items-center'} className={'flex py-4 border-t border-line-divider gap-1 justify-around items-center'}
> >
{/*<Tooltip title={t('template.label')}>*/} <Tooltip title={t('template.label')}>
{/* <IconButton*/} <IconButton
{/* size={'small'}*/} size={'small'}
{/* onClick={() => {*/} onClick={() => {
{/* window.open('https://appflowy.io/templates', '_blank');*/} window.open('https://appflowy.io/templates', '_blank');
{/* }}*/} }}
{/* >*/} >
{/* <TemplateIcon/>*/} <TemplateIcon />
{/* </IconButton>*/} </IconButton>
{/*</Tooltip>*/} </Tooltip>
<Tooltip title={t('trash.text')}> <Tooltip title={t('trash.text')}>
<IconButton <IconButton
@ -36,11 +36,11 @@ function SideBarBottom() {
navigate('/app/trash'); navigate('/app/trash');
}} }}
> >
<TrashIcon/> <TrashIcon />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<QuickNote/> <QuickNote />
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
import { AFConfigContext } from '@/components/main/app.hooks'; import { AFConfigContext } from '@/components/main/app.hooks';
import React, { useCallback, useContext, useEffect } from 'react'; import React, { useCallback, useContext, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { Trans, useTranslation } from 'react-i18next';
import { NormalModal } from '@/components/_shared/modal'; import { NormalModal } from '@/components/_shared/modal';
import SelectWorkspace from '@/components/publish/header/duplicate/SelectWorkspace'; import SelectWorkspace from '@/components/publish/header/duplicate/SelectWorkspace';
import { useLoadWorkspaces } from '@/components/publish/header/duplicate/useDuplicate'; import { useLoadWorkspaces } from '@/components/publish/header/duplicate/useDuplicate';
@ -31,6 +31,7 @@ function DuplicateModal ({ open, onClose }: { open: boolean; onClose: () => void
const layout = viewMeta?.layout as ViewLayout; const layout = viewMeta?.layout as ViewLayout;
const [loading, setLoading] = React.useState<boolean>(false); const [loading, setLoading] = React.useState<boolean>(false);
const [successModalOpen, setSuccessModalOpen] = React.useState<boolean>(false); const [successModalOpen, setSuccessModalOpen] = React.useState<boolean>(false);
const [newViewId, setNewViewId] = React.useState<string | undefined>(undefined);
const { const {
workspaceList, workspaceList,
spaceList, spaceList,
@ -64,15 +65,18 @@ function DuplicateModal ({ open, onClose }: { open: boolean; onClose: () => void
setLoading(true); setLoading(true);
try { try {
await service?.duplicatePublishView({ const newViewId = await service?.duplicatePublishView({
workspaceId: selectedWorkspaceId, workspaceId: selectedWorkspaceId,
spaceViewId: selectedSpaceId, spaceViewId: selectedSpaceId,
viewId, viewId,
collabType, collabType,
}); });
onClose(); onClose();
setSuccessModalOpen(true); setSuccessModalOpen(true);
setNewViewId(newViewId);
} catch (e) { } catch (e) {
setNewViewId(undefined);
notify.error(t('publish.duplicateFailed')); notify.error(t('publish.duplicateFailed'));
} finally { } finally {
setLoading(false); setLoading(false);
@ -115,18 +119,35 @@ function DuplicateModal ({ open, onClose }: { open: boolean; onClose: () => void
maxWidth: 420, maxWidth: 420,
}, },
}} }}
okText={t('publish.useThisTemplate')} okText={t('openInBrowser')}
cancelText={t('publish.downloadIt')} cancelText={t('openInApp')}
onOk={() => window.open(openAppFlowySchema, '_self')} onOk={() => {
if (!newViewId || !selectedWorkspaceId) return;
window.open(`/app/${selectedWorkspaceId}/${newViewId}`, '_self');
}}
onCancel={() => { onCancel={() => {
window.open(downloadPage, '_blank'); window.open(openAppFlowySchema, '_self');
}} }}
onClose={() => setSuccessModalOpen(false)} onClose={() => setSuccessModalOpen(false)}
open={successModalOpen} open={successModalOpen}
title={<div className={'text-left'}>{t('publish.duplicateSuccessfully')}</div>} title={
<div className={'text-left'}>
{t('addToWorkspace')}
</div>
}
> >
<div className={'w-full whitespace-pre-wrap break-words pb-1 text-text-caption'}> <div className={'w-full whitespace-pre-wrap break-words pb-1 text-text-caption'}>
{t('publish.duplicateSuccessfullyDescription')} <Trans
i18nKey="downloadTip"
components={{
link: <span
onClick={() => {
window.open(downloadPage, '_blank');
}}
className={'hover:underline cursor-pointer text-fill-default'}
>{t('here')}</span>,
}}
/>
</div> </div>
</NormalModal> </NormalModal>
</> </>