Merge pull request #680 from ONLYOFFICE/feature/smart-banner

Feature/smart banner
This commit is contained in:
Alexey Safronov 2022-05-30 16:38:14 +03:00 committed by GitHub
commit 80f6d8e8b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 418 additions and 4 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

View File

@ -30,6 +30,15 @@
Learn how to configure a non-root public URL by running `npm run build`.
-->
<meta name="react-apple-itunes-app" content="app-id=944896972" />
<meta
name="react-google-play-app"
content="app-id=com.onlyoffice.documents"
/>
<link rel="apple-touch-icon" href="images/logo/favicon_general.ico" />
<link rel="android-touch-icon" href="images/logo/favicon_general.ico" />
<%= htmlWebpackPlugin.options.custom %>
<style type="text/css">

View File

@ -43,6 +43,7 @@
"dependencies": {
"firebase": "^8.10.0",
"react-markdown": "^7.0.1",
"react-smartbanner": "^5.1.4",
"react-string-format": "^0.1.4"
},
"devDependencies": {

View File

@ -29,6 +29,16 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<meta name="react-apple-itunes-app" content="app-id=944896972" />
<meta
name="react-google-play-app"
content="app-id=com.onlyoffice.documents"
/>
<link rel="apple-touch-icon" href="images/logo/favicon_general.ico" />
<link rel="android-touch-icon" href="images/logo/favicon_general.ico" />
<%= htmlWebpackPlugin.options.custom %>
<style type="text/css">

View File

@ -0,0 +1,6 @@
{
"AppName": "ONLYOFFICE Documents",
"Price": "Free",
"AppStore": "On the App Store",
"GooglePlay": "In Google Play"
}

View File

@ -1,4 +1,4 @@
import React, { useEffect } from "react";
import React, { useEffect, useState } from "react";
import { Router, Switch, Route, Redirect } from "react-router-dom";
import { inject, observer } from "mobx-react";
import NavMenu from "./components/NavMenu";
@ -23,6 +23,7 @@ import System from "./components/System";
import { AppServerConfig } from "@appserver/common/constants";
import Snackbar from "@appserver/components/snackbar";
import moment from "moment";
import ReactSmartBanner from "./components/SmartBanner";
const { proxyURL } = AppServerConfig;
const homepage = config.homepage;
@ -197,8 +198,11 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
roomsMode,
setSnackbarExist,
userTheme,
currentProductId,
} = rest;
const [isDocuments, setIsDocuments] = useState(false);
useEffect(() => {
try {
if (!window.AppServer) {
@ -234,7 +238,7 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
});
}, [socketHelper]);
const { t } = useTranslation("Common");
const { t, ready } = useTranslation(["Common", "SmartBanner"]);
let snackTimer = null;
let fbInterval = null;
@ -425,6 +429,14 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
if (userTheme) setTheme(userTheme);
}, [userTheme]);
useEffect(() => {
if (window.location.pathname.toLowerCase().includes("files")) {
setIsDocuments(true);
} else {
setIsDocuments(false);
}
}, [currentProductId]);
const pathname = window.location.pathname.toLowerCase();
const isEditor = pathname.indexOf("doceditor") !== -1;
@ -510,6 +522,7 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
<Layout>
<Router history={history}>
<>
{isDocuments ? <ReactSmartBanner t={t} ready={ready} /> : <></>}
{isEditor ? <></> : <NavMenu />}
<ScrollToTop />
<Main isDesktop={isDesktop}>
@ -572,6 +585,7 @@ const ShellWrapper = inject(({ auth, backup }) => {
setSnackbarExist,
socketHelper,
setTheme,
currentProductId,
} = settingsStore;
const { setPreparationPortalDialogVisible } = backup;
@ -600,6 +614,7 @@ const ShellWrapper = inject(({ auth, backup }) => {
roomsMode,
setSnackbarExist,
userTheme: auth?.userStore?.user?.theme,
currentProductId,
};
})(observer(Shell));

