chore: fix web repo issues (#82)

* chore: fix the row height incorrect on firefox

* chore: add back button to row modal

* chore: remove sticky header on open view
This commit is contained in:
Kilu.He
2025-09-23 16:23:31 +08:00
committed by GitHub
parent df556eaf71
commit 2babdf1deb
11 changed files with 130 additions and 72 deletions

View File

@@ -70,6 +70,7 @@ export interface DatabaseContextState {
// Calendar view type map: viewId -> CalendarViewType
calendarViewTypeMap?: Map<string, CalendarViewType>;
setCalendarViewType?: (viewId: string, viewType: CalendarViewType) => void;
openPageModalViewId?: string;
}
export const DatabaseContext = createContext<DatabaseContextState | null>(null);

View File

@@ -1,8 +1,13 @@
import { ThemeModeContext } from '@/components/main/useAppThemeMode';
import { renderColor } from '@/utils/color';
import { getIcon } from '@/utils/emoji';
import DOMPurify from 'dompurify';
import { useContext, useEffect, useMemo, useState } from 'react';
import { ReactComponent as SpaceIcon1 } from '@/assets/space_icon/space_icon_1.svg';
import { ReactComponent as SpaceIcon10 } from '@/assets/space_icon/space_icon_10.svg';
import { ReactComponent as SpaceIcon11 } from '@/assets/space_icon/space_icon_11.svg';
import { ReactComponent as SpaceIcon12 } from '@/assets/space_icon/space_icon_12.svg';
import { ReactComponent as SpaceIcon13 } from '@/assets/space_icon/space_icon_13.svg';
import { ReactComponent as SpaceIcon14 } from '@/assets/space_icon/space_icon_14.svg';
import { ReactComponent as SpaceIcon15 } from '@/assets/space_icon/space_icon_15.svg';
import { ReactComponent as SpaceIcon2 } from '@/assets/space_icon/space_icon_2.svg';
import { ReactComponent as SpaceIcon3 } from '@/assets/space_icon/space_icon_3.svg';
import { ReactComponent as SpaceIcon4 } from '@/assets/space_icon/space_icon_4.svg';
@@ -11,13 +16,9 @@ import { ReactComponent as SpaceIcon6 } from '@/assets/space_icon/space_icon_6.s
import { ReactComponent as SpaceIcon7 } from '@/assets/space_icon/space_icon_7.svg';
import { ReactComponent as SpaceIcon8 } from '@/assets/space_icon/space_icon_8.svg';
import { ReactComponent as SpaceIcon9 } from '@/assets/space_icon/space_icon_9.svg';
import { ReactComponent as SpaceIcon10 } from '@/assets/space_icon/space_icon_10.svg';
import { ReactComponent as SpaceIcon11 } from '@/assets/space_icon/space_icon_11.svg';
import { ReactComponent as SpaceIcon12 } from '@/assets/space_icon/space_icon_12.svg';
import { ReactComponent as SpaceIcon13 } from '@/assets/space_icon/space_icon_13.svg';
import { ReactComponent as SpaceIcon14 } from '@/assets/space_icon/space_icon_14.svg';
import { ReactComponent as SpaceIcon15 } from '@/assets/space_icon/space_icon_15.svg';
import DOMPurify from 'dompurify';
import { ThemeModeContext } from '@/components/main/useAppThemeMode';
import { renderColor } from '@/utils/color';
import { getIcon } from '@/utils/emoji';
export const getIconComponent = (icon: string) => {
switch (icon) {
@@ -58,11 +59,16 @@ export const getIconComponent = (icon: string) => {
}
};
function SpaceIcon({ value, char, bgColor, className: classNameProp }: {
value: string,
char?: string,
bgColor?: string,
className?: string
function SpaceIcon({
value,
char,
bgColor,
className: classNameProp,
}: {
value: string;
char?: string;
bgColor?: string;
className?: string;
}) {
const IconComponent = getIconComponent(value);
const isDark = useContext(ThemeModeContext)?.isDark || false;
@@ -70,7 +76,7 @@ function SpaceIcon({ value, char, bgColor, className: classNameProp }: {
useEffect(() => {
if (value) {
void getIcon(value).then(icon => {
void getIcon(value).then((icon) => {
setCustomIconContent(icon?.content || '');
});
}
@@ -78,22 +84,31 @@ function SpaceIcon({ value, char, bgColor, className: classNameProp }: {
const customIcon = useMemo(() => {
if (customIconContent) {
const cleanSvg = DOMPurify.sanitize(customIconContent.replaceAll('black', isDark ? 'black' : 'white').replace('<svg', '<svg width="100%" height="100%"'), {
USE_PROFILES: { svg: true, svgFilters: true },
});
const cleanSvg = DOMPurify.sanitize(
customIconContent
.replaceAll('black', isDark ? 'black' : 'white')
.replace('<svg', '<svg width="100%" height="100%"'),
{
USE_PROFILES: { svg: true, svgFilters: true },
}
);
return <span className={'flex p-[0.2em] items-center justify-center'}><span dangerouslySetInnerHTML={{
__html: cleanSvg,
}}/></span>;
return (
<span className={'flex items-center justify-center p-[0.2em]'}>
<span
dangerouslySetInnerHTML={{
__html: cleanSvg,
}}
/>
</span>
);
}
}, [customIconContent, isDark]);
const content = useMemo(() => {
if (char) {
return (
<span className={'text-content-on-fill font-medium h-full w-full flex items-center justify-center'}>
{char}
</span>
<span className={'flex h-full w-full items-center justify-center font-medium text-content-on-fill'}>{char}</span>
);
}
@@ -101,11 +116,18 @@ function SpaceIcon({ value, char, bgColor, className: classNameProp }: {
return customIcon;
}
return <IconComponent className={'h-full w-full'}/>;
return <IconComponent className={'h-full w-full'} />;
}, [IconComponent, char, customIcon]);
const className = useMemo(() => {
const classList = ['icon', 'h-[1.2em]', 'w-[1.2em]', 'shrink-0', 'rounded-[4px]', 'p-[0.1em]'];
const classList = [
'icon',
'h-[1.2em] min-h-[1.2em]',
'w-[1.2em] min-w-[1.2em]',
'shrink-0',
'rounded-[4px]',
'p-[0.1em]',
];
if (classNameProp) {
classList.push(classNameProp);
@@ -114,12 +136,16 @@ function SpaceIcon({ value, char, bgColor, className: classNameProp }: {
return classList.join(' ');
}, [classNameProp]);
return <span
className={className}
style={{
backgroundColor: bgColor ? renderColor(bgColor) : 'rgb(163, 74, 253)',
}}
>{content}</span>;
return (
<span
className={className}
style={{
backgroundColor: bgColor ? renderColor(bgColor) : 'rgb(163, 74, 253)',
}}
>
{content}
</span>
);
}
export default SpaceIcon;

View File

@@ -2,14 +2,14 @@ import { Suspense, useCallback, useMemo } from 'react';
import { useSearchParams } from 'react-router-dom';
import { ViewComponentProps, ViewLayout, YDatabase, YjsEditorKey } from '@/application/types';
import { useAppOutline } from '@/components/app/app.hooks';
import { Database } from '@/components/database';
import { findView } from '@/components/_shared/outline/utils';
import ComponentLoading from '@/components/_shared/progress/ComponentLoading';
import CalendarSkeleton from '@/components/_shared/skeleton/CalendarSkeleton';
import DocumentSkeleton from '@/components/_shared/skeleton/DocumentSkeleton';
import GridSkeleton from '@/components/_shared/skeleton/GridSkeleton';
import KanbanSkeleton from '@/components/_shared/skeleton/KanbanSkeleton';
import { useAppOutline } from '@/components/app/app.hooks';
import { Database } from '@/components/database';
import ViewMetaPreview from 'src/components/view-meta/ViewMetaPreview';
@@ -53,6 +53,7 @@ function DatabaseView(props: ViewComponentProps) {
);
const rowId = search.get('r') || undefined;
const modalRowId = search.get('r-modal') || undefined;
const doc = props.doc;
const database = doc?.getMap(YjsEditorKey.data_section)?.get(YjsEditorKey.database) as YDatabase;
const skeleton = useMemo(() => {
@@ -103,6 +104,7 @@ function DatabaseView(props: ViewComponentProps) {
visibleViewIds={visibleViewIds}
onChangeView={handleChangeView}
onOpenRowPage={handleNavigateToRow}
modalRowId={modalRowId}
/>
</Suspense>
</div>

View File

@@ -4,7 +4,7 @@ import { ErrorBoundary } from 'react-error-boundary';
import { useOutlineDrawer } from '@/components/_shared/outline/outline.hooks';
import { AFScroller } from '@/components/_shared/scroller';
import { useAIChatContext } from '@/components/ai-chat/AIChatProvider';
import { useViewErrorStatus } from '@/components/app/app.hooks';
import { useAppHandlers, useViewErrorStatus } from '@/components/app/app.hooks';
import { ConnectBanner } from '@/components/app/ConnectBanner';
import { AppHeader } from '@/components/app/header';
import Main from '@/components/app/Main';
@@ -17,6 +17,7 @@ function MainLayout() {
const { drawerOpened, drawerWidth, setDrawerWidth, toggleOpenDrawer } = useOutlineDrawer();
const { drawerOpen: chatViewDrawerOpen, drawerWidth: openViewDrawerWidth } = useAIChatContext();
const { openPageModalViewId } = useAppHandlers();
const { notFound, deleted } = useViewErrorStatus();
const main = useMemo(() => {
@@ -65,17 +66,19 @@ function MainLayout() {
/>
<ConnectBanner />
<div
className={'sticky-header-overlay'}
style={{
width: '100%',
position: 'sticky',
top: 48,
left: 0,
right: 0,
zIndex: 50,
}}
/>
{!openPageModalViewId && (
<div
className={'sticky-header-overlay'}
style={{
width: '100%',
position: 'sticky',
top: 48,
left: 0,
right: 0,
zIndex: 50,
}}
/>
)}
<ErrorBoundary FallbackComponent={SomethingError}>{main}</ErrorBoundary>
</AFScroller>

View File

@@ -7,6 +7,8 @@ import { UIVariant, ViewComponentProps, ViewLayout, ViewMetaProps, YDoc } from '
import { ReactComponent as ArrowDownIcon } from '@/assets/icons/alt_arrow_down.svg';
import { ReactComponent as CloseIcon } from '@/assets/icons/close.svg';
import { ReactComponent as ExpandIcon } from '@/assets/icons/expand.svg';
import { findAncestors, findView } from '@/components/_shared/outline/utils';
import SpaceIcon from '@/components/_shared/view-icon/SpaceIcon';
import { useAppHandlers, useAppOutline, useCurrentWorkspaceId } from '@/components/app/app.hooks';
import DatabaseView from '@/components/app/DatabaseView';
import MoreActions from '@/components/app/header/MoreActions';
@@ -14,8 +16,6 @@ import MovePagePopover from '@/components/app/view-actions/MovePagePopover';
import { Document } from '@/components/document';
import RecordNotFound from '@/components/error/RecordNotFound';
import { useService } from '@/components/main/app.hooks';
import { findAncestors, findView } from '@/components/_shared/outline/utils';
import SpaceIcon from '@/components/_shared/view-icon/SpaceIcon';
import ShareButton from 'src/components/app/share/ShareButton';
@@ -144,9 +144,6 @@ function ViewModal({ viewId, open, onClose }: { viewId?: string; open: boolean;
{space && ref.current && (
<MovePagePopover
viewId={viewId}
popoverContentProps={{
container: ref.current,
}}
open={movePageOpen}
onOpenChange={setMovePageOpen}
onMoved={() => {

View File

@@ -247,6 +247,7 @@ export function useAppHandlers() {
onRendered: context.onRendered,
addPage: context.addPage,
openPageModal: context.openPageModal,
openPageModalViewId: context.openPageModalViewId,
deletePage: context.deletePage,
deleteTrash: context.deleteTrash,
restorePage: context.restorePage,

View File

@@ -1,10 +1,11 @@
import { CustomIconPopover } from '@/components/_shared/cutsom-icon';
import SpaceIcon from '@/components/_shared/view-icon/SpaceIcon';
import { Avatar } from '@mui/material';
import React from 'react';
import { ReactComponent as EditIcon } from '@/assets/icons/edit.svg';
function SpaceIconButton ({
import { ReactComponent as EditIcon } from '@/assets/icons/edit.svg';
import { CustomIconPopover } from '@/components/_shared/cutsom-icon';
import SpaceIcon from '@/components/_shared/view-icon/SpaceIcon';
function SpaceIconButton({
spaceIcon,
spaceIconColor,
spaceName,
@@ -39,29 +40,33 @@ function SpaceIconButton ({
>
<Avatar
variant={'rounded'}
className={`${size ? `w-[${size}px] h-[${size}px]` : 'w-10 h-10'} rounded-[30%] bg-transparent`}
className={`aspect-square h-10 w-10 rounded-[30%] bg-transparent`}
onMouseEnter={() => setSpaceIconEditing(true)}
onMouseLeave={() => setSpaceIconEditing(false)}
onClick={() => {
setSpaceIconEditing(false);
}}
style={{
minWidth: size ? `${size}px` : undefined,
minHeight: size ? `${size}px` : '100%',
}}
>
<SpaceIcon
bgColor={spaceIconColor}
value={spaceIcon || ''}
className={'w-full h-full p-0.5'}
className={'h-full w-full !p-2'}
char={spaceIcon ? undefined : spaceName.slice(0, 1)}
/>
{spaceIconEditing &&
<div className={'absolute cursor-pointer inset-0 bg-black bg-opacity-30 rounded-[8px]'}>
<div className={'flex items-center text-white justify-center w-full h-full'}>
{spaceIconEditing && (
<div className={'absolute inset-0 cursor-pointer rounded-[8px] bg-black bg-opacity-30'}>
<div className={'flex h-full w-full items-center justify-center text-white'}>
<EditIcon />
</div>
</div>
}
)}
</Avatar>
</CustomIconPopover>
);
}
export default SpaceIconButton;
export default SpaceIconButton;

View File

@@ -1,12 +1,13 @@
import { Button, Divider } from '@mui/material';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { SpacePermission } from '@/application/types';
import { ReactComponent as ArrowDownIcon } from '@/assets/icons/alt_arrow_down.svg';
import { ReactComponent as LockIcon } from '@/assets/icons/lock.svg';
import { ReactComponent as PublicIcon } from '@/assets/icons/public.svg';
import { ReactComponent as TickIcon } from '@/assets/icons/tick.svg';
import { Popover } from '@/components/_shared/popover';
import { Button, Divider } from '@mui/material';
import React from 'react';
import { useTranslation } from 'react-i18next';
function SpacePermissionButton({
onSelected,

View File

@@ -33,6 +33,7 @@ export interface Database2Props {
viewId: string;
iidName: string;
rowId?: string;
modalRowId?: string;
appendBreadcrumb?: AppendBreadcrumb;
onChangeView: (viewId: string) => void;
onOpenRowPage?: (rowId: string) => void;
@@ -62,6 +63,7 @@ function Database(props: Database2Props) {
readOnly = true,
loadView,
navigateToView,
modalRowId,
} = props;
const database = doc.getMap(YjsEditorKey.data_section)?.get(YjsEditorKey.database) as YDatabase | null;
const view = database?.get(YjsDatabaseKey.views)?.get(iidIndex);
@@ -136,8 +138,8 @@ function Database(props: Database2Props) {
};
}, [handleUpdateRowDocMap, rowOrders]);
const [openModalRowId, setOpenModalRowId] = useState<string | null>(null);
const [openModalViewId, setOpenModalViewId] = useState<string | null>(null);
const [openModalRowId, setOpenModalRowId] = useState<string | null>(() => modalRowId || null);
const [openModalViewId, setOpenModalViewId] = useState<string | null>(() => (modalRowId ? viewId : null));
const [openModalRowDatabaseDoc, setOpenModalRowDatabaseDoc] = useState<YDoc | null>(null);
const [openModalRowDocMap, setOpenModalRowDocMap] = useState<Record<RowId, YDoc> | null>(null);

View File

@@ -3,11 +3,14 @@ import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { toast } from 'sonner';
import { useDatabaseContext } from '@/application/database-yjs';
import { useDeleteRowDispatch, useDuplicateRowDispatch } from '@/application/database-yjs/dispatch';
import { ReactComponent as ArrowLeftIcon } from '@/assets/icons/arrow_left.svg';
import { ReactComponent as DeleteIcon } from '@/assets/icons/delete.svg';
import { ReactComponent as DuplicateIcon } from '@/assets/icons/duplicate.svg';
import { ReactComponent as ExpandIcon } from '@/assets/icons/expand.svg';
import { ReactComponent as MoreIcon } from '@/assets/icons/more.svg';
import { AFScroller } from '@/components/_shared/scroller';
import { DatabaseRow } from '@/components/database/DatabaseRow';
import { Button } from '@/components/ui/button';
import {
@@ -19,7 +22,6 @@ import {
} from '@/components/ui/dropdown-menu';
import { Progress } from '@/components/ui/progress';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { AFScroller } from '@/components/_shared/scroller';
function DatabaseRowModal({
open,
@@ -32,7 +34,7 @@ function DatabaseRowModal({
onOpenChange: (open: boolean) => void;
openPage?: (rowId: string) => void;
}) {
// const {} = useDatabaseContext();
const { openPageModalViewId } = useDatabaseContext();
const { t } = useTranslation();
const duplicateRow = useDuplicateRowDispatch();
const deleteRow = useDeleteRowDispatch();
@@ -49,12 +51,32 @@ function DatabaseRowModal({
disableAutoFocus={false}
disableEnforceFocus={false}
disableRestoreFocus={true}
hideBackdrop={!!openPageModalViewId}
PaperProps={{
className: `max-w-[70vw] relative w-[1188px] h-[80vh] overflow-hidden flex flex-col`,
}}
>
<DialogContent className={'flex h-full w-full flex-col px-0 py-0'}>
<DialogTitle className={'flex max-h-[48px] flex-1 items-center justify-end gap-2 px-2'}>
<div className='flex flex-1 items-center'>
{openPageModalViewId && (
<Tooltip>
<TooltipTrigger asChild>
<Button
size={'icon'}
variant='ghost'
onClick={() => {
onOpenChange(false);
}}
>
<ArrowLeftIcon className='h-5 w-5' />
</Button>
</TooltipTrigger>
<TooltipContent>Go back</TooltipContent>
</Tooltip>
)}
</div>
<Tooltip>
<TooltipTrigger asChild>
<Button

View File

@@ -10,7 +10,6 @@ import { RenderRow, RenderRowType } from '@/components/database/components/grid/
import { useGridContext } from '@/components/database/grid/useGridContext';
import { cn } from '@/lib/utils';
const MIN_HEIGHT = 36;
function GridVirtualColumn({
data,
@@ -87,7 +86,6 @@ function GridVirtualColumn({
readOnly && rowType === RenderRowType.CalculateRow ? 'border-t border-border-primary' : ''
)}
style={{
height: rowIndex === 0 ? MIN_HEIGHT : row.size,
width: columnData.width,
}}
>