Compare commits

...

5 Commits

Author SHA1 Message Date
Tom Moor 2aaad03270 refactor 2020-08-20 19:05:48 -07:00
Tom Moor 9252683260 fix: SocketPresence account for socket changing 2020-08-20 00:06:51 -07:00
Tom Moor f5748eb5e7 check connection on page visibility change 2020-08-19 22:51:18 -07:00
Tom Moor 0555fd2caa pref: JS bundling improvements (#1461)
* perf: Split only initial vendors
2020-08-17 22:09:12 -07:00
Tom Moor d885252fb0 fix: Mobile style fixes and improvements (#1459)
* fixes #1457 – check for matchMedia function before using it

* fixes: Depth issues
closes #1458

* fixes: Long breadcrumbs cause horizontal overflow

* fix: Improve tabs and overflow on mobile
2020-08-17 00:08:22 -07:00
17 changed files with 130 additions and 48 deletions
+1
View File
@@ -9,6 +9,7 @@ type Props = {
const Container = styled.div`
width: 100%;
max-width: 100vw;
padding: 60px 20px;
${breakpoint("tablet")`
@@ -169,6 +169,7 @@ const DocumentLink = styled(Link)`
border-radius: 8px;
max-height: 50vh;
min-width: 100%;
max-width: calc(100vw - 40px);
overflow: hidden;
position: relative;
+2 -2
View File
@@ -232,7 +232,7 @@ const Label = styled(Flex).attrs({
justify: "center",
align: "center",
})`
z-index: 1000;
z-index: ${(props) => props.theme.depths.menu};
cursor: pointer;
`;
@@ -244,7 +244,7 @@ const Position = styled.div`
${({ top }) => (top !== undefined ? `top: ${top}px` : "")};
${({ bottom }) => (bottom !== undefined ? `bottom: ${bottom}px` : "")};
max-height: 75%;
z-index: 1000;
z-index: ${(props) => props.theme.depths.menu};
transform: ${(props) =>
props.position === "center" ? "translateX(-50%)" : "initial"};
pointer-events: none;
@@ -18,7 +18,7 @@ const loadingFrame = keyframes`
const Container = styled.div`
position: fixed;
top: 0;
z-index: 9999;
z-index: ${(props) => props.theme.depths.loadingIndicatorBar};
background-color: #03a9f4;
width: 100%;
+2 -2
View File
@@ -23,7 +23,7 @@ const GlobalStyles = createGlobalStyle`
.ReactModal__Overlay {
background-color: ${(props) =>
transparentize(0.25, props.theme.background)} !important;
z-index: 100;
z-index: ${(props) => props.theme.depths.modalOverlay};
}
${breakpoint("tablet")`
@@ -103,7 +103,7 @@ const StyledModal = styled(ReactModal)`
left: 0;
bottom: 0;
right: 0;
z-index: 100;
z-index: ${(props) => props.theme.depths.modal};
display: flex;
justify-content: center;
align-items: flex-start;
+1 -1
View File
@@ -22,7 +22,7 @@ const StyledPopover = styled(BoundlessPopover)`
position: absolute;
top: 0;
left: 0;
z-index: 9999;
z-index: ${(props) => props.theme.depths.popover};
svg {
height: 16px;
+1 -1
View File
@@ -71,7 +71,7 @@ const Container = styled(Flex)`
transition: left 100ms ease-out,
${(props) => props.theme.backgroundTransition};
margin-left: ${(props) => (props.mobileSidebarVisible ? 0 : "-100%")};
z-index: 1000;
z-index: ${(props) => props.theme.depths.sidebar};
@media print {
display: none;
+30 -10
View File
@@ -3,7 +3,7 @@ import { find } from "lodash";
import { observable } from "mobx";
import { inject, observer } from "mobx-react";
import * as React from "react";
import io from "socket.io-client";
import io, { Socket } from "socket.io-client";
import AuthStore from "stores/AuthStore";
import CollectionsStore from "stores/CollectionsStore";
import DocumentPresenceStore from "stores/DocumentPresenceStore";
@@ -13,6 +13,7 @@ import MembershipsStore from "stores/MembershipsStore";
import PoliciesStore from "stores/PoliciesStore";
import UiStore from "stores/UiStore";
import ViewsStore from "stores/ViewsStore";
import { getVisibilityListener, getPageVisible } from "utils/pageVisibility";
export const SocketContext: any = React.createContext();
@@ -31,9 +32,35 @@ type Props = {
@observer
class SocketProvider extends React.Component<Props> {
@observable socket;
@observable socket: Socket;
componentDidMount() {
this.createConnection();
document.addEventListener(getVisibilityListener(), this.checkConnection);
}
componentWillUnmount() {
if (this.socket) {
this.socket.authenticated = false;
this.socket.disconnect();
}
document.removeEventListener(getVisibilityListener(), this.checkConnection);
}
checkConnection = () => {
if (this.socket && this.socket.disconnected && getPageVisible()) {
// null-ifying this reference is important, do not remove. Without it
// references to old sockets are potentially held in context
this.socket.close();
this.socket = null;
this.createConnection();
}
};
createConnection = () => {
this.socket = io(window.location.origin, {
path: "/realtime",
transports: ["websocket"],
@@ -264,14 +291,7 @@ class SocketProvider extends React.Component<Props> {
this.socket.on("user.presence", (event) => {
presence.touch(event.documentId, event.userId, event.isEditing);
});
}
componentWillUnmount() {
if (this.socket) {
this.socket.disconnect();
this.socket.authenticated = false;
}
}
};
render() {
return (
+2
View File
@@ -6,6 +6,8 @@ const Tabs = styled.nav`
border-bottom: 1px solid ${(props) => props.theme.divider};
margin-top: 22px;
margin-bottom: 12px;
overflow-y: auto;
white-space: nowrap;
`;
export const Separator = styled.span`
+1 -1
View File
@@ -34,7 +34,7 @@ const List = styled.ol`
list-style: none;
margin: 0;
padding: 0;
z-index: 1000;
z-index: ${(props) => props.theme.depths.toasts};
`;
export default inject("ui")(Toasts);
@@ -41,7 +41,7 @@ export default class SocketPresence extends React.Component<Props> {
}
setupOnce = () => {
if (this.context && !this.previousContext) {
if (this.context && this.context !== this.previousContext) {
this.previousContext = this.context;
if (this.context.authenticated) {
+7
View File
@@ -12,6 +12,7 @@ import { withRouter, Link } from "react-router-dom";
import type { RouterHistory, Match } from "react-router-dom";
import { Waypoint } from "react-waypoint";
import styled from "styled-components";
import breakpoint from "styled-components-breakpoint";
import { DEFAULT_PAGINATION_LIMIT } from "stores/BaseStore";
import DocumentsStore from "stores/DocumentsStore";
@@ -387,6 +388,12 @@ const Filters = styled(Flex)`
margin-bottom: 12px;
opacity: 0.85;
transition: opacity 100ms ease-in-out;
overflow-y: auto;
padding: 8px 0;
${breakpoint("tablet")`
padding: 0;
`};
&:hover {
opacity: 1;
+11 -9
View File
@@ -32,16 +32,18 @@ class UiStore {
}
// system theme listeners
const colorSchemeQueryList = window.matchMedia(
"(prefers-color-scheme: dark)"
);
if (window.matchMedia) {
const colorSchemeQueryList = window.matchMedia(
"(prefers-color-scheme: dark)"
);
const setSystemTheme = (event) => {
this.systemTheme = event.matches ? "dark" : "light";
};
setSystemTheme(colorSchemeQueryList);
if (colorSchemeQueryList.addListener) {
colorSchemeQueryList.addListener(setSystemTheme);
const setSystemTheme = (event) => {
this.systemTheme = event.matches ? "dark" : "light";
};
setSystemTheme(colorSchemeQueryList);
if (colorSchemeQueryList.addListener) {
colorSchemeQueryList.addListener(setSystemTheme);
}
}
// persisted keys
+25
View File
@@ -0,0 +1,25 @@
// @flow
let hidden = "hidden";
let visibilityChange = "visibilitychange";
if ("hidden" in document) {
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if ("mozHidden" in document) {
// Firefox up to v17
hidden = "mozHidden";
visibilityChange = "mozvisibilitychange";
} else if ("webkitHidden" in document) {
// Chrome up to v32, Android up to v4.4, Blackberry up to v10
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
export function getVisibilityListener(): string {
return visibilityChange;
}
export function getPageVisible(): boolean {
// $FlowFixMe
return !document[hidden];
}
+10
View File
@@ -101,6 +101,16 @@ export const base = {
desktop: 1025, // targeting devices that are larger than the iPad (which is 1024px in landscape mode)
desktopLarge: 1600,
},
depths: {
sidebar: 1000,
modalOverlay: 2000,
modal: 3000,
menu: 4000,
toasts: 5000,
loadingIndicatorBar: 6000,
popover: 9000,
},
};
export const light = {
+28 -15
View File
@@ -10,30 +10,30 @@ require('dotenv').config({ silent: true });
module.exports = {
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
filename: '[name].[hash].js',
publicPath: '/static/',
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: [
path.join(__dirname, 'node_modules')
],
include: [
path.join(__dirname, 'app'),
path.join(__dirname, 'shared'),
],
options: {
cacheDirectory: true
}
test: /\.js$/,
loader: 'babel-loader',
exclude: [
path.join(__dirname, 'node_modules')
],
include: [
path.join(__dirname, 'app'),
path.join(__dirname, 'shared'),
],
options: {
cacheDirectory: true
}
},
// inline base64 URLs for <=8k images, direct URLs for the rest
{ test: /\.(png|jpg|svg)$/, loader: 'url-loader' },
{
test: /\.woff$/,
loader: 'url-loader?limit=1&mimetype=application/font-woff&name=public/fonts/[name].[ext]',
test: /\.woff$/,
loader: 'url-loader?limit=1&mimetype=application/font-woff&name=public/fonts/[name].[ext]',
},
{ test: /\.md/, loader: 'raw-loader' },
]
@@ -64,4 +64,17 @@ module.exports = {
stats: {
assets: false,
},
optimization: {
runtimeChunk: 'single',
moduleIds: 'hashed',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'initial',
},
},
},
}
};
+6 -5
View File
@@ -7,17 +7,18 @@ const TerserPlugin = require('terser-webpack-plugin');
commonWebpackConfig = require('./webpack.config');
productionWebpackConfig = Object.assign(commonWebpackConfig, {
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].[contenthash].js',
publicPath: '/static/',
},
cache: true,
mode: "production",
devtool: 'source-map',
entry: ['./app/index'],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.[hash].js',
publicPath: '/static/',
},
stats: "normal",
optimization: {
...commonWebpackConfig.optimization,
minimizer: [
new TerserPlugin({
terserOptions: {