mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-26 23:30:47 +00:00
fix: add new row cover (#6826)
* fix: add new row cover * fix: add default callout icon
This commit is contained in:
parent
8a7cedd5b4
commit
cc7476c75b
@ -1,5 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
FieldId,
|
FieldId, RowCoverType,
|
||||||
SortId,
|
SortId,
|
||||||
YDatabase,
|
YDatabase,
|
||||||
YDatabaseField, YDatabaseMetas, YDatabaseRow,
|
YDatabaseField, YDatabaseMetas, YDatabaseRow,
|
||||||
@ -641,7 +641,10 @@ export function usePrimaryFieldId () {
|
|||||||
|
|
||||||
export interface RowMeta {
|
export interface RowMeta {
|
||||||
documentId: string;
|
documentId: string;
|
||||||
cover: string;
|
cover: {
|
||||||
|
data: string,
|
||||||
|
cover_type: RowCoverType,
|
||||||
|
} | null;
|
||||||
icon: string;
|
icon: string;
|
||||||
isEmptyDocument: boolean;
|
isEmptyDocument: boolean;
|
||||||
}
|
}
|
||||||
@ -691,10 +694,10 @@ export const useRowMetaSelector = (rowId: string) => {
|
|||||||
const metaJson = yMeta.toJSON();
|
const metaJson = yMeta.toJSON();
|
||||||
|
|
||||||
const icon = metaJson[iconKey];
|
const icon = metaJson[iconKey];
|
||||||
let cover = '';
|
let cover = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cover = metaJson[coverKey] ? JSON.parse(metaJson[coverKey])?.url : '';
|
cover = metaJson[coverKey] ? JSON.parse(metaJson[coverKey]) : null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|||||||
@ -830,6 +830,13 @@ export enum CoverType {
|
|||||||
None = 'none',
|
None = 'none',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum RowCoverType {
|
||||||
|
ColorCover = 0,
|
||||||
|
FileCover = 1,
|
||||||
|
AssetCover = 2,
|
||||||
|
GradientCover = 3,
|
||||||
|
}
|
||||||
|
|
||||||
export enum UIVariant {
|
export enum UIVariant {
|
||||||
Publish = 'publish',
|
Publish = 'publish',
|
||||||
App = 'app',
|
App = 'app',
|
||||||
|
|||||||
@ -1,14 +1,9 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<g clip-path="url(#clip0_41_21)">
|
<path d="M5.00006 0.799988V2.89999" stroke="currentColor" stroke-width="1.2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<path d="M13.8933 4.53334V3.49334C13.8933 2.72752 13.2725 2.10667 12.5067 2.10667H2.8C2.03417 2.10667 1.41333 2.72752 1.41333 3.49334V13.2C1.41333 13.9659 2.03411 14.5867 2.8 14.5867H5.22666"
|
<path d="M10.5999 0.799988V2.89999" stroke="currentColor" stroke-width="1.2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M1.8501 5.76297H13.7501" stroke="currentColor" stroke-width="1.2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<path d="M10.4266 0.720001V3.49333" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M14.1 5.34995V11.2999C14.1 13.3999 13.05 14.7999 10.6 14.7999H5C2.55 14.7999 1.5 13.3999 1.5 11.2999V5.34995C1.5 3.24995 2.55 1.84995 5 1.84995H10.6C13.05 1.84995 14.1 3.24995 14.1 5.34995Z" stroke="currentColor" stroke-width="1.2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<path d="M4.88 0.720001V3.49333" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M5.0946 8.91612H5.10359" stroke="currentColor" stroke-width="1.05" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<path d="M1.41333 6.26666H4.88" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M5.0946 11.0839H5.10359" stroke="currentColor" stroke-width="1.05" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<path d="M11.4666 11.4667L10.4266 10.6347V9.03999" stroke="currentColor" stroke-linecap="round"
|
<path d="M7.69659 8.89999H7.70558" stroke="currentColor" stroke-width="1.05" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
stroke-linejoin="round"/>
|
|
||||||
<path d="M6.26666 10.4267C6.26666 13.6291 9.73333 15.6305 12.5067 14.0293C13.7938 13.2862 14.5867 11.9129 14.5867 10.4267C14.5867 7.22426 11.12 5.22282 8.34666 6.82399C7.05954 7.56709 6.26666 8.94045 6.26666 10.4267Z"
|
|
||||||
stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
||||||
</g>
|
|
||||||
|
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
5
frontend/appflowy_web_app/src/assets/reminder_clock.svg
Normal file
5
frontend/appflowy_web_app/src/assets/reminder_clock.svg
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M13.8332 8.83333C13.8332 12.0533 11.2198 14.6667 7.99984 14.6667C4.77984 14.6667 2.1665 12.0533 2.1665 8.83333C2.1665 5.61333 4.77984 3 7.99984 3C11.2198 3 13.8332 5.61333 13.8332 8.83333Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M8 5.33325V8.66659" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M6 1.33325H10" stroke="currentColor" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 591 B |
@ -13,6 +13,7 @@ export function ImageRender({ src, ...props }: ImageRenderProps) {
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [hasError, setHasError] = useState(false);
|
const [hasError, setHasError] = useState(false);
|
||||||
|
|
||||||
|
console.log('ImageRender', src);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{hasError ? (
|
{hasError ? (
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import { DatabaseContext, useFieldsSelector, useRowMetaSelector } from '@/application/database-yjs';
|
import { DatabaseContext, RowMeta, useFieldsSelector, useRowMetaSelector } from '@/application/database-yjs';
|
||||||
import CardField from '@/components/database/components/field/CardField';
|
import CardField from '@/components/database/components/field/CardField';
|
||||||
import React, { memo, useContext, useEffect, useMemo } from 'react';
|
import React, { memo, useCallback, useContext, useEffect, useMemo } from 'react';
|
||||||
|
import { RowCoverType } from '@/application/types';
|
||||||
|
import { renderColor } from '@/utils/color';
|
||||||
|
import ImageRender from '@/components/_shared/image-render/ImageRender';
|
||||||
|
|
||||||
export interface CardProps {
|
export interface CardProps {
|
||||||
groupFieldId: string;
|
groupFieldId: string;
|
||||||
@ -45,6 +48,41 @@ export const Card = memo(({ groupFieldId, rowId, onResize, isDragging }: CardPro
|
|||||||
return classList.join(' ');
|
return classList.join(' ');
|
||||||
}, [navigateToRow]);
|
}, [navigateToRow]);
|
||||||
|
|
||||||
|
|
||||||
|
const renderCoverImage = useCallback((cover: RowMeta["cover"]) => {
|
||||||
|
if (!cover) return null;
|
||||||
|
|
||||||
|
if (cover.cover_type === RowCoverType.GradientCover || cover.cover_type === RowCoverType.ColorCover) {
|
||||||
|
return <div
|
||||||
|
style={{
|
||||||
|
background: renderColor(cover.data),
|
||||||
|
}}
|
||||||
|
className={`h-full w-full`}
|
||||||
|
/> ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let url: string | undefined = cover.data;
|
||||||
|
|
||||||
|
if (cover.cover_type === RowCoverType.AssetCover) {
|
||||||
|
url = {
|
||||||
|
1: '/covers/m_cover_image_1.png',
|
||||||
|
2: '/covers/m_cover_image_2.png',
|
||||||
|
3: '/covers/m_cover_image_3.png',
|
||||||
|
4: '/covers/m_cover_image_4.png',
|
||||||
|
5: '/covers/m_cover_image_5.png',
|
||||||
|
6: '/covers/m_cover_image_6.png',
|
||||||
|
}[Number(cover.data)]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!url) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ImageRender draggable={false} src={url} alt={''} className={'h-full w-full object-cover'} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -60,10 +98,7 @@ export const Card = memo(({ groupFieldId, rowId, onResize, isDragging }: CardPro
|
|||||||
<div
|
<div
|
||||||
className={'w-full h-[100px] bg-cover bg-center'}
|
className={'w-full h-[100px] bg-cover bg-center'}
|
||||||
>
|
>
|
||||||
<img
|
{renderCoverImage(cover)}
|
||||||
className={'w-full h-full object-cover'}
|
|
||||||
src={cover}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={'flex flex-col gap-2 py-2 px-3'}>
|
<div className={'flex flex-col gap-2 py-2 px-3'}>
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { useCellSelector, usePrimaryFieldId, useRowMetaSelector } from '@/application/database-yjs';
|
import { RowMeta, useCellSelector, usePrimaryFieldId, useRowMetaSelector } from '@/application/database-yjs';
|
||||||
import { AppendBreadcrumb, ViewIconType, ViewLayout } from '@/application/types';
|
import { AppendBreadcrumb, RowCoverType, ViewIconType, ViewLayout } from '@/application/types';
|
||||||
import Title from '@/components/database/components/header/Title';
|
import Title from '@/components/database/components/header/Title';
|
||||||
import { getScrollParent } from '@/components/global-comment/utils';
|
import { getScrollParent } from '@/components/global-comment/utils';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useCallback, useEffect } from 'react';
|
||||||
|
import { renderColor } from '@/utils/color';
|
||||||
|
import ImageRender from '@/components/_shared/image-render/ImageRender';
|
||||||
|
|
||||||
function DatabaseRowHeader ({ rowId, appendBreadcrumb }: { rowId: string; appendBreadcrumb?: AppendBreadcrumb }) {
|
function DatabaseRowHeader ({ rowId, appendBreadcrumb }: { rowId: string; appendBreadcrumb?: AppendBreadcrumb }) {
|
||||||
const fieldId = usePrimaryFieldId() || '';
|
const fieldId = usePrimaryFieldId() || '';
|
||||||
@ -13,6 +15,40 @@ function DatabaseRowHeader ({ rowId, appendBreadcrumb }: { rowId: string; append
|
|||||||
const meta = useRowMetaSelector(rowId);
|
const meta = useRowMetaSelector(rowId);
|
||||||
const cover = meta?.cover;
|
const cover = meta?.cover;
|
||||||
|
|
||||||
|
const renderCoverImage = useCallback((cover: RowMeta["cover"]) => {
|
||||||
|
if (!cover) return null;
|
||||||
|
|
||||||
|
if (cover.cover_type === RowCoverType.GradientCover || cover.cover_type === RowCoverType.ColorCover) {
|
||||||
|
return <div
|
||||||
|
style={{
|
||||||
|
background: renderColor(cover.data),
|
||||||
|
}}
|
||||||
|
className={`h-full w-full`}
|
||||||
|
/> ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let url: string | undefined = cover.data;
|
||||||
|
|
||||||
|
if (cover.cover_type === RowCoverType.AssetCover) {
|
||||||
|
url = {
|
||||||
|
1: '/covers/m_cover_image_1.png',
|
||||||
|
2: '/covers/m_cover_image_2.png',
|
||||||
|
3: '/covers/m_cover_image_3.png',
|
||||||
|
4: '/covers/m_cover_image_4.png',
|
||||||
|
5: '/covers/m_cover_image_5.png',
|
||||||
|
6: '/covers/m_cover_image_6.png',
|
||||||
|
}[Number(cover.data)]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!url) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ImageRender draggable={false} src={url} alt={''} className={'h-full w-full object-cover'} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const cell = useCellSelector({
|
const cell = useCellSelector({
|
||||||
rowId,
|
rowId,
|
||||||
fieldId,
|
fieldId,
|
||||||
@ -63,12 +99,16 @@ function DatabaseRowHeader ({ rowId, appendBreadcrumb }: { rowId: string; append
|
|||||||
|
|
||||||
return <div ref={ref} className={'flex flex-col relative'}>
|
return <div ref={ref} className={'flex flex-col relative'}>
|
||||||
<div className={'row-header-cover relative'} style={{ left: offsetLeft, width }}>
|
<div className={'row-header-cover relative'} style={{ left: offsetLeft, width }}>
|
||||||
{cover && <img
|
{cover && <div
|
||||||
className={'max-h-[288px] min-h-[130px] w-full max-sm:h-[180px] object-cover'} src={cover}
|
style={{
|
||||||
alt={cell?.data as string}
|
height: '40vh',
|
||||||
/>}
|
}}
|
||||||
|
className={'relative flex max-h-[288px] min-h-[130px] w-full max-sm:h-[180px]'}
|
||||||
|
>
|
||||||
|
{renderCoverImage(cover)}
|
||||||
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
<Title icon={meta?.icon} name={cell?.data as string} />
|
<Title icon={meta?.icon} name={cell?.data as string}/>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,8 @@ function CalloutIcon({ node }: { node: CalloutNode }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span contentEditable={false} ref={ref} className={`icon flex h-8 w-8 items-center p-1`}>
|
<span contentEditable={false} ref={ref} className={`icon flex h-10 w-8 items-center p-1`}>
|
||||||
{node.data.icon}
|
{node.data.icon || `📌`}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { renderDate } from '@/utils/time';
|
import { renderDate } from '@/utils/time';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { ReactComponent as DateSvg } from '@/assets/date.svg';
|
import { ReactComponent as DateSvg } from '@/assets/date.svg';
|
||||||
import { ReactComponent as ReminderSvg } from '@/assets/clock_alarm.svg';
|
import { ReactComponent as ReminderSvg } from '@/assets/reminder_clock.svg';
|
||||||
|
|
||||||
function MentionDate ({ date, reminder }: { date: string; reminder?: { id: string; option: string } }) {
|
function MentionDate ({ date, reminder }: { date: string; reminder?: { id: string; option: string } }) {
|
||||||
const dateFormat = useMemo(() => {
|
const dateFormat = useMemo(() => {
|
||||||
@ -9,10 +9,12 @@ function MentionDate ({ date, reminder }: { date: string; reminder?: { id: strin
|
|||||||
}, [date]);
|
}, [date]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={'mention-inline'}>
|
<span className={'mention-inline opacity-70'} style={{
|
||||||
{reminder ? <ReminderSvg className={'mention-icon'} /> : <DateSvg className={'mention-icon'} />}
|
color: reminder ? 'var(--fill-default)' : 'var(--text-title)',
|
||||||
|
}}>
|
||||||
|
<span className={'mention-content mr-[1.5em] ml-0'}><span>@</span>{dateFormat}</span>
|
||||||
|
{reminder ? <ReminderSvg className={'mention-icon right-1'} /> : <DateSvg className={'mention-icon right-1'} />}
|
||||||
|
|
||||||
<span className={'mention-content'}>{dateFormat}</span>
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user