mirror of
https://github.com/laurent22/joplin.git
synced 2026-10-25 02:47:28 +00:00
Mobile: Implement redesigned screen header (#16345)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
This commit is contained in:
1 parent
00d62e8700
commit
b0affc0a30
8 files changed
+65
-42
No files matched your search
@@ -5,7 +5,7 @@ import Folder, { FolderEntityWithChildren } from '@joplin/lib/models/Folder';
|
||||
import { themeStyle } from './global-style';
|
||||
import Dropdown, { DropdownListItem, OnValueChangedListener } from './Dropdown';
|
||||
import { FolderEntity } from '@joplin/lib/services/database/types';
|
||||
import { View } from 'react-native';
|
||||
import { TextStyle, View } from 'react-native';
|
||||
import { Button } from 'react-native-paper';
|
||||
import { DialogContext } from './DialogManager';
|
||||
|
||||
@@ -18,6 +18,7 @@ interface FolderPickerProps {
|
||||
placeholder?: string;
|
||||
darkText?: boolean;
|
||||
themeId?: number;
|
||||
headerStyle?: TextStyle;
|
||||
coverableChildrenRight?: ReactElement|ReactElement[];
|
||||
onNewFolder?: (title: string)=> void;
|
||||
}
|
||||
@@ -30,6 +31,7 @@ const FolderPicker: FunctionComponent<FolderPickerProps> = ({
|
||||
mustSelect,
|
||||
folders,
|
||||
placeholder,
|
||||
headerStyle,
|
||||
darkText,
|
||||
coverableChildrenRight,
|
||||
onNewFolder,
|
||||
@@ -86,9 +88,11 @@ const FolderPicker: FunctionComponent<FolderPickerProps> = ({
|
||||
backgroundColor: theme.backgroundColor,
|
||||
}}
|
||||
headerStyle={{
|
||||
color: darkText ? theme.colorFaded : theme.colorBright2,
|
||||
color: darkText ? theme.color : theme.colorFaded,
|
||||
fontWeight: darkText ? 'bold' : 'normal',
|
||||
fontSize: theme.fontSize,
|
||||
opacity: disabled ? theme.disabledOpacity : 1,
|
||||
...headerStyle,
|
||||
}}
|
||||
itemStyle={{
|
||||
color: theme.color,
|
||||
|
||||
@@ -114,22 +114,21 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
innerContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.backgroundColor2,
|
||||
shadowColor: '#000000',
|
||||
elevation: 5,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
borderBottomColor: theme.dividerColor,
|
||||
borderBottomWidth: 1,
|
||||
// 2026-08-28: Including a fully transparent shadow avoids a crash on iOS when opening settings:
|
||||
shadowColor: '#000',
|
||||
shadowOpacity: 0,
|
||||
},
|
||||
// A small border above the header: Covers the part of the shadow that would otherwise
|
||||
// be shown above the header on Android.
|
||||
aboveHeader: {
|
||||
backgroundColor: theme.backgroundColor2,
|
||||
paddingBottom: 6,
|
||||
marginTop: -6,
|
||||
zIndex: 2,
|
||||
folderPicker: {
|
||||
marginRight: theme.marginMedium,
|
||||
fontSize: theme.fontSizeLarger,
|
||||
},
|
||||
sideMenuButton: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.backgroundColor2,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
paddingLeft: theme.marginLeft,
|
||||
paddingRight: 5,
|
||||
marginRight: 2,
|
||||
@@ -138,7 +137,7 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
},
|
||||
iconButton: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.backgroundColor2,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10,
|
||||
paddingTop: PADDING_V,
|
||||
@@ -153,61 +152,60 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
minHeight: 40,
|
||||
|
||||
borderWidth: 1,
|
||||
borderColor: theme.colorBright2,
|
||||
borderColor: theme.color,
|
||||
borderRadius: 4,
|
||||
marginRight: 8,
|
||||
},
|
||||
saveButtonText: {
|
||||
textAlignVertical: 'center',
|
||||
color: theme.colorBright2,
|
||||
color: theme.color,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
savedButtonIcon: {
|
||||
...theme.icon,
|
||||
fontSize: 20,
|
||||
color: theme.colorBright2,
|
||||
width: 18,
|
||||
height: 18,
|
||||
},
|
||||
saveButtonIcon: {
|
||||
...theme.icon,
|
||||
fontSize: 25,
|
||||
color: theme.colorBright2,
|
||||
},
|
||||
contextMenuTrigger: {
|
||||
fontSize: 30,
|
||||
paddingLeft: 5,
|
||||
paddingRight: theme.marginRight,
|
||||
color: theme.color2,
|
||||
color: theme.color,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
titleText: {
|
||||
flex: 1,
|
||||
textAlignVertical: 'center',
|
||||
marginLeft: 10,
|
||||
color: theme.colorBright2,
|
||||
color: theme.color,
|
||||
fontWeight: 'bold',
|
||||
fontSize: theme.fontSize,
|
||||
fontSize: theme.fontSizeLarger,
|
||||
paddingTop: 15,
|
||||
paddingBottom: 15,
|
||||
},
|
||||
viewToggleButton: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.backgroundColor2,
|
||||
paddingLeft: 22,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10,
|
||||
paddingTop: PADDING_V,
|
||||
paddingBottom: PADDING_V,
|
||||
},
|
||||
viewToggleIcon: {
|
||||
fontSize: 27,
|
||||
color: theme.colorBright2,
|
||||
color: theme.color,
|
||||
flex: 1,
|
||||
textAlignVertical: 'center',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
const topIcon: TextStyle = { ...theme.icon, flex: 1, textAlignVertical: 'center', color: theme.colorBright2 };
|
||||
const topIcon: TextStyle = { ...theme.icon, flex: 1, textAlignVertical: 'center', color: theme.color };
|
||||
styleObject.topIcon = topIcon;
|
||||
|
||||
styleObject.backButton = { ...styleObject.iconButton };
|
||||
@@ -553,7 +551,7 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
themeId={themeId}
|
||||
|
||||
description={_('Sort notes by')}
|
||||
iconName='ionicon filter-outline'
|
||||
iconName='ionicon filter'
|
||||
contentWrapperStyle={styles.iconButton}
|
||||
iconStyle={styles.topIcon}
|
||||
/>
|
||||
@@ -589,7 +587,9 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
<FolderPicker
|
||||
themeId={themeId}
|
||||
disabled={disabled}
|
||||
headerStyle={this.styles().folderPicker}
|
||||
selectedFolderId={'selectedFolderId' in folderPickerOptions ? folderPickerOptions.selectedFolderId : null}
|
||||
darkText
|
||||
onValueChange={async (folderId) => {
|
||||
// If onValueChange is specified, use this as a callback, otherwise do the default
|
||||
// which is to take the selectedNoteIds from the state and move them to the
|
||||
@@ -709,7 +709,6 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
|
||||
return (
|
||||
<View style={this.styles().outerContainer}>
|
||||
<View style={this.styles().aboveHeader}/>
|
||||
<View style={this.styles().innerContainer}>
|
||||
{zeroWidthSpacer}
|
||||
{sideMenuComp}
|
||||
|
||||
@@ -185,7 +185,6 @@ const NotePreview: React.FC<Props> = ({
|
||||
/>
|
||||
<FolderPicker
|
||||
themeId={themeId}
|
||||
darkText
|
||||
placeholder={_('Select notebook')}
|
||||
folders={realFolders}
|
||||
onValueChange={setSelectedFolderId}
|
||||
|
||||
@@ -552,14 +552,25 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
flexDirection: 'row',
|
||||
flexBasis: 'auto',
|
||||
paddingLeft: theme.marginLeft,
|
||||
borderBottomColor: theme.dividerColor,
|
||||
borderBottomWidth: 1,
|
||||
paddingRight: theme.marginRight,
|
||||
maxHeight: '40%',
|
||||
|
||||
// Prevents the title/content divider overlaying the title's focus indicator on web:
|
||||
zIndex: 1,
|
||||
};
|
||||
|
||||
styles.titleContainerTodo = { ...styles.titleContainer };
|
||||
styles.titleContainerTodo.paddingLeft = 0;
|
||||
|
||||
styles.titleDivider = {
|
||||
flex: 0,
|
||||
height: 0,
|
||||
marginLeft: theme.marginLeft,
|
||||
marginRight: theme.marginRight,
|
||||
borderBottomColor: theme.dividerColor,
|
||||
borderBottomWidth: 1,
|
||||
};
|
||||
|
||||
styles.titleTextInput = {
|
||||
flex: 1,
|
||||
marginTop: 0,
|
||||
@@ -567,8 +578,8 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
color: theme.color,
|
||||
fontWeight: 'bold',
|
||||
fontSize: theme.fontSize,
|
||||
paddingTop: theme.itemMarginTop, // Added for iOS (Not needed for Android??)
|
||||
paddingBottom: theme.itemMarginBottom, // Added for iOS (Not needed for Android??)
|
||||
paddingTop: theme.marginTop,
|
||||
paddingBottom: theme.marginBottom,
|
||||
};
|
||||
|
||||
this.styles_[cacheKey] = StyleSheet.create(styles);
|
||||
@@ -2003,7 +2014,7 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
style={{ width: 30, height: 30, alignSelf: 'center' }}
|
||||
/>;
|
||||
|
||||
const titleComp = (
|
||||
const titleComp = <>
|
||||
<View
|
||||
style={titleContainerStyle}
|
||||
onLayout={(e) => {
|
||||
@@ -2046,7 +2057,8 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
/>
|
||||
{ titleToggleButton }
|
||||
</View>
|
||||
);
|
||||
<View style={this.styles().titleDivider}/>
|
||||
</>;
|
||||
|
||||
const noteTagDialog = !this.state.noteTagDialogShown ? null : <NoteTagsDialog onCloseRequested={this.noteTagDialog_closeRequested} />;
|
||||
|
||||
|
||||
@@ -126,7 +126,6 @@ class FolderScreenComponent extends BaseScreenComponent<Props, State> {
|
||||
selectedFolderId={this.state.folder.parent_id}
|
||||
onValueChange={newValue => this.parent_changeValue(newValue)}
|
||||
mustSelect
|
||||
darkText
|
||||
/>
|
||||
</View>
|
||||
<View style={{ flex: 1 }} />
|
||||
|
||||
@@ -133,6 +133,12 @@ const useSource = (props: UseSourceProps) => {
|
||||
${rendererCss}
|
||||
${markdownEditorCss}
|
||||
|
||||
body.rich-text-editor {
|
||||
/* Zero the body padding to align the editor content with the note title */
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
/* Increase the size of the editor to make it easier to focus the editor. */
|
||||
.prosemirror-editor {
|
||||
min-height: 75vh;
|
||||
@@ -143,6 +149,8 @@ const useSource = (props: UseSourceProps) => {
|
||||
${rendererJs}
|
||||
${markdownEditorJs}
|
||||
|
||||
document.body.classList.add('rich-text-editor');
|
||||
|
||||
if (!window.richTextEditorCreated) {
|
||||
window.richTextEditorCreated = true;
|
||||
${shim.injectedJs('richTextEditorBundle')}
|
||||
|
||||
@@ -781,7 +781,7 @@ class AppComponent extends React.Component<AppComponentProps, AppComponentState>
|
||||
|
||||
|
||||
// const statusBarStyle = theme.appearance === 'light-content';
|
||||
const statusBarStyle = 'light-content';
|
||||
const statusBarStyle = theme.appearance === ThemeAppearance.Light ? 'dark-content' : 'light-content';
|
||||
|
||||
const shouldShowMainContent = !biometricsEnabled(this.state.sensorInfo) || this.props.biometricsDone;
|
||||
|
||||
@@ -793,7 +793,7 @@ class AppComponent extends React.Component<AppComponentProps, AppComponentState>
|
||||
const mainContent = (
|
||||
<View style={{ flex: 1, backgroundColor: theme.backgroundColor }}>
|
||||
<View style={{ flexGrow: 1, flexShrink: 1, flexBasis: '100%' }}>
|
||||
<SafeAreaView style={{ flex: 1 }} titleBarUnderlayColor={theme.backgroundColor2}>
|
||||
<SafeAreaView style={{ flex: 1 }} titleBarUnderlayColor={theme.backgroundColor}>
|
||||
<SideMenu
|
||||
menu={sideMenuContent}
|
||||
toleranceX={4}
|
||||
|
||||
Vendored
+7
-5
@@ -89,6 +89,7 @@ const createTheme = (theme: EditorTheme): Extension[] => {
|
||||
paddingBottom: '0.2em',
|
||||
};
|
||||
|
||||
const linePaddingLeft = 1;
|
||||
const codeMirrorTheme = EditorView.theme({
|
||||
// Include &.CodeMirror to handle the case where additional CodeMirror 5 styles
|
||||
// need to be overridden.
|
||||
@@ -104,7 +105,8 @@ const createTheme = (theme: EditorTheme): Extension[] => {
|
||||
fontFamily: theme.fontFamily,
|
||||
...baseContentStyle,
|
||||
paddingBottom: `${theme.paddingBottom}px`,
|
||||
marginLeft: `${theme.marginLeft}px`,
|
||||
|
||||
marginLeft: `${Math.max(theme.marginLeft - linePaddingLeft, 0)}px`,
|
||||
marginRight: `${theme.marginRight}px`,
|
||||
},
|
||||
|
||||
@@ -172,12 +174,12 @@ const createTheme = (theme: EditorTheme): Extension[] => {
|
||||
marginRight: 'auto',
|
||||
} : undefined,
|
||||
|
||||
// Allows editor content to be left-aligned with the toolbar on desktop.
|
||||
// Allows editor content to be left-aligned with the toolbar.
|
||||
// See https://github.com/laurent22/joplin/issues/11279
|
||||
[`${editorNoGuttersSelector} .cm-line`]: theme.isDesktop ? {
|
||||
[`${editorNoGuttersSelector} .cm-line`]: {
|
||||
// Note: This cannot be zero:
|
||||
paddingLeft: '1px',
|
||||
} : undefined,
|
||||
paddingLeft: `${linePaddingLeft}px`,
|
||||
},
|
||||
|
||||
// Override the default URL style when the URL is within a link
|
||||
'& .tok-url.tok-link, & .tok-link.tok-meta, & .tok-link.tok-string': {
|
||||
|
||||
Reference in new issue
Block a user