mirror of
https://github.com/lingble/twenty.git
synced 2025-11-01 21:27:58 +00:00
fix: Handling filename overflow in mobile viewports (#7364)
Fixes #7330 Fixes https://github.com/twentyhq/twenty/issues/7516 <div style="display: flex"> <img style="max-width:50%" src="https://github.com/user-attachments/assets/51027a9d-8745-4cc7-9f17-4000e3615e44"/> <img style="max-width:50%" src="https://github.com/user-attachments/assets/827f69ba-c581-402f-9498-6b1a4dde7b69"/> </div> --------- Co-authored-by: sid0-0 <a@b.com> Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
import { Card } from '@/ui/layout/card/components/Card';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledList = styled(Card)`
|
||||
& > :not(:last-child) {
|
||||
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
}
|
||||
|
||||
width: calc(100% - 2px);
|
||||
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
export const ActivityList = ({ children }: React.PropsWithChildren) => {
|
||||
return <StyledList>{children}</StyledList>;
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
import { CardContent } from '@/ui/layout/card/components/CardContent';
|
||||
import styled from '@emotion/styled';
|
||||
import React from 'react';
|
||||
|
||||
const StyledRowContent = styled(CardContent)<{
|
||||
clickable?: boolean;
|
||||
}>`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
height: ${({ theme }) => theme.spacing(12)};
|
||||
padding: ${({ theme }) => theme.spacing(0, 4)};
|
||||
cursor: ${({ clickable }) => (clickable === true ? 'pointer' : 'default')};
|
||||
`;
|
||||
|
||||
export const ActivityRow = ({
|
||||
children,
|
||||
onClick,
|
||||
disabled,
|
||||
}: React.PropsWithChildren<{
|
||||
onClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
|
||||
disabled?: boolean;
|
||||
}>) => {
|
||||
const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (disabled !== true) {
|
||||
onClick?.(event);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledRowContent onClick={handleClick} clickable={disabled !== true}>
|
||||
{children}
|
||||
</StyledRowContent>
|
||||
);
|
||||
};
|
||||
@@ -1,30 +1,15 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useRef } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { Avatar, GRAY_SCALE } from 'twenty-ui';
|
||||
|
||||
import { ActivityRow } from '@/activities/components/ActivityRow';
|
||||
import { EmailThreadNotShared } from '@/activities/emails/components/EmailThreadNotShared';
|
||||
import { useEmailThread } from '@/activities/emails/hooks/useEmailThread';
|
||||
import { emailThreadIdWhenEmailThreadWasClosedState } from '@/activities/emails/states/lastViewableEmailThreadIdState';
|
||||
import { CardContent } from '@/ui/layout/card/components/CardContent';
|
||||
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
||||
import { MessageChannelVisibility, TimelineThread } from '~/generated/graphql';
|
||||
import { formatToHumanReadableDate } from '~/utils/date-utils';
|
||||
|
||||
const StyledCardContent = styled(CardContent)<{
|
||||
visibility: MessageChannelVisibility;
|
||||
}>`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
height: ${({ theme }) => theme.spacing(12)};
|
||||
padding: ${({ theme }) => theme.spacing(0, 4)};
|
||||
cursor: ${({ visibility }) =>
|
||||
visibility === MessageChannelVisibility.ShareEverything
|
||||
? 'pointer'
|
||||
: 'default'};
|
||||
`;
|
||||
|
||||
const StyledHeading = styled.div<{ unread: boolean }>`
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
@@ -82,16 +67,10 @@ const StyledReceivedAt = styled.div`
|
||||
`;
|
||||
|
||||
type EmailThreadPreviewProps = {
|
||||
divider?: boolean;
|
||||
thread: TimelineThread;
|
||||
};
|
||||
|
||||
export const EmailThreadPreview = ({
|
||||
divider,
|
||||
thread,
|
||||
}: EmailThreadPreviewProps) => {
|
||||
const cardRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
export const EmailThreadPreview = ({ thread }: EmailThreadPreviewProps) => {
|
||||
const { openEmailThread } = useEmailThread();
|
||||
|
||||
const visibility = thread.visibility;
|
||||
@@ -143,12 +122,12 @@ export const EmailThreadPreview = ({
|
||||
],
|
||||
);
|
||||
|
||||
const isDisabled = visibility !== MessageChannelVisibility.ShareEverything;
|
||||
|
||||
return (
|
||||
<StyledCardContent
|
||||
ref={cardRef}
|
||||
<ActivityRow
|
||||
onClick={(event) => handleThreadClick(event)}
|
||||
divider={divider}
|
||||
visibility={visibility}
|
||||
disabled={isDisabled}
|
||||
>
|
||||
<StyledHeading unread={!thread.read}>
|
||||
<StyledParticipantsContainer>
|
||||
@@ -201,6 +180,6 @@ export const EmailThreadPreview = ({
|
||||
<StyledReceivedAt>
|
||||
{formatToHumanReadableDate(thread.lastMessageReceivedAt)}
|
||||
</StyledReceivedAt>
|
||||
</StyledCardContent>
|
||||
</ActivityRow>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { H1Title, H1TitleFontColor } from 'twenty-ui';
|
||||
|
||||
import { ActivityList } from '@/activities/components/ActivityList';
|
||||
import { CustomResolverFetchMoreLoader } from '@/activities/components/CustomResolverFetchMoreLoader';
|
||||
import { SkeletonLoader } from '@/activities/components/SkeletonLoader';
|
||||
import { EmailThreadPreview } from '@/activities/emails/components/EmailThreadPreview';
|
||||
@@ -18,7 +19,6 @@ import {
|
||||
AnimatedPlaceholderEmptyTitle,
|
||||
EMPTY_PLACEHOLDER_TRANSITION_PROPS,
|
||||
} from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled';
|
||||
import { Card } from '@/ui/layout/card/components/Card';
|
||||
import { Section } from '@/ui/layout/section/components/Section';
|
||||
import { TimelineThread, TimelineThreadsWithTotal } from '~/generated/graphql';
|
||||
|
||||
@@ -106,15 +106,11 @@ export const EmailThreads = ({
|
||||
fontColor={H1TitleFontColor.Primary}
|
||||
/>
|
||||
{!firstQueryLoading && (
|
||||
<Card>
|
||||
{timelineThreads?.map((thread: TimelineThread, index: number) => (
|
||||
<EmailThreadPreview
|
||||
key={index}
|
||||
divider={index < timelineThreads.length - 1}
|
||||
thread={thread}
|
||||
/>
|
||||
<ActivityList>
|
||||
{timelineThreads?.map((thread: TimelineThread) => (
|
||||
<EmailThreadPreview key={thread.id} thread={thread} />
|
||||
))}
|
||||
</Card>
|
||||
</ActivityList>
|
||||
)}
|
||||
<CustomResolverFetchMoreLoader
|
||||
loading={isFetchingMore || firstQueryLoading}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useUploadAttachmentFile } from '@/activities/files/hooks/useUploadAttac
|
||||
import { Attachment } from '@/activities/files/types/Attachment';
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
|
||||
import { ActivityList } from '@/activities/components/ActivityList';
|
||||
import { AttachmentRow } from './AttachmentRow';
|
||||
|
||||
type AttachmentListProps = {
|
||||
@@ -22,6 +23,9 @@ const StyledContainer = styled.div`
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: ${({ theme }) => theme.spacing(2, 6, 6)};
|
||||
|
||||
width: calc(100% - ${({ theme }) => theme.spacing(12)});
|
||||
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
@@ -44,21 +48,11 @@ const StyledCount = styled.span`
|
||||
margin-left: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledAttachmentContainer = styled.div`
|
||||
align-items: flex-start;
|
||||
align-self: stretch;
|
||||
background: ${({ theme }) => theme.background.secondary};
|
||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledDropZoneContainer = styled.div`
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
export const AttachmentList = ({
|
||||
@@ -91,11 +85,11 @@ export const AttachmentList = ({
|
||||
onUploadFile={onUploadFile}
|
||||
/>
|
||||
) : (
|
||||
<StyledAttachmentContainer>
|
||||
<ActivityList>
|
||||
{attachments.map((attachment) => (
|
||||
<AttachmentRow key={attachment.id} attachment={attachment} />
|
||||
))}
|
||||
</StyledAttachmentContainer>
|
||||
</ActivityList>
|
||||
)}
|
||||
</StyledDropZoneContainer>
|
||||
</StyledContainer>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ActivityRow } from '@/activities/components/ActivityRow';
|
||||
import { AttachmentDropdown } from '@/activities/files/components/AttachmentDropdown';
|
||||
import { AttachmentIcon } from '@/activities/files/components/AttachmentIcon';
|
||||
import { Attachment } from '@/activities/files/types/Attachment';
|
||||
@@ -13,26 +14,19 @@ import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { IconCalendar } from 'twenty-ui';
|
||||
import { IconCalendar, OverflowingTextWithTooltip } from 'twenty-ui';
|
||||
|
||||
import { formatToHumanReadableDate } from '~/utils/date-utils';
|
||||
import { getFileAbsoluteURI } from '~/utils/file/getFileAbsoluteURI';
|
||||
|
||||
const StyledRow = styled.div`
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
height: 32px;
|
||||
`;
|
||||
|
||||
const StyledLeftContent = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(3)};
|
||||
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
`;
|
||||
|
||||
const StyledRightContent = styled.div`
|
||||
@@ -52,11 +46,19 @@ const StyledLink = styled.a`
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
|
||||
width: 100%;
|
||||
|
||||
:hover {
|
||||
color: ${({ theme }) => theme.font.color.secondary};
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledLinkContainer = styled.div`
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const AttachmentRow = ({ attachment }: { attachment: Attachment }) => {
|
||||
const theme = useTheme();
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
@@ -97,7 +99,7 @@ export const AttachmentRow = ({ attachment }: { attachment: Attachment }) => {
|
||||
|
||||
return (
|
||||
<FieldContext.Provider value={fieldContext as GenericFieldContextType}>
|
||||
<StyledRow>
|
||||
<ActivityRow disabled>
|
||||
<StyledLeftContent>
|
||||
<AttachmentIcon attachmentType={attachment.type} />
|
||||
{isEditing ? (
|
||||
@@ -109,12 +111,14 @@ export const AttachmentRow = ({ attachment }: { attachment: Attachment }) => {
|
||||
fullWidth
|
||||
/>
|
||||
) : (
|
||||
<StyledLink
|
||||
href={getFileAbsoluteURI(attachment.fullPath)}
|
||||
target="__blank"
|
||||
>
|
||||
{attachment.name}
|
||||
</StyledLink>
|
||||
<StyledLinkContainer>
|
||||
<StyledLink
|
||||
href={getFileAbsoluteURI(attachment.fullPath)}
|
||||
target="__blank"
|
||||
>
|
||||
<OverflowingTextWithTooltip text={attachment.name} />
|
||||
</StyledLink>
|
||||
</StyledLinkContainer>
|
||||
)}
|
||||
</StyledLeftContent>
|
||||
<StyledRightContent>
|
||||
@@ -131,7 +135,7 @@ export const AttachmentRow = ({ attachment }: { attachment: Attachment }) => {
|
||||
onRename={handleRename}
|
||||
/>
|
||||
</StyledRightContent>
|
||||
</StyledRow>
|
||||
</ActivityRow>
|
||||
</FieldContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { ReactElement } from 'react';
|
||||
|
||||
import { ActivityList } from '@/activities/components/ActivityList';
|
||||
import { Task } from '@/activities/types/Task';
|
||||
import { TaskRow } from './TaskRow';
|
||||
|
||||
@@ -17,7 +18,9 @@ const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 8px 24px;
|
||||
padding: 8px ${({ theme }) => theme.spacing(6)};
|
||||
|
||||
width: calc(100% - ${({ theme }) => theme.spacing(12)});
|
||||
`;
|
||||
|
||||
const StyledTitleBar = styled.div`
|
||||
@@ -39,13 +42,6 @@ const StyledCount = styled.span`
|
||||
margin-left: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledTaskRows = styled.div`
|
||||
background-color: ${({ theme }) => theme.background.secondary};
|
||||
border: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const TaskList = ({ title, tasks, button }: TaskListProps) => (
|
||||
<>
|
||||
{tasks && tasks.length > 0 && (
|
||||
@@ -58,11 +54,11 @@ export const TaskList = ({ title, tasks, button }: TaskListProps) => (
|
||||
)}
|
||||
{button}
|
||||
</StyledTitleBar>
|
||||
<StyledTaskRows>
|
||||
<ActivityList>
|
||||
{tasks.map((task) => (
|
||||
<TaskRow key={task.id} task={task} />
|
||||
))}
|
||||
</StyledTaskRows>
|
||||
</ActivityList>
|
||||
</StyledContainer>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -8,28 +8,12 @@ import { getActivitySummary } from '@/activities/utils/getActivitySummary';
|
||||
import { Checkbox, CheckboxShape } from '@/ui/input/components/Checkbox';
|
||||
import { beautifyExactDate, hasDatePassed } from '~/utils/date-utils';
|
||||
|
||||
import { ActivityRow } from '@/activities/components/ActivityRow';
|
||||
import { Task } from '@/activities/types/Task';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useFieldContext } from '@/object-record/hooks/useFieldContext';
|
||||
import { useCompleteTask } from '../hooks/useCompleteTask';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
height: ${({ theme }) => theme.spacing(12)};
|
||||
min-width: calc(100% - ${({ theme }) => theme.spacing(8)});
|
||||
max-width: calc(100% - ${({ theme }) => theme.spacing(8)});
|
||||
padding: 0 ${({ theme }) => theme.spacing(4)};
|
||||
overflow: hidden;
|
||||
max-inline-size: 60px;
|
||||
&:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledTaskBody = styled.div`
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
display: flex;
|
||||
@@ -105,7 +89,7 @@ export const TaskRow = ({ task }: { task: Task }) => {
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledContainer
|
||||
<ActivityRow
|
||||
onClick={() => {
|
||||
openActivityRightDrawer(task.id);
|
||||
}}
|
||||
@@ -150,6 +134,6 @@ export const TaskRow = ({ task }: { task: Task }) => {
|
||||
</TaskTargetsContextProvider>
|
||||
)}
|
||||
</StyledRightSideContainer>
|
||||
</StyledContainer>
|
||||
</ActivityRow>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -37,12 +37,12 @@ import {
|
||||
|
||||
const StyledShowPageRightContainer = styled.div<{ isMobile: boolean }>`
|
||||
display: flex;
|
||||
flex: 1 0 0;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
justify-content: start;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
const StyledTabListContainer = styled.div`
|
||||
|
||||
@@ -28,6 +28,9 @@ export type Story = StoryObj<typeof SettingsNewObject>;
|
||||
export const WithStandardSelected: Story = {
|
||||
play: async () => {
|
||||
const canvas = within(document.body);
|
||||
|
||||
await canvas.findByText('New Object');
|
||||
|
||||
const listingInput = await canvas.findByPlaceholderText('Listing');
|
||||
const pluralInput = await canvas.findByPlaceholderText('Listings');
|
||||
const descriptionInput = await canvas.findByPlaceholderText(
|
||||
|
||||
Reference in New Issue
Block a user