View File

@ -0,0 +1,77 @@
import React, { useState, useEffect } from "react";
import styled from "styled-components";
import { isMobile, isIOS } from "react-device-detect";
import SmartBanner from "react-smartbanner";
import "./main.css";
const Wrapper = styled.div`
padding-bottom: 80px;
`;
const ReactSmartBanner = (props) => {
const { t, ready } = props;
const [isVisible, setIsVisible] = useState(true);
const force = isIOS ? "ios" : "android";
const getCookie = (name) => {
let matches = document.cookie.match(
new RegExp(
"(?:^|; )" +
name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, "\\$1") +
"=([^;]*)"
)
);
return matches ? decodeURIComponent(matches[1]) : undefined;
};
const hideBanner = () => {
setIsVisible(false);
};
useEffect(() => {
const cookieClosed = getCookie("smartbanner-closed");
const cookieInstalled = getCookie("smartbanner-installed");
if (cookieClosed || cookieInstalled) hideBanner();
}, []);
const storeText = {
ios: t("SmartBanner:AppStore"),
android: t("SmartBanner:GooglePlay"),
windows: "",
kindle: "",
};
const priceText = {
ios: t("SmartBanner:Price"),
android: t("SmartBanner:Price"),
windows: "",
kindle: "",
};
const appMeta = {
ios: "react-apple-itunes-app",
android: "react-google-play-app",
windows: "msApplication-ID",
kindle: "kindle-fire-app",
};
return isMobile && isVisible && ready ? (
<Wrapper>
<SmartBanner
title={t("SmartBanner:AppName")}
author="Ascensio System SIA"
button={t("Common:View")}
force={force}
onClose={hideBanner}
onInstall={hideBanner}
storeText={storeText}
price={priceText}
appMeta={appMeta}
/>
</Wrapper>
) : (
<></>
);
};
export default ReactSmartBanner;

View File

