- Added accomodation of mobile navigation bar in command menu (#17419)
Fix for #16743 Added styles to accommodate for mobile navigation bar for better visibility and better access of the command menu buttons. ## CommandMenuAskAIPage.tsx (Not shown in the issue) ### Before <img width="1100" height="1792" alt="screenshot-2026-01-24_17-22-45" src="https://github.com/user-attachments/assets/8a337ffe-9dfc-4e52-b744-622cc6989ae4" /> ### After Since the component here already had some padding on it the mobile navigation bar offset was lesser than it is in other places. <img width="1092" height="1778" alt="screenshot-2026-01-24_17-28-33" src="https://github.com/user-attachments/assets/00a217f1-d98e-4303-bdc1-df112d71a553" /> ## CommandMenuWorkflowEditStep.tsx ### Before As mentioned in the issue ### After <img width="755" height="1061" alt="image" src="https://github.com/user-attachments/assets/487d0b20-f544-4e85-99d5-eb5add4b2cb4" /> ## CommandMenuWorkflowRunViewStep.tsx ### Before As shown in the issue ### After <img width="1102" height="1784" alt="screenshot-2026-01-24_17-19-31" src="https://github.com/user-attachments/assets/a95773e3-5f61-46d0-93cb-e678e087a42f" /> --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
committed by
GitHub
parent
7e5e800f63
commit
2d42b0a726
@@ -22,6 +22,7 @@ import { AI_CHAT_SCROLL_WRAPPER_ID } from '@/ai/constants/AiChatScrollWrapperId'
|
||||
import { useAIChatFileUpload } from '@/ai/hooks/useAIChatFileUpload';
|
||||
import { useAgentChatContextOrThrow } from '@/ai/hooks/useAgentChatContextOrThrow';
|
||||
import { agentChatInputState } from '@/ai/states/agentChatInputState';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useState } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
@@ -36,12 +37,13 @@ const StyledContainer = styled.div<{ isDraggingFile: boolean }>`
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const StyledInputArea = styled.div`
|
||||
const StyledInputArea = styled.div<{ isMobile: boolean }>`
|
||||
align-items: flex-end;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
padding: ${({ theme }) => theme.spacing(3)};
|
||||
padding-inline: ${({ theme }) => theme.spacing(3)};
|
||||
padding-block: ${({ theme, isMobile }) => (isMobile ? 0 : theme.spacing(3))};
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
`;
|
||||
|
||||
@@ -105,7 +107,7 @@ const StyledButtonsContainer = styled.div`
|
||||
|
||||
export const AIChatTab = () => {
|
||||
const [isDraggingFile, setIsDraggingFile] = useState(false);
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
const { isLoading, messages, isStreaming, error } =
|
||||
useAgentChatContextOrThrow();
|
||||
|
||||
@@ -163,7 +165,7 @@ export const AIChatTab = () => {
|
||||
)}
|
||||
{isLoading && messages.length === 0 && <AIChatSkeletonLoader />}
|
||||
|
||||
<StyledInputArea>
|
||||
<StyledInputArea isMobile={isMobile}>
|
||||
<AgentChatContextPreview />
|
||||
<StyledInputBox>
|
||||
<StyledTextAreaWrapper>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { AgentChatProvider } from '@/ai/components/AgentChatProvider';
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
@@ -7,9 +8,21 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/con
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
const StyledCommandMenuContainer = styled.div<{ isMobile: boolean }>`
|
||||
max-height: ${({ theme, isMobile }) => {
|
||||
const mobileOffset = isMobile ? theme.spacing(16) : '0px';
|
||||
|
||||
return `calc(100% - ${mobileOffset})`;
|
||||
}};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
`;
|
||||
|
||||
type CommandMenuContainerProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
@@ -21,6 +34,7 @@ export const CommandMenuContainer = ({
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState,
|
||||
COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
);
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||
|
||||
@@ -46,7 +60,11 @@ export const CommandMenuContainer = ({
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID }}
|
||||
>
|
||||
<AgentChatProvider>{children}</AgentChatProvider>
|
||||
<AgentChatProvider>
|
||||
<StyledCommandMenuContainer isMobile={isMobile}>
|
||||
{children}
|
||||
</StyledCommandMenuContainer>
|
||||
</AgentChatProvider>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
|
||||
@@ -14,8 +14,6 @@ import { t } from '@lingui/core/macro';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
|
||||
|
||||
const MOBILE_NAVIGATION_BAR_HEIGHT = 64;
|
||||
|
||||
export type CommandMenuListProps = {
|
||||
commandGroups: ActionGroupConfig[];
|
||||
selectableItemIds: string[];
|
||||
@@ -27,8 +25,7 @@ export type CommandMenuListProps = {
|
||||
const StyledInnerList = styled.div`
|
||||
max-height: calc(
|
||||
100dvh - ${COMMAND_MENU_SEARCH_BAR_HEIGHT}px -
|
||||
${COMMAND_MENU_SEARCH_BAR_PADDING * 2}px -
|
||||
${MOBILE_NAVIGATION_BAR_HEIGHT}px
|
||||
${COMMAND_MENU_SEARCH_BAR_PADDING * 2}px
|
||||
);
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
padding-right: ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { AIChatTab } from '@/ai/components/AIChatTab';
|
||||
import styled from '@emotion/styled';
|
||||
import { AIChatTab } from '@/ai/components/AIChatTab';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
height: 100%;
|
||||
|
||||
+2
-6
@@ -8,7 +8,6 @@ import { EmailThreadMessage } from '@/activities/emails/components/EmailThreadMe
|
||||
import { CommandMenuMessageThreadIntermediaryMessages } from '@/command-menu/pages/message-thread/components/CommandMenuMessageThreadIntermediaryMessages';
|
||||
import { useEmailThreadInCommandMenu } from '@/command-menu/pages/message-thread/hooks/useEmailThreadInCommandMenu';
|
||||
import { messageThreadComponentState } from '@/command-menu/pages/message-thread/states/messageThreadComponentState';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { ConnectedAccountProvider } from 'twenty-shared/types';
|
||||
@@ -31,12 +30,11 @@ const StyledContainer = styled.div`
|
||||
overflow-y: auto;
|
||||
`;
|
||||
|
||||
const StyledButtonContainer = styled.div<{ isMobile: boolean }>`
|
||||
const StyledButtonContainer = styled.div`
|
||||
background: ${({ theme }) => theme.background.secondary};
|
||||
border-top: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
height: ${({ isMobile }) => (isMobile ? '100px' : '50px')};
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
@@ -53,8 +51,6 @@ export const CommandMenuMessageThreadPage = () => {
|
||||
messageThreadComponentState,
|
||||
);
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const {
|
||||
thread,
|
||||
messages,
|
||||
@@ -170,7 +166,7 @@ export const CommandMenuMessageThreadPage = () => {
|
||||
)}
|
||||
</StyledContainer>
|
||||
{canReply && !messageChannelLoading && (
|
||||
<StyledButtonContainer isMobile={isMobile}>
|
||||
<StyledButtonContainer>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={handleReplyClick}
|
||||
|
||||
+3
-12
@@ -4,23 +4,14 @@ import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { MergeRecordsContainer } from '@/object-record/record-merge/components/MergeRecordsContainer';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledRightDrawerRecord = styled.div<{
|
||||
isMobile: boolean;
|
||||
}>`
|
||||
height: ${({ theme, isMobile }) => {
|
||||
const mobileOffset = isMobile ? theme.spacing(16) : '0px';
|
||||
|
||||
return `calc(100% - ${mobileOffset})`;
|
||||
}};
|
||||
const StyledRightDrawerRecord = styled.div`
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
export const CommandMenuMergeRecordPage = () => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const commandMenuPageInstanceId = useComponentInstanceStateContext(
|
||||
CommandMenuPageComponentInstanceContext,
|
||||
)?.instanceId;
|
||||
@@ -45,7 +36,7 @@ export const CommandMenuMergeRecordPage = () => {
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: commandMenuPageInstanceId }}
|
||||
>
|
||||
<StyledRightDrawerRecord isMobile={isMobile}>
|
||||
<StyledRightDrawerRecord>
|
||||
<MergeRecordsContainer
|
||||
objectNameSingular={objectMetadataItem.nameSingular}
|
||||
/>
|
||||
|
||||
+3
-11
@@ -9,28 +9,23 @@ import { RecordComponentInstanceContextsWrapper } from '@/object-record/componen
|
||||
import { PageLayoutDispatcher } from '@/object-record/record-show/components/PageLayoutDispatcher';
|
||||
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
const StyledRightDrawerRecord = styled.div<{
|
||||
isMobile: boolean;
|
||||
hasDeletedRecordBanner: boolean;
|
||||
}>`
|
||||
height: ${({ theme, isMobile, hasDeletedRecordBanner }) => {
|
||||
const mobileOffset = isMobile ? theme.spacing(16) : '0px';
|
||||
height: ${({ hasDeletedRecordBanner }) => {
|
||||
const bannerOffset = hasDeletedRecordBanner
|
||||
? INFORMATION_BANNER_HEIGHT
|
||||
: '0px';
|
||||
return `calc(100% - ${mobileOffset} - ${bannerOffset})`;
|
||||
return `calc(100% - ${bannerOffset})`;
|
||||
}};
|
||||
`;
|
||||
|
||||
export const CommandMenuRecordPage = () => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const viewableRecordNameSingular = useRecoilComponentValue(
|
||||
viewableRecordNameSingularComponentState,
|
||||
);
|
||||
@@ -79,10 +74,7 @@ export const CommandMenuRecordPage = () => {
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: commandMenuPageInstanceId }}
|
||||
>
|
||||
<StyledRightDrawerRecord
|
||||
isMobile={isMobile}
|
||||
hasDeletedRecordBanner={!!recordDeletedAt}
|
||||
>
|
||||
<StyledRightDrawerRecord hasDeletedRecordBanner={!!recordDeletedAt}>
|
||||
<TimelineActivityContext.Provider
|
||||
value={{
|
||||
recordId: objectRecordId,
|
||||
|
||||
+3
-12
@@ -2,23 +2,14 @@ import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/c
|
||||
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
|
||||
|
||||
import { UpdateMultipleRecordsContainer } from '@/object-record/record-update-multiple/components/UpdateMultipleRecordsContainer';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledRightDrawerRecord = styled.div<{
|
||||
isMobile: boolean;
|
||||
}>`
|
||||
height: ${({ theme, isMobile }) => {
|
||||
const mobileOffset = isMobile ? theme.spacing(16) : '0px';
|
||||
|
||||
return `calc(100% - ${mobileOffset})`;
|
||||
}};
|
||||
const StyledRightDrawerRecord = styled.div`
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
export const CommandMenuUpdateMultipleRecords = () => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const commandMenuPageInstanceId = useComponentInstanceStateContext(
|
||||
CommandMenuPageComponentInstanceContext,
|
||||
)?.instanceId;
|
||||
@@ -32,7 +23,7 @@ export const CommandMenuUpdateMultipleRecords = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledRightDrawerRecord isMobile={isMobile}>
|
||||
<StyledRightDrawerRecord>
|
||||
<UpdateMultipleRecordsContainer
|
||||
objectNameSingular={objectMetadataItem.nameSingular}
|
||||
contextStoreInstanceId={commandMenuPageInstanceId}
|
||||
|
||||
-1
@@ -5,7 +5,6 @@ import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-
|
||||
|
||||
export const CommandMenuWorkflowRunViewStep = () => {
|
||||
const workflowRunId = useCommandMenuWorkflowRunIdOrThrow();
|
||||
|
||||
return (
|
||||
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||
value={{
|
||||
|
||||
Reference in New Issue
Block a user