mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-10-02 09:24:45 +08:00
Add option for vertically stacked reading pane (#2243)
* Add option for vertically stacked reading pane * Switch from creating a separate column to scoping ThreadList to split+list modes * Better styling for vertical reading pane * Fix bug that prevented changing the panel layout via the preferences dialog * Add resize functionality for vertical thread list * Add Contact Toolbar button to Thread List Vertical View * Remove debug log Co-authored-by: Ben Gotow <ben@foundry376.com>
This commit is contained in:
parent
d0583899ee
commit
c7f7dc027c
15 changed files with 161 additions and 43 deletions
|
@ -26,7 +26,7 @@ export function activate() {
|
||||||
|
|
||||||
ComponentRegistry.register(ToggleWithTutorialTip, {
|
ComponentRegistry.register(ToggleWithTutorialTip, {
|
||||||
location: WorkspaceStore.Sheet.Threads.Toolbar.Right,
|
location: WorkspaceStore.Sheet.Threads.Toolbar.Right,
|
||||||
modes: ['split'],
|
modes: ['split', 'splitVertical'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,8 +62,9 @@ export function activate() {
|
||||||
'Preferences',
|
'Preferences',
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
split: ['Preferences'],
|
|
||||||
list: ['Preferences'],
|
list: ['Preferences'],
|
||||||
|
split: ['Preferences'],
|
||||||
|
splitVertical: ['Preferences'],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -135,11 +135,13 @@ class AppearanceModeSwitch extends React.Component<
|
||||||
}
|
}
|
||||||
|
|
||||||
_onApplyChanges = () => {
|
_onApplyChanges = () => {
|
||||||
AppEnv.commands.dispatch(`navigation:select-${this.state.value}-mode`);
|
// The command to be called contains an `off` as this denotes the current
|
||||||
|
// state that is used to show the menu item in an (in)active state.
|
||||||
|
AppEnv.commands.dispatch(`navigation:${this.state.value}-mode-off`);
|
||||||
};
|
};
|
||||||
|
|
||||||
_renderModeOptions() {
|
_renderModeOptions() {
|
||||||
return ['list', 'split'].map(mode => (
|
return ['list', 'split', 'splitVertical'].map(mode => (
|
||||||
<AppearanceModeOption
|
<AppearanceModeOption
|
||||||
mode={mode}
|
mode={mode}
|
||||||
key={mode}
|
key={mode}
|
||||||
|
@ -174,6 +176,7 @@ const AppearanceModeOption = function AppearanceModeOption(props) {
|
||||||
const label = {
|
const label = {
|
||||||
list: localized('Single Panel'),
|
list: localized('Single Panel'),
|
||||||
split: localized('Two Panel'),
|
split: localized('Two Panel'),
|
||||||
|
splitVertical: localized('Two Panel Vertical'),
|
||||||
}[props.mode];
|
}[props.mode];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -136,7 +136,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.container-appearance {
|
.container-appearance {
|
||||||
width: 400px;
|
width: 600px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|
||||||
input[type='radio'] {
|
input[type='radio'] {
|
||||||
|
@ -156,7 +156,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.appearance-mode-switch {
|
.appearance-mode-switch {
|
||||||
max-width: 400px;
|
max-width: 600px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
|
||||||
.appearance-mode {
|
.appearance-mode {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { ComponentRegistry, WorkspaceStore } from 'mailspring-exports';
|
||||||
|
|
||||||
import ThreadList from './thread-list';
|
import ThreadList from './thread-list';
|
||||||
import ThreadListToolbar from './thread-list-toolbar';
|
import ThreadListToolbar from './thread-list-toolbar';
|
||||||
|
import ThreadListVertical from './thread-list-vertical';
|
||||||
import ThreadListEmptyFolderBar from './thread-list-empty-folder-bar';
|
import ThreadListEmptyFolderBar from './thread-list-empty-folder-bar';
|
||||||
import MessageListToolbar from './message-list-toolbar';
|
import MessageListToolbar from './message-list-toolbar';
|
||||||
import SelectedItemsStack from './selected-items-stack';
|
import SelectedItemsStack from './selected-items-stack';
|
||||||
|
@ -15,6 +16,12 @@ export function activate() {
|
||||||
|
|
||||||
ComponentRegistry.register(ThreadList, {
|
ComponentRegistry.register(ThreadList, {
|
||||||
location: WorkspaceStore.Location.ThreadList,
|
location: WorkspaceStore.Location.ThreadList,
|
||||||
|
modes: ['split', 'list'],
|
||||||
|
});
|
||||||
|
|
||||||
|
ComponentRegistry.register(ThreadListVertical, {
|
||||||
|
location: WorkspaceStore.Location.ThreadList,
|
||||||
|
modes: ['splitVertical'],
|
||||||
});
|
});
|
||||||
|
|
||||||
ComponentRegistry.register(SelectedItemsStack, {
|
ComponentRegistry.register(SelectedItemsStack, {
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { InjectedComponentSet } from 'mailspring-component-kit';
|
||||||
|
import { WorkspaceStore } from 'mailspring-exports';
|
||||||
|
import { ResizableRegion, ResizableHandle } from '../../../src/components/resizable-region';
|
||||||
|
|
||||||
|
class ThreadListVertical extends React.Component<{}, { style: string; syncing: boolean }> {
|
||||||
|
static displayName = 'ThreadListVertical';
|
||||||
|
static containerRequired = false;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const minHeight = 100;
|
||||||
|
const initialHeight = AppEnv.getThreadListVerticalHeight() || 400;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ResizableRegion
|
||||||
|
minHeight={minHeight}
|
||||||
|
initialHeight={initialHeight}
|
||||||
|
handle={ResizableHandle.Bottom}
|
||||||
|
onResize={h => this._onResize(h)}
|
||||||
|
>
|
||||||
|
<InjectedComponentSet
|
||||||
|
matching={{ location: WorkspaceStore.Location.ThreadList, modes: ['split'] }}
|
||||||
|
/>
|
||||||
|
</ResizableRegion>
|
||||||
|
<ResizableRegion>
|
||||||
|
<div style={{ height: '100%', width: '100%', borderTop: '0.5px solid #dddddd' }}>
|
||||||
|
<div className="sheet-toolbar" style={{ borderBottom: '0' }}>
|
||||||
|
<InjectedComponentSet
|
||||||
|
matching={{ location: WorkspaceStore.Location.MessageList.Toolbar, modes: ['split'] }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<InjectedComponentSet
|
||||||
|
matching={{ location: WorkspaceStore.Location.MessageList, modes: ['split'] }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ResizableRegion>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onResize = (height) => {
|
||||||
|
AppEnv.storeThreadListVerticalHeight(height);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ThreadListVertical;
|
|
@ -508,6 +508,8 @@
|
||||||
"Reading": "Lesen",
|
"Reading": "Lesen",
|
||||||
"Reading Pane Off": "Lesefenster aus",
|
"Reading Pane Off": "Lesefenster aus",
|
||||||
"Reading Pane On": "Lesefenster ein",
|
"Reading Pane On": "Lesefenster ein",
|
||||||
|
"Horizontal Reading Pane": "Horizontales Lesefenster",
|
||||||
|
"Vertical Reading Pane": "Vertikales Lesefenster",
|
||||||
"Rebuild": "Wiederherstellen",
|
"Rebuild": "Wiederherstellen",
|
||||||
"Rebuild Cache...": "Cache neu erstellen...",
|
"Rebuild Cache...": "Cache neu erstellen...",
|
||||||
"Recipient": "Empfänger:",
|
"Recipient": "Empfänger:",
|
||||||
|
@ -776,6 +778,7 @@
|
||||||
"Twitter Handle": "Twitter Handle",
|
"Twitter Handle": "Twitter Handle",
|
||||||
"Twitter Profile Image": "Twitter Profilbild",
|
"Twitter Profile Image": "Twitter Profilbild",
|
||||||
"Two Panel": "Zwei Panel",
|
"Two Panel": "Zwei Panel",
|
||||||
|
"Two Panel Vertical": "Zwei vertikale Panel",
|
||||||
"Uhoh - that's a pro feature!": "Uhoh - das ist ein Pro-Feature!",
|
"Uhoh - that's a pro feature!": "Uhoh - das ist ein Pro-Feature!",
|
||||||
"Unable to Add Account": "Account kann nicht hinzugefügt werden",
|
"Unable to Add Account": "Account kann nicht hinzugefügt werden",
|
||||||
"Unable to Start Local Server": "Der lokale Server konnte nicht gestartet werden",
|
"Unable to Start Local Server": "Der lokale Server konnte nicht gestartet werden",
|
||||||
|
|
|
@ -97,28 +97,42 @@ module.exports = {
|
||||||
{
|
{
|
||||||
label: localized('Reading Pane Off'),
|
label: localized('Reading Pane Off'),
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
command: 'navigation:select-split-mode',
|
command: 'navigation:list-mode-off',
|
||||||
checked: true,
|
|
||||||
hideWhenDisabled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: localized('Reading Pane On'),
|
|
||||||
type: 'radio',
|
|
||||||
command: 'navigation:select-split-mode',
|
|
||||||
checked: false,
|
checked: false,
|
||||||
hideWhenDisabled: true,
|
hideWhenDisabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: localized('Reading Pane Off'),
|
label: localized('Reading Pane Off'),
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
command: 'navigation:select-list-mode',
|
command: 'navigation:list-mode-on',
|
||||||
|
checked: true,
|
||||||
|
hideWhenDisabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: localized('Horizontal Reading Pane'),
|
||||||
|
type: 'radio',
|
||||||
|
command: 'navigation:split-mode-off',
|
||||||
checked: false,
|
checked: false,
|
||||||
hideWhenDisabled: true,
|
hideWhenDisabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: localized('Reading Pane On'),
|
label: localized('Horizontal Reading Pane'),
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
command: 'navigation:select-list-mode',
|
command: 'navigation:split-mode-on',
|
||||||
|
checked: true,
|
||||||
|
hideWhenDisabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: localized('Vertical Reading Pane'),
|
||||||
|
type: 'radio',
|
||||||
|
command: 'navigation:splitVertical-mode-off',
|
||||||
|
checked: false,
|
||||||
|
hideWhenDisabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: localized('Vertical Reading Pane'),
|
||||||
|
type: 'radio',
|
||||||
|
command: 'navigation:splitVertical-mode-on',
|
||||||
checked: true,
|
checked: true,
|
||||||
hideWhenDisabled: true,
|
hideWhenDisabled: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -69,28 +69,42 @@ module.exports = {
|
||||||
{
|
{
|
||||||
label: localized('Reading Pane Off'),
|
label: localized('Reading Pane Off'),
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
command: 'navigation:select-split-mode',
|
command: 'navigation:list-mode-off',
|
||||||
checked: true,
|
|
||||||
hideWhenDisabled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: localized('Reading Pane On'),
|
|
||||||
type: 'radio',
|
|
||||||
command: 'navigation:select-split-mode',
|
|
||||||
checked: false,
|
checked: false,
|
||||||
hideWhenDisabled: true,
|
hideWhenDisabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: localized('Reading Pane Off'),
|
label: localized('Reading Pane Off'),
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
command: 'navigation:select-list-mode',
|
command: 'navigation:list-mode-on',
|
||||||
|
checked: true,
|
||||||
|
hideWhenDisabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: localized('Horizontal Reading Pane'),
|
||||||
|
type: 'radio',
|
||||||
|
command: 'navigation:split-mode-off',
|
||||||
checked: false,
|
checked: false,
|
||||||
hideWhenDisabled: true,
|
hideWhenDisabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: localized('Reading Pane On'),
|
label: localized('Horizontal Reading Pane'),
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
command: 'navigation:select-list-mode',
|
command: 'navigation:split-mode-on',
|
||||||
|
checked: true,
|
||||||
|
hideWhenDisabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: localized('Vertical Reading Pane'),
|
||||||
|
type: 'radio',
|
||||||
|
command: 'navigation:splitVertical-mode-off',
|
||||||
|
checked: false,
|
||||||
|
hideWhenDisabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: localized('Vertical Reading Pane'),
|
||||||
|
type: 'radio',
|
||||||
|
command: 'navigation:splitVertical-mode-on',
|
||||||
checked: true,
|
checked: true,
|
||||||
hideWhenDisabled: true,
|
hideWhenDisabled: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -44,28 +44,42 @@ module.exports = {
|
||||||
{
|
{
|
||||||
label: localized('Reading Pane Off'),
|
label: localized('Reading Pane Off'),
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
command: 'navigation:select-split-mode',
|
command: 'navigation:list-mode-off',
|
||||||
checked: true,
|
|
||||||
hideWhenDisabled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: localized('Reading Pane On'),
|
|
||||||
type: 'radio',
|
|
||||||
command: 'navigation:select-split-mode',
|
|
||||||
checked: false,
|
checked: false,
|
||||||
hideWhenDisabled: true,
|
hideWhenDisabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: localized('Reading Pane Off'),
|
label: localized('Reading Pane Off'),
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
command: 'navigation:select-list-mode',
|
command: 'navigation:list-mode-on',
|
||||||
|
checked: true,
|
||||||
|
hideWhenDisabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: localized('Horizontal Reading Pane'),
|
||||||
|
type: 'radio',
|
||||||
|
command: 'navigation:split-mode-off',
|
||||||
checked: false,
|
checked: false,
|
||||||
hideWhenDisabled: true,
|
hideWhenDisabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: localized('Reading Pane On'),
|
label: localized('Horizontal Reading Pane'),
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
command: 'navigation:select-list-mode',
|
command: 'navigation:split-mode-on',
|
||||||
|
checked: true,
|
||||||
|
hideWhenDisabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: localized('Vertical Reading Pane'),
|
||||||
|
type: 'radio',
|
||||||
|
command: 'navigation:splitVertical-mode-off',
|
||||||
|
checked: false,
|
||||||
|
hideWhenDisabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: localized('Vertical Reading Pane'),
|
||||||
|
type: 'radio',
|
||||||
|
command: 'navigation:splitVertical-mode-on',
|
||||||
checked: true,
|
checked: true,
|
||||||
hideWhenDisabled: true,
|
hideWhenDisabled: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -593,6 +593,14 @@ export default class AppEnvConstructor {
|
||||||
return this.savedState.columnWidths[id];
|
return this.savedState.columnWidths[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
storeThreadListVerticalHeight(height) {
|
||||||
|
this.savedState.threadListVerticalHeight = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
getThreadListVerticalHeight() {
|
||||||
|
return this.savedState.threadListVerticalHeight;
|
||||||
|
}
|
||||||
|
|
||||||
async startWindow() {
|
async startWindow() {
|
||||||
const { windowType } = this.getLoadSettings();
|
const { windowType } = this.getLoadSettings();
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { PropTypes, Utils } from 'mailspring-exports';
|
import { PropTypes, Utils } from 'mailspring-exports';
|
||||||
|
|
||||||
const ResizableHandle: { [side: string]: IResizeHandle } = {
|
export const ResizableHandle: { [side: string]: IResizeHandle } = {
|
||||||
Top: {
|
Top: {
|
||||||
axis: 'vertical',
|
axis: 'vertical',
|
||||||
className: 'flexbox-handle-vertical flexbox-handle-top',
|
className: 'flexbox-handle-vertical flexbox-handle-top',
|
||||||
|
|
|
@ -30,7 +30,7 @@ export default {
|
||||||
mode: {
|
mode: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: 'list',
|
default: 'list',
|
||||||
enum: ['split', 'list'],
|
enum: ['split', 'list', 'splitVertical'],
|
||||||
},
|
},
|
||||||
systemTray: {
|
systemTray: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
|
|
|
@ -119,6 +119,7 @@ class WorkspaceStore extends MailspringStore {
|
||||||
{
|
{
|
||||||
list: ['RootSidebar', 'ThreadList'],
|
list: ['RootSidebar', 'ThreadList'],
|
||||||
split: ['RootSidebar', 'ThreadList', 'MessageList', 'MessageListSidebar'],
|
split: ['RootSidebar', 'ThreadList', 'MessageList', 'MessageListSidebar'],
|
||||||
|
splitVertical: ['RootSidebar', 'ThreadList', 'MessageListSidebar'],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.defineSheet('Thread', {}, { list: ['MessageList', 'MessageListSidebar'] });
|
this.defineSheet('Thread', {}, { list: ['MessageList', 'MessageListSidebar'] });
|
||||||
|
@ -222,8 +223,14 @@ class WorkspaceStore extends MailspringStore {
|
||||||
'core:pop-sheet': () => this.popSheet(),
|
'core:pop-sheet': () => this.popSheet(),
|
||||||
},
|
},
|
||||||
this._preferredLayoutMode === 'list'
|
this._preferredLayoutMode === 'list'
|
||||||
? { 'navigation:select-split-mode': () => this._onSelectLayoutMode('split') }
|
? { 'navigation:list-mode-on': () => this._onSelectLayoutMode('list') }
|
||||||
: { 'navigation:select-list-mode': () => this._onSelectLayoutMode('list') }
|
: { 'navigation:list-mode-off': () => this._onSelectLayoutMode('list') },
|
||||||
|
this._preferredLayoutMode === 'split'
|
||||||
|
? { 'navigation:split-mode-on': () => this._onSelectLayoutMode('split') }
|
||||||
|
: { 'navigation:split-mode-off': () => this._onSelectLayoutMode('split') },
|
||||||
|
this._preferredLayoutMode === 'splitVertical'
|
||||||
|
? { 'navigation:splitVertical-mode-on': () => this._onSelectLayoutMode('splitVertical') }
|
||||||
|
: { 'navigation:splitVertical-mode-off': () => this._onSelectLayoutMode('splitVertical') }
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
Loading…
Add table
Reference in a new issue