@ -0,0 +1,276 @@
.smartbanner-show.smartbanner-margin-top {
margin-top: 0px;
}
.smartbanner-show.smartbanner-margin-bottom {
margin-bottom: 0px;
}
.smartbanner-show .smartbanner {
display: block;
}
.smartbanner {
left: 0;
display: none;
width: 100%;
height: 80px;
line-height: 80px;
font-family: Helvetica Neue, sans-serif;
background: #f4f4f4;
z-index: 9998;
-webkit-font-smoothing: antialiased;
overflow: hidden;
-webkit-text-size-adjust: none;
}
.smartbanner-top {
position: absolute;
top: 0;
}
.smartbanner-bottom {
position: fixed;
bottom: 0;
}
.smartbanner-container {
margin: 0 auto;
padding: 0 5px;
}
.smartbanner-close {
display: inline-block;
vertical-align: middle;
margin: 0 5px 0 0;
font-family: ArialRoundedMTBold, Arial;
font-size: 20px;
text-align: center;
color: #888;
text-decoration: none;
border: 0;
border-radius: 14px;
padding: 0 0 1px;
background-color: transparent;
-webkit-font-smoothing: subpixel-antialiased;
}
.smartbanner-close:active,
.smartbanner-close:hover {
color: #aaa;
}
.smartbanner-icon {
width: 57px;
height: 57px;
margin-right: 12px;
background-size: cover;
border-radius: 10px;
}
.smartbanner-icon,
.smartbanner-info {
display: inline-block;
vertical-align: middle;
}
.smartbanner-info {
white-space: normal;
width: calc(99% - 201px);
font-size: 11px;
line-height: 1.2em;
font-weight: 700;
}
.smartbanner-wrapper {
max-width: 110px;
display: inline-block;
text-align: right;
width: 100%;
}
.smartbanner-title {
font-size: 13px;
line-height: 18px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.smartbanner-description {
max-height: 40px;
overflow: hidden;
}
.smartbanner-author {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.smartbanner-author:empty + .smartbanner-description {
max-height: 50px;
}
.smartbanner-button {
margin: auto 0;
height: 24px;
font-size: 14px;
line-height: 24px;
text-align: center;
font-weight: 700;
color: #6a6a6a;
text-transform: uppercase;
text-decoration: none;
display: inline-block;
text-shadow: 0 1px 0 hsla(0, 0%, 100%, 0.8);
}
.smartbanner-button:active,
.smartbanner-button:hover {
color: #aaa;
}
.smartbanner-ios {
background: #f2f2f2;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
line-height: 80px;
}
.smartbanner-ios .smartbanner-close {
border: 0;
width: 18px;
height: 18px;
line-height: 18px;
font-family: Arial;
color: #888;
text-shadow: 0 1px 0 #fff;
-webkit-font-smoothing: none;
}
.smartbanner-ios .smartbanner-close:active,
.smartbanner-ios .smartbanner-close:hover {
color: #888;
}
.smartbanner-ios .smartbanner-icon {
background-size: cover;
}
.smartbanner-ios .smartbanner-info {
color: #6a6a6a;
text-shadow: 0 1px 0 hsla(0, 0%, 100%, 0.8);
font-weight: 300;
}
.smartbanner-ios .smartbanner-title {
color: #4d4d4d;
font-weight: 500;
}
.smartbanner-ios .smartbanner-button {
padding: 0 10px;
font-size: 15px;
min-width: 10%;
font-weight: 400;
color: #0c71fd;
}
.smartbanner-ios .smartbanner-button:active,
.smartbanner-ios .smartbanner-button:hover {
background: #f2f2f2;
}
.smartbanner-android {
background: #3d3d3d
url("data:image/gif;base64,R0lGODlhCAAIAIABAFVVVf///yH5BAEHAAEALAAAAAAIAAgAAAINRG4XudroGJBRsYcxKAA7");
box-shadow: inset 0 4px 0 #88b131;
line-height: 82px;
}
.smartbanner-android .smartbanner-close {
border: 0;
max-width: 17px;
width: 100%;
height: 17px;
line-height: 17px;
margin-right: 7px;
color: #b1b1b3;
background: #1c1e21;
text-shadow: 0 1px 1px #000;
text-decoration: none;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.8),
0 1px 1px hsla(0, 0%, 100%, 0.3);
cursor: pointer;
}
.smartbanner-android .smartbanner-close:active,
.smartbanner-android .smartbanner-close:hover {
color: #eee;
}
.smartbanner-android .smartbanner-icon {
background-color: transparent;
box-shadow: none;
}
.smartbanner-android .smartbanner-info {
color: #ccc;
text-shadow: 0 1px 2px #000;
}
.smartbanner-android .smartbanner-title {
color: #fff;
font-weight: 700;
}
.smartbanner-android .smartbanner-button {
min-width: 12%;
color: #d1d1d1;
font-weight: 700;
padding: 0;
background: none;
border-radius: 0;
box-shadow: 0 0 0 1px #333, 0 0 0 2px #dddcdc;
}
.smartbanner-android .smartbanner-button:active,
.smartbanner-android .smartbanner-button:hover {
background: none;
}
.smartbanner-android .smartbanner-button-text {
text-align: center;
display: block;
padding: 0 10px;
background: #42b6c9;
background: linear-gradient(180deg, #42b6c9, #39a9bb);
text-transform: none;
text-shadow: none;
box-shadow: none;
}
.smartbanner-android .smartbanner-button-text:active,
.smartbanner-android .smartbanner-button-text:hover {
background: #2ac7e1;
}
.smartbanner-kindle,
.smartbanner-windows {
background: #f4f4f4;
background: linear-gradient(180deg, #f4f4f4, #cdcdcd);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
line-height: 80px;
}
.smartbanner-kindle .smartbanner-close,
.smartbanner-windows .smartbanner-close {
border: 0;
width: 18px;
height: 18px;
line-height: 18px;
color: #888;
text-shadow: 0 1px 0 #fff;
}
.smartbanner-kindle .smartbanner-close:active,
.smartbanner-kindle .smartbanner-close:hover,
.smartbanner-windows .smartbanner-close:active,
.smartbanner-windows .smartbanner-close:hover {
color: #aaa;
}
.smartbanner-kindle .smartbanner-icon,
.smartbanner-windows .smartbanner-icon {
background: rgba(0, 0, 0, 0.6);
background-size: cover;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
.smartbanner-kindle .smartbanner-info,
.smartbanner-windows .smartbanner-info {
color: #6a6a6a;
text-shadow: 0 1px 0 hsla(0, 0%, 100%, 0.8);
}
.smartbanner-kindle .smartbanner-title,
.smartbanner-windows .smartbanner-title {
color: #4d4d4d;
font-weight: 700;
}
.smartbanner-kindle .smartbanner-button,
.smartbanner-windows .smartbanner-button {
padding: 0 10px;
min-width: 10%;
color: #6a6a6a;
background: #efefef;
background: linear-gradient(180deg, #efefef, #dcdcdc);
border-radius: 3px;
box-shadow: inset 0 0 0 1px #bfbfbf, 0 1px 0 hsla(0, 0%, 100%, 0.6),
inset 0 2px 0 hsla(0, 0%, 100%, 0.7);
}
.smartbanner-kindle .smartbanner-button:active,
.smartbanner-kindle .smartbanner-button:hover,
.smartbanner-windows .smartbanner-button:active,
.smartbanner-windows .smartbanner-button:hover {
background: #dcdcdc;
background: linear-gradient(180deg, #dcdcdc, #efefef);
}

View File

@ -7745,6 +7745,11 @@ convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.5.0,
dependencies:
safe-buffer "~5.1.1"
cookie-cutter@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/cookie-cutter/-/cookie-cutter-0.1.1.tgz#4503fd9dd35ec7000ce945ef9cca31d75fe9ccea"
integrity sha1-RQP9ndNexwAM6UXvnMox11/pzOo=
cookie-signature@1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
@ -7755,6 +7760,11 @@ cookie@0.4.2, cookie@~0.4.1:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
cookies-js@^1.2.1:
version "1.2.3"
resolved "https://registry.yarnpkg.com/cookies-js/-/cookies-js-1.2.3.tgz#03315049e7c52bee3f73186a69167eab0ddb2d31"
integrity sha1-AzFQSefFK+4/cxhqaRZ+qw3bLTE=
copy-concurrently@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
@ -16216,7 +16226,7 @@ prop-types-exact@^1.2.0:
object.assign "^4.1.0"
reflect.ownkeys "^0.2.0"
prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@ -16948,6 +16958,16 @@ react-sizeme@^3.0.1:
shallowequal "^1.1.0"
throttle-debounce "^3.0.1"
react-smartbanner@^5.1.4:
version "5.1.4"
resolved "https://registry.yarnpkg.com/react-smartbanner/-/react-smartbanner-5.1.4.tgz#c20e6e68385f25d86890b3d82a0255a27093175f"
integrity sha512-UQ+FAsV/RYTzMw1Ok02OOxJryU4YwR0f/ckeHw/4JZi+UunQ79dj1+HE64nWurwIaa/dS9IXb0AyPXeAObXxXA==
dependencies:
cookie-cutter "^0.1.1"
cookies-js "^1.2.1"
prop-types "^15.5.8"
ua-parser-js "^0.7.9"
react-string-format@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/react-string-format/-/react-string-format-0.1.4.tgz#2b56dbabff2625cd4e17541d1a54cd2c5cc426cc"
@ -19806,7 +19826,7 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
ua-parser-js@^0.7.24:
ua-parser-js@^0.7.24, ua-parser-js@^0.7.9:
version "0.7.31"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6"
integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==