mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-09-26 08:53:40 +00:00
fix: display duplicate entry (#5853)
* fix: some issue * fix: add colors * fix: do not allow people who are not appflowy
This commit is contained in:
parent
dda798752f
commit
4b0368d552
@ -59,17 +59,6 @@ function AsTemplate ({
|
|||||||
await loadTemplate();
|
await loadTemplate();
|
||||||
}
|
}
|
||||||
|
|
||||||
notify.info({
|
|
||||||
type: 'success',
|
|
||||||
title: t('template.uploadSuccess'),
|
|
||||||
message: t('template.uploadSuccessDescription'),
|
|
||||||
okText: t('template.viewTemplate'),
|
|
||||||
onOk: () => {
|
|
||||||
const url = import.meta.env.AF_BASE_URL?.includes('test') ? 'https://test.appflowy.io' : 'https://appflowy.io';
|
|
||||||
|
|
||||||
window.open(`${url}/templates/${selectedCategoryIds[0]}/${viewId}`, '_blank');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
handleBack();
|
handleBack();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
@ -77,8 +66,7 @@ function AsTemplate ({
|
|||||||
notify.error(error.toString());
|
notify.error(error.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [service, selectedCreatorId, selectedCategoryIds, viewId, isNewTemplate, isFeatured, viewUrl, template, t, handleBack, loadTemplate]);
|
}, [service, selectedCreatorId, selectedCategoryIds, isNewTemplate, isFeatured, viewId, viewUrl, template, loadTemplate, handleBack]);
|
||||||
|
|
||||||
const submitRef = React.useRef<HTMLInputElement>(null);
|
const submitRef = React.useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -8,6 +8,57 @@ import { ReactComponent as CloudUploadIcon } from '@/assets/cloud_add.svg';
|
|||||||
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const colorArray = [
|
||||||
|
'#5287D8',
|
||||||
|
'#6E9DE3',
|
||||||
|
'#8BB3ED',
|
||||||
|
'#A7C9F7',
|
||||||
|
'#979EB6',
|
||||||
|
'#A2A8BF',
|
||||||
|
'#ACB2C8',
|
||||||
|
'#C1C7DA',
|
||||||
|
'#E8AF53',
|
||||||
|
'#E6C25A',
|
||||||
|
'#E6D26F',
|
||||||
|
'#E6E288',
|
||||||
|
'#589599',
|
||||||
|
'#68AD8E',
|
||||||
|
'#79C47F',
|
||||||
|
'#8CDB6A',
|
||||||
|
'#AA94DC',
|
||||||
|
'#C49EEB',
|
||||||
|
'#BAACEE',
|
||||||
|
'#D5C4FB',
|
||||||
|
'#F597D2',
|
||||||
|
'#FCB2E3',
|
||||||
|
'#FDC5E8',
|
||||||
|
'#F8D2E1',
|
||||||
|
'#D1D269',
|
||||||
|
'#C7C98D',
|
||||||
|
'#CED09B',
|
||||||
|
'#DAD9B6',
|
||||||
|
'#DDD2C6',
|
||||||
|
'#DDD6C7',
|
||||||
|
'#EADED3',
|
||||||
|
'#FED5C4',
|
||||||
|
'#72A7D8',
|
||||||
|
'#8FCAE3',
|
||||||
|
'#64B3DA',
|
||||||
|
'#52B2D4',
|
||||||
|
'#90A4FF',
|
||||||
|
'#A8BEF4',
|
||||||
|
'#AEBDFF',
|
||||||
|
'#C2CDFF',
|
||||||
|
'#86C1B7',
|
||||||
|
'#A6D8D0',
|
||||||
|
'#A7D7A8',
|
||||||
|
'#C8E4C9',
|
||||||
|
'#FF9494',
|
||||||
|
'#FFBDBD',
|
||||||
|
'#DCA8A8',
|
||||||
|
'#E3C4C4',
|
||||||
|
];
|
||||||
|
|
||||||
function CreatorAvatar({ src, name, enableUpload, onChange, size }: {
|
function CreatorAvatar({ src, name, enableUpload, onChange, size }: {
|
||||||
src: string;
|
src: string;
|
||||||
name: string;
|
name: string;
|
||||||
@ -20,7 +71,7 @@ function CreatorAvatar ({ src, name, enableUpload, onChange, size }: {
|
|||||||
|
|
||||||
const [tab, setTab] = React.useState(0);
|
const [tab, setTab] = React.useState(0);
|
||||||
const avatarProps = useMemo(() => {
|
const avatarProps = useMemo(() => {
|
||||||
return stringAvatar(name || '');
|
return stringAvatar(name || '', colorArray);
|
||||||
}, [name]);
|
}, [name]);
|
||||||
const [openModal, setOpenModal] = React.useState(false);
|
const [openModal, setOpenModal] = React.useState(false);
|
||||||
|
|
||||||
@ -46,7 +97,10 @@ function CreatorAvatar ({ src, name, enableUpload, onChange, size }: {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Avatar src={src} className={'w-full h-full object-cover p-2'} {...avatarProps} sx={{
|
<Avatar
|
||||||
|
src={src}
|
||||||
|
className={'w-full h-full object-cover p-2'} {...avatarProps}
|
||||||
|
sx={{
|
||||||
...avatarProps?.sx,
|
...avatarProps?.sx,
|
||||||
bgcolor: imageUrl ? 'var(--bg-body)' : avatarProps?.sx.bgcolor,
|
bgcolor: imageUrl ? 'var(--bg-body)' : avatarProps?.sx.bgcolor,
|
||||||
width: size || undefined,
|
width: size || undefined,
|
||||||
@ -54,7 +108,10 @@ function CreatorAvatar ({ src, name, enableUpload, onChange, size }: {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{enableUpload && showUpload && (
|
{enableUpload && showUpload && (
|
||||||
<Tooltip title={t('template.creator.uploadAvatar')} arrow>
|
<Tooltip
|
||||||
|
title={t('template.creator.uploadAvatar')}
|
||||||
|
arrow
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
component="label"
|
component="label"
|
||||||
role={undefined}
|
role={undefined}
|
||||||
@ -82,21 +139,35 @@ function CreatorAvatar ({ src, name, enableUpload, onChange, size }: {
|
|||||||
if(!imageUrl) return;
|
if(!imageUrl) return;
|
||||||
onChange?.(imageUrl);
|
onChange?.(imageUrl);
|
||||||
setOpenModal(false);
|
setOpenModal(false);
|
||||||
}} title={t('template.uploadAvatar')}
|
}}
|
||||||
|
title={t('template.uploadAvatar')}
|
||||||
onCancel={() => setOpenModal(false)}
|
onCancel={() => setOpenModal(false)}
|
||||||
onClose={() => setOpenModal(false)} open={openModal}
|
onClose={() => setOpenModal(false)}
|
||||||
|
open={openModal}
|
||||||
>
|
>
|
||||||
<div className={'min-w-[400px] flex flex-col gap-4'}>
|
<div className={'min-w-[400px] flex flex-col gap-4'}>
|
||||||
<ViewTabs value={tab} onChange={(_, newValue) => {
|
<ViewTabs
|
||||||
|
value={tab}
|
||||||
|
onChange={(_, newValue) => {
|
||||||
setTab(newValue);
|
setTab(newValue);
|
||||||
setImageUrl(src);
|
setImageUrl(src);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ViewTab value={0} label={t('document.imageBlock.embedLink.label')} />
|
<ViewTab
|
||||||
<ViewTab value={1} label={t('button.upload')} />
|
value={0}
|
||||||
|
label={t('document.imageBlock.embedLink.label')}
|
||||||
|
/>
|
||||||
|
<ViewTab
|
||||||
|
value={1}
|
||||||
|
label={t('button.upload')}
|
||||||
|
/>
|
||||||
|
|
||||||
</ViewTabs>
|
</ViewTabs>
|
||||||
<TabPanel className={'w-full'} value={tab} index={0}>
|
<TabPanel
|
||||||
|
className={'w-full'}
|
||||||
|
value={tab}
|
||||||
|
index={0}
|
||||||
|
>
|
||||||
<OutlinedInput
|
<OutlinedInput
|
||||||
size={'small'}
|
size={'small'}
|
||||||
value={imageUrl}
|
value={imageUrl}
|
||||||
@ -109,7 +180,11 @@ function CreatorAvatar ({ src, name, enableUpload, onChange, size }: {
|
|||||||
placeholder={t('document.imageBlock.embedLink.placeholder')}
|
placeholder={t('document.imageBlock.embedLink.placeholder')}
|
||||||
/>
|
/>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel className={'w-full flex flex-col gap-2'} value={tab} index={1}>
|
<TabPanel
|
||||||
|
className={'w-full flex flex-col gap-2'}
|
||||||
|
value={tab}
|
||||||
|
index={1}
|
||||||
|
>
|
||||||
<UploadAvatar onChange={setImageUrl} />
|
<UploadAvatar onChange={setImageUrl} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
|
@ -2,8 +2,6 @@ import { TemplateSummary, TemplateCategory } from '@/application/template.type';
|
|||||||
import CreatorAvatar from '@/components/as-template/creator/CreatorAvatar';
|
import CreatorAvatar from '@/components/as-template/creator/CreatorAvatar';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
|
|
||||||
const url = import.meta.env.AF_BASE_URL?.includes('test') ? 'https://test.appflowy.io' : 'https://appflowy.io';
|
|
||||||
|
|
||||||
function TemplateItem({ template, category }: { template: TemplateSummary; category: TemplateCategory }) {
|
function TemplateItem({ template, category }: { template: TemplateSummary; category: TemplateCategory }) {
|
||||||
const iframeUrl = useMemo(() => {
|
const iframeUrl = useMemo(() => {
|
||||||
const url = new URL(template.view_url);
|
const url = new URL(template.view_url);
|
||||||
@ -17,20 +15,26 @@ function TemplateItem ({ template, category }: { template: TemplateSummary; cate
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<a
|
<div
|
||||||
href={`${url}/templates/${category.id}/${template.view_id}`}
|
|
||||||
className={'relative rounded-[16px] pt-4 px-4 h-[230px] w-full overflow-hidden'}
|
className={'relative rounded-[16px] pt-4 px-4 h-[230px] w-full overflow-hidden'}
|
||||||
target={'_blank'}
|
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: category?.bg_color,
|
backgroundColor: category?.bg_color,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<iframe loading={'lazy'} className={'w-full h-full'} src={iframeUrl} />
|
<iframe
|
||||||
</a>
|
loading={'lazy'}
|
||||||
|
className={'w-full h-full'}
|
||||||
|
src={iframeUrl}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className={'template-info'}>
|
<div className={'template-info'}>
|
||||||
<div className={'template-creator'}>
|
<div className={'template-creator'}>
|
||||||
<div className={'avatar'}>
|
<div className={'avatar'}>
|
||||||
<CreatorAvatar size={40} src={template.creator.avatar_url} name={template.creator.name} />
|
<CreatorAvatar
|
||||||
|
size={40}
|
||||||
|
src={template.creator.avatar_url}
|
||||||
|
name={template.creator.name}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={'right-info'}>
|
<div className={'right-info'}>
|
||||||
<div className={'template-name'}>{template.name}</div>
|
<div className={'template-name'}>{template.name}</div>
|
||||||
|
@ -15,7 +15,7 @@ export function Event({ event }: EventWrapperProps<CalendarEvent>) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'px-1 py-0.5'}>
|
<div className={'px-1 py-0.5'}>
|
||||||
<RichTooltip content={<EventPaper rowId={rowId} />} open={open} placement='right' onClose={() => setOpen(false)}>
|
<RichTooltip content={<EventPaper rowId={rowId} />} open={open} placement="right" onClose={() => setOpen(false)}>
|
||||||
<div
|
<div
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (window.innerWidth < 768) {
|
if (window.innerWidth < 768) {
|
||||||
@ -25,7 +25,7 @@ export function Event({ event }: EventWrapperProps<CalendarEvent>) {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
'flex min-h-[24px] cursor-pointer flex-col gap-2 rounded-md border border-line-border bg-bg-body p-2 text-xs text-xs shadow-sm hover:bg-fill-list-active hover:shadow'
|
'flex min-h-[24px] cursor-pointer flex-col gap-2 rounded-md border border-line-divider bg-bg-body p-2 text-xs shadow-sm hover:bg-fill-list-active hover:shadow'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{showFields.map((field) => {
|
{showFields.map((field) => {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { usePublishContext } from '@/application/publish';
|
import { usePublishContext } from '@/application/publish';
|
||||||
|
import { useCurrentUser } from '@/components/app/app.hooks';
|
||||||
import { openOrDownload } from '@/components/publish/header/utils';
|
import { openOrDownload } from '@/components/publish/header/utils';
|
||||||
import { createHotkey, HOT_KEY_NAME } from '@/utils/hotkeys';
|
import { createHotkey, HOT_KEY_NAME } from '@/utils/hotkeys';
|
||||||
import { Divider, IconButton, Tooltip } from '@mui/material';
|
import { Divider, IconButton, Tooltip } from '@mui/material';
|
||||||
@ -10,7 +11,7 @@ import Breadcrumb from './Breadcrumb';
|
|||||||
import { ReactComponent as Logo } from '@/assets/logo.svg';
|
import { ReactComponent as Logo } from '@/assets/logo.svg';
|
||||||
import MoreActions from './MoreActions';
|
import MoreActions from './MoreActions';
|
||||||
import { ReactComponent as SideOutlined } from '@/assets/side_outlined.svg';
|
import { ReactComponent as SideOutlined } from '@/assets/side_outlined.svg';
|
||||||
// import { Duplicate } from './duplicate';
|
import { Duplicate } from './duplicate';
|
||||||
|
|
||||||
export const HEADER_HEIGHT = 48;
|
export const HEADER_HEIGHT = 48;
|
||||||
|
|
||||||
@ -75,6 +76,10 @@ export function PublishViewHeader ({ onOpenDrawer, openDrawer }: { onOpenDrawer:
|
|||||||
setOpenPopover(true);
|
setOpenPopover(true);
|
||||||
}, [openDrawer, debounceClosePopover]);
|
}, [openDrawer, debounceClosePopover]);
|
||||||
|
|
||||||
|
const currentUser = useCurrentUser();
|
||||||
|
|
||||||
|
const isAppFlowyUser = currentUser?.email?.endsWith('@appflowy.io');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@ -113,8 +118,12 @@ export function PublishViewHeader ({ onOpenDrawer, openDrawer }: { onOpenDrawer:
|
|||||||
<div className={'flex items-center gap-2'}>
|
<div className={'flex items-center gap-2'}>
|
||||||
|
|
||||||
<MoreActions />
|
<MoreActions />
|
||||||
{/*<Duplicate />*/}
|
{isAppFlowyUser && <Duplicate />}
|
||||||
<Divider orientation={'vertical'} className={'mx-2'} flexItem />
|
<Divider
|
||||||
|
orientation={'vertical'}
|
||||||
|
className={'mx-2'}
|
||||||
|
flexItem
|
||||||
|
/>
|
||||||
<Tooltip title={t('publish.downloadApp')}>
|
<Tooltip title={t('publish.downloadApp')}>
|
||||||
<button onClick={openOrDownload}>
|
<button onClick={openOrDownload}>
|
||||||
<Logo className={'h-6 w-6'} />
|
<Logo className={'h-6 w-6'} />
|
||||||
|
@ -19,11 +19,23 @@ export function Duplicate () {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button onClick={handleClick} size={'small'} variant={'outlined'} color={'inherit'}>
|
<Button
|
||||||
|
onClick={handleClick}
|
||||||
|
size={'small'}
|
||||||
|
variant={'outlined'}
|
||||||
|
color={'inherit'}
|
||||||
|
>
|
||||||
{t('publish.saveThisPage')}
|
{t('publish.saveThisPage')}
|
||||||
</Button>
|
</Button>
|
||||||
<LoginModal redirectTo={url} open={loginOpen} onClose={handleLoginClose} />
|
<LoginModal
|
||||||
{duplicateOpen && <DuplicateModal open={duplicateOpen} onClose={handleDuplicateClose} />}
|
redirectTo={url}
|
||||||
|
open={loginOpen}
|
||||||
|
onClose={handleLoginClose}
|
||||||
|
/>
|
||||||
|
{duplicateOpen && <DuplicateModal
|
||||||
|
open={duplicateOpen}
|
||||||
|
onClose={handleDuplicateClose}
|
||||||
|
/>}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ export function renderColor (color: string) {
|
|||||||
return argbToRgba(color);
|
return argbToRgba(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stringToColor (string: string) {
|
export function stringToColor(string: string, colorArray?: string[]) {
|
||||||
let hash = 0;
|
let hash = 0;
|
||||||
let i;
|
let i;
|
||||||
|
|
||||||
@ -82,6 +82,10 @@ export function stringToColor (string: string) {
|
|||||||
hash = string.charCodeAt(i) + ((hash << 5) - hash);
|
hash = string.charCodeAt(i) + ((hash << 5) - hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(colorArray) {
|
||||||
|
return colorArray[string.slice(0, 1).charCodeAt(0) % colorArray.length];
|
||||||
|
}
|
||||||
|
|
||||||
let color = '#';
|
let color = '#';
|
||||||
|
|
||||||
for(i = 0; i < 3; i += 1) {
|
for(i = 0; i < 3; i += 1) {
|
||||||
@ -94,14 +98,14 @@ export function stringToColor (string: string) {
|
|||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stringAvatar (name: string) {
|
export function stringAvatar(name: string, colorArray?: string[]) {
|
||||||
if(!name) {
|
if(!name) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sx: {
|
sx: {
|
||||||
bgcolor: stringToColor(name),
|
bgcolor: stringToColor(name, colorArray),
|
||||||
},
|
},
|
||||||
children: `${name.split('')[0]}`,
|
children: `${name.split('')[0]}`,
|
||||||
};
|
};
|
||||||
|
@ -2358,7 +2358,7 @@
|
|||||||
"mustSelectPrimaryDatabase": "The primary view must be selected",
|
"mustSelectPrimaryDatabase": "The primary view must be selected",
|
||||||
"noDatabaseSelected": "No database selected, please select at least one database.",
|
"noDatabaseSelected": "No database selected, please select at least one database.",
|
||||||
"unableToDeselectPrimaryDatabase": "Unable to deselect primary database",
|
"unableToDeselectPrimaryDatabase": "Unable to deselect primary database",
|
||||||
"saveThisPage": "Save this page",
|
"saveThisPage": "Start with this template",
|
||||||
"duplicateTitle": "Where would you like to add",
|
"duplicateTitle": "Where would you like to add",
|
||||||
"selectWorkspace": "Select a workspace",
|
"selectWorkspace": "Select a workspace",
|
||||||
"addTo": "Add to",
|
"addTo": "Add to",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user