Merge branch 'master' of https://github.com/manojVivek/responsively-app into feature/focus-device

This commit is contained in:
Suresh 2020-06-24 20:55:52 +05:30
commit 0ede51e7a3
30 changed files with 745 additions and 153 deletions

View file

@ -127,6 +127,24 @@
"contributions": [
"code"
]
},
{
"login": "jonathanurias96",
"name": "jonathanurias96",
"avatar_url": "https://avatars2.githubusercontent.com/u/57416786?v=4",
"profile": "https://github.com/jonathanurias96",
"contributions": [
"code"
]
},
{
"login": "falecci",
"name": "Federico Alecci",
"avatar_url": "https://avatars2.githubusercontent.com/u/17703824?v=4",
"profile": "https://falecci.dev",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,

View file

@ -1,6 +1,6 @@
# Responsively App [![Twitter Follow](https://img.shields.io/twitter/follow/ResponsivelyApp?style=social)](https://twitter.com/ResponsivelyApp)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-15-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
[![Gitter chat](https://img.shields.io/gitter/room/badges/shields.svg)](https://gitter.im/responsively-app) [![xscode](https://img.shields.io/badge/Available%20on-xs%3Acode-blue?style=?style=plastic&logo=appveyor&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF////////VXz1bAAAAAJ0Uk5T/wDltzBKAAAAlUlEQVR42uzXSwqAMAwE0Mn9L+3Ggtgkk35QwcnSJo9S+yGwM9DCooCbgn4YrJ4CIPUcQF7/XSBbx2TEz4sAZ2q1RAECBAiYBlCtvwN+KiYAlG7UDGj59MViT9hOwEqAhYCtAsUZvL6I6W8c2wcbd+LIWSCHSTeSAAECngN4xxIDSK9f4B9t377Wd7H5Nt7/Xz8eAgwAvesLRjYYPuUAAAAASUVORK5CYII=)](https://xscode.com/manojvivek/responsively-app) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/manojVivek/responsively-app/issues)
@ -82,6 +82,10 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center"><a href="https://github.com/Kidcredo"><img src="https://avatars0.githubusercontent.com/u/15522605?v=4" width="100px;" alt=""/><br /><sub><b>Ryan Pais</b></sub></a><br /><a href="https://github.com/manojVivek/responsively-app/commits?author=Kidcredo" title="Code">💻</a> <a href="https://github.com/manojVivek/responsively-app/commits?author=Kidcredo" title="Tests">⚠️</a></td>
<td align="center"><a href="https://grafikart.fr"><img src="https://avatars1.githubusercontent.com/u/395137?v=4" width="100px;" alt=""/><br /><sub><b>Jonathan</b></sub></a><br /><a href="https://github.com/manojVivek/responsively-app/commits?author=Grafikart" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/heygema"><img src="https://avatars1.githubusercontent.com/u/10743728?v=4" width="100px;" alt=""/><br /><sub><b>Gema Anggada ✌︎</b></sub></a><br /><a href="https://github.com/manojVivek/responsively-app/commits?author=heygema" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/jonathanurias96"><img src="https://avatars2.githubusercontent.com/u/57416786?v=4" width="100px;" alt=""/><br /><sub><b>jonathanurias96</b></sub></a><br /><a href="https://github.com/manojVivek/responsively-app/commits?author=jonathanurias96" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://falecci.dev"><img src="https://avatars2.githubusercontent.com/u/17703824?v=4" width="100px;" alt=""/><br /><sub><b>Federico Alecci</b></sub></a><br /><a href="https://github.com/manojVivek/responsively-app/commits?author=falecci" title="Code">💻</a></td>
</tr>
</table>

View file

@ -5,7 +5,7 @@ import App from './containers/App';
import Browser from './containers/Browser';
import LeftIconsPaneContainer from './containers/LeftIconsPaneContainer';
import styles from './layout.css';
import StatusBar from './components/StatusBar';
import StatusBarContainer from './containers/StatusBarContainer';
import DevToolResizerContainer from './containers/DevToolResizerContainer';
export default () => (
@ -20,7 +20,7 @@ export default () => (
</Switch>
</div>
</div>
<StatusBar />
<StatusBarContainer />
<DevToolResizerContainer />
</App>
);

View file

@ -2,11 +2,11 @@ export const TOGGLE_BOOKMARK = 'TOGGLE_BOOKMARK';
export const EDIT_BOOKMARK = 'EDIT_BOOKMARK';
// Add or Remove an URL from the bookmark list
export function toggleBookmarkUrl(url, title = null) {
export function toggleBookmarkUrl(url, pageMeta = {}) {
return {
type: TOGGLE_BOOKMARK,
url,
title
title: pageMeta.title,
};
}
@ -16,6 +16,6 @@ export function editBookmark(bookmark, {title, url}) {
type: EDIT_BOOKMARK,
title,
url,
bookmark
}
bookmark,
};
}

View file

@ -22,6 +22,7 @@ import {DEVTOOLS_MODES} from '../constants/previewerLayouts';
import console from 'electron-timber';
export const NEW_ADDRESS = 'NEW_ADDRESS';
export const NEW_PAGE_META_FIELD = 'NEW_PAGE_META_FIELD';
export const NEW_DEV_TOOLS_CONFIG = 'NEW_DEV_TOOLS_CONFIG';
export const NEW_HOMEPAGE = 'NEW_HOMEPAGE';
export const NEW_ZOOM_LEVEL = 'NEW_ZOOM_LEVEL';
@ -47,6 +48,14 @@ export function newAddress(address) {
};
}
export function newPageMetaField(name, value) {
return {
type: NEW_PAGE_META_FIELD,
name,
value,
};
}
export function newWindowSize(size) {
return {
type: NEW_WINDOW_SIZE,
@ -183,6 +192,12 @@ export function onAddressChange(newURL, force) {
};
}
export function onPageMetaFieldUpdate(name, value) {
return (dispatch: Dispatch, getState: RootStateType) => {
dispatch(newPageMetaField(name, value));
};
}
function isHashOnlyChange(newURL, oldURL) {
if (!newURL || !oldURL) {
return false;

View file

@ -0,0 +1,14 @@
// @flow
import {statusBarSettings} from '../settings/statusBarSettings';
export const TOGGLE_STATUS_BAR_VISIBILITY = 'TOGGLE_STATUS_BAR_VISIBILITY';
export function toggleStatusBarVisibility() {
const newVisibility = !statusBarSettings.getVisibility();
statusBarSettings.setVisibility(newVisibility);
return {
type: TOGGLE_STATUS_BAR_VISIBILITY,
visible: newVisibility,
};
}

View file

@ -1,10 +1,9 @@
import {autoUpdater} from 'electron-updater';
import log from 'electron-log';
import {pkg} from './utils/generalUtils';
const EventEmitter = require('events').EventEmitter;
const {EventEmitter} = require('events');
const AppUpdaterState = {
const AppUpdaterStatus = {
Idle: 'idle',
Checking: 'checking',
NoUpdate: 'noUpdate',
@ -12,46 +11,52 @@ const AppUpdaterState = {
Downloaded: 'downloaded',
}
Object.freeze(AppUpdaterState);
Object.freeze(AppUpdaterStatus);
class AppUpdater extends EventEmitter {
state: AppUpdaterState;
status: string;
readyStates: AppUpdaterState[];
timerId = null;
constructor() {
super();
log.transports.file.level = 'info';
autoUpdater.logger = log;
this.state = AppUpdaterState.Idle;
this.readyStates = [AppUpdaterState.Idle, AppUpdaterState.NoUpdate, AppUpdaterState.Downloaded];
this.status = AppUpdaterStatus.Idle;
autoUpdater.on('checking-for-update', () => this.handleStatusChange(AppUpdaterState.Checking));
autoUpdater.on('update-not-available', () => this.handleStatusChange(AppUpdaterState.NoUpdate));
autoUpdater.on('download-progress', () => this.handleStatusChange(AppUpdaterState.Downloading));
autoUpdater.on('update-downloaded', () => this.handleStatusChange(AppUpdaterState.Downloaded));
autoUpdater.on('checking-for-update', () => this.handleStatusChange(AppUpdaterStatus.Checking, false));
autoUpdater.on('update-not-available', () => this.handleStatusChange(AppUpdaterStatus.NoUpdate, true));
autoUpdater.on('download-progress', () => this.handleStatusChange(AppUpdaterStatus.Downloading, false));
autoUpdater.on('update-downloaded', () => this.handleStatusChange(AppUpdaterStatus.Downloaded, true));
}
getCurrentState() {
return this.state;
}
readyToCheck() {
return this.readyStates.includes(this.state);
getCurrentStatus() {
return this.status;
}
checkForUpdatesAndNotify() {
if (this.readyToCheck())
if (this.status === AppUpdaterStatus.Idle)
return autoUpdater.checkForUpdatesAndNotify();
}
handleStatusChange(nextStatus: AppUpdaterState) {
const changed = this.state !== nextStatus;
this.state = nextStatus;
if (changed)
handleStatusChange(nextStatus: string, backToIdle: boolean) {
clearTimeout(this.timerId);
if (this.status !== nextStatus) {
this.status = nextStatus;
this.emit('status-changed', nextStatus);
if (backToIdle) {
this.timerId = setTimeout(() => {
if (this.status !== AppUpdaterStatus.Idle) {
this.status = AppUpdaterStatus.Idle;
this.emit('status-changed', AppUpdaterStatus.Idle);
}
}, 2000);
}
}
}
}
}
const appUpdaterInstance = new AppUpdater();
export { AppUpdaterState, appUpdaterInstance as appUpdater };
export { AppUpdaterStatus, appUpdaterInstance as appUpdater };

View file

@ -47,6 +47,10 @@ body {
overflow: hidden;
}
svg {
pointer-events: none;
}
/*h2 {
margin: 0;
font-size: 2.25rem;

View file

@ -6,11 +6,12 @@ import DeleteCookieIcon from '../icons/DeleteCookie';
import DeleteStorageIcon from '../icons/DeleteStorage';
import FavIconOff from '@material-ui/icons/StarBorder';
import FavIconOn from '@material-ui/icons/Star';
import {iconsColor} from '../../constants/colors';
import {iconsColor, lightIconsColor} from '../../constants/colors';
import commonStyles from '../common.styles.css';
import styles from './style.css';
import {Tooltip} from '@material-ui/core';
import {Icon} from 'flwww';
type Props = {
address: string,
@ -45,7 +46,6 @@ class AddressBar extends React.Component<Props> {
}
render() {
const FavIcon = this.props.isBookmarked ? FavIconOn : FavIconOff;
return (
<div className={styles.addressBarContainer}>
<input
@ -65,12 +65,23 @@ class AddressBar extends React.Component<Props> {
[commonStyles.enabled]: true,
})}
>
<Tooltip title="Bookmark">
<Tooltip
title={
this.props.isBookmarked
? 'Remove from Bookmarks'
: 'Add to Bookmarks'
}
>
<div
className={cx(commonStyles.flexAlignVerticalMiddle)}
onClick={() => this.props.toggleBookmark(this.state.userTypedAddress)}
onClick={() =>
this.props.toggleBookmark(this.state.userTypedAddress)
}
>
<FavIcon fontSize="small"/>
<Icon
type={this.props.isBookmarked ? 'starFull' : 'star'}
color={lightIconsColor}
/>
</div>
</Tooltip>
</div>

View file

@ -1,74 +1,112 @@
// @flow
import React, { useState } from 'react';
import React, {useState} from 'react';
import Grid from '@material-ui/core/Grid';
import Button from '@material-ui/core/Button';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import BookmarkEditDialog from './BookmarkEditDialog'
import styles from './style.css';
import BookmarkEditDialog from './BookmarkEditDialog';
import styles from './style.module.css';
import Globe from '../icons/Globe';
export const BookmarksBar = function ({bookmarks, onBookmarkClick, onBookmarkDelete, onBookmarkEdit}) {
return <Grid container direction="row" justify="flex-start" alignItems="center" className={styles.bookmarks} spacing={1}>
{bookmarks.map((bookmark, k) => (
<BookmarkItem bookmark={bookmark} onClick={onBookmarkClick} key={'bookmark' + k} onDelete={onBookmarkDelete} onEdit={onBookmarkEdit}/>
))}
</Grid>
export const BookmarksBar = function({
bookmarks,
onBookmarkClick,
onBookmarkDelete,
onBookmarkEdit,
}) {
return (
<div className={styles.bookmarks}>
{bookmarks.map((bookmark, k) => (
<BookmarkItem
bookmark={bookmark}
onClick={onBookmarkClick}
key={'bookmark' + k}
onDelete={onBookmarkDelete}
onEdit={onBookmarkEdit}
/>
))}
</div>
);
};
const useToggle = function () {
const [value, setValue] = useState(false)
const useToggle = function() {
const [value, setValue] = useState(false);
return [
value,
function () { setValue(true) },
function () { setValue(false) }
]
}
function() {
setValue(true);
},
function() {
setValue(false);
},
];
};
function BookmarkItem ({bookmark, onClick, onDelete, onEdit}) {
function BookmarkItem({bookmark, onClick, onDelete, onEdit}) {
const [anchorEl, setAnchorEl] = useState(null);
const [renameDialog, openRenameDialog, closeRenameDialog] = useToggle(null)
const [renameDialog, openRenameDialog, closeRenameDialog] = useToggle(null);
const handleContextMenu = function (event) {
const handleContextMenu = function(event) {
event.preventDefault();
setAnchorEl(event.currentTarget);
};
const handleClose = function () {
const handleClose = function() {
setAnchorEl(null);
};
const handleClick = function () {
onClick(bookmark)
const handleClick = function() {
onClick(bookmark);
};
const handleDelete = function () {
onDelete(bookmark)
const handleDelete = function() {
setAnchorEl(null);
onDelete(bookmark);
};
const handleRename = function (title, url) {
onEdit(bookmark, {title, url})
setAnchorEl(null)
}
const handleRename = function(title, url) {
onEdit(bookmark, {title, url});
setAnchorEl(null);
};
const closeDialog = function () {
closeRenameDialog()
setAnchorEl(null)
}
const closeDialog = function() {
closeRenameDialog();
setAnchorEl(null);
};
return <Grid item key={bookmark.url}>
<Button aria-controls="bookmark-menu" aria-haspopup="true" onClick={handleClick} onContextMenu={handleContextMenu}>
{bookmark.title}
</Button>
<Menu
id="bookmark-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={openRenameDialog}>Rename</MenuItem>
<MenuItem onClick={handleDelete}>Delete</MenuItem>
</Menu>
<BookmarkEditDialog open={renameDialog} onSubmit={handleRename} onClose={closeDialog} bookmark={bookmark}/>
</Grid>
return (
<>
<div
className={styles.bookmarkItem}
key={bookmark.url}
onClick={handleClick}
onContextMenu={handleContextMenu}
>
<Globe height={10} className={styles.icon} />
<span>{bookmark.title}</span>
</div>
<Menu
id="bookmark-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
getContentAnchorEl={null}
onContextMenu={handleClose}
>
<MenuItem onClick={openRenameDialog}>Edit</MenuItem>
<MenuItem onClick={handleDelete}>Delete</MenuItem>
</Menu>
<BookmarkEditDialog
open={renameDialog}
onSubmit={handleRename}
onClose={closeDialog}
bookmark={bookmark}
/>
</>
);
}

View file

@ -1,3 +0,0 @@
.bookmarks {
padding: 0 10px;
}

View file

@ -0,0 +1,28 @@
.bookmarks {
padding: 0 10px;
display: flex;
margin-top: 4px;
}
.bookmarkItem {
color: #ffffffcc;
fill: #ffffffcc;
cursor: default;
padding: 2px 10px;
border-radius: 15px;
font-size: 13px;
min-width: 100px;
max-width: 150px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.bookmarkItem:hover {
background-color: #6075ef;
fill: #fff;
}
.icon {
margin-right: 5px;
}

View file

@ -1,6 +1,6 @@
.header {
width: calc(100vw - 50px);
padding: 20px 0 10px;
padding: 20px 0 5px;
background: #252526;
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.35);
z-index: 2;

View file

@ -18,6 +18,13 @@ class NavigationControls extends Component {
ipcRenderer.on('reload-url', this.props.triggerNavigationReload);
ipcRenderer.on('reload-css', this.props.reloadCSS);
}
componentWillUnmount() {
ipcRenderer.removeListener(
'reload-url',
this.props.triggerNavigationReload
);
ipcRenderer.removeListener('reload-css', this.props.reloadCSS);
}
render() {
const iconProps = {

View file

@ -1,16 +1,64 @@
import React from 'react';
import React, {useState, useEffect} from 'react';
import cx from 'classnames';
import {shell, ipcRenderer} from 'electron';
import PropTypes from 'prop-types';
import styles from './styles.module.css';
import Github from '../icons/Github';
import {shell} from 'electron';
import Twitter from '../icons/Twitter';
import RoadMap from '../icons/RoadMap';
const Spacer = ({width = 10}) => (
<div className={styles.link} style={{width}}></div>
<div className={styles.link} style={{width}} />
);
const StatusBar = () => {
const AppUpdaterStatusInfoSection = () => {
const [status, setAppUpdaterStatus] = useState('idle');
useEffect(() => {
const handler = (event, args) => {
setAppUpdaterStatus(args.nextStatus);
};
ipcRenderer.on('updater-status-changed', handler);
return () => {
ipcRenderer.removeListener('updater-status-changed', handler);
};
}, []);
let label = '';
switch (status) {
case 'checking':
label = 'Update Info: Checking for Updates...';
break;
case 'noUpdate':
label = 'Update Info: The App is up to date!';
break;
case 'downloading':
label = 'Update Info: Downloading Update...';
break;
case 'downloaded':
label = 'Update Info: Update Downloaded';
break;
default:
label = null;
break;
}
if (label == null) return null;
return (
<div className={styles.section}>
<div>
<span className={cx('appUpdaterStatusInfo', styles.linkText)}>
{label}
</span>
</div>
</div>
);
};
const StatusBar = ({visible}) => {
if (!visible) {
return null;
}
return (
<div className={styles.statusBar}>
<div className={styles.section}>
@ -56,6 +104,7 @@ const StatusBar = () => {
</span>
</div>
</div>
<AppUpdaterStatusInfoSection />
<div className={styles.section}>
<div
className={styles.link}
@ -74,4 +123,8 @@ const StatusBar = () => {
);
};
StatusBar.propTypes = {
visible: PropTypes.bool.isRequired,
};
export default StatusBar;

View file

@ -131,6 +131,18 @@ class WebView extends Component {
this.initEventTriggers(this.webviewRef.current);
});
if (this.props.transmitNavigatorStatus) {
this.webviewRef.current.addEventListener(
'page-favicon-updated',
({favicons}) => this.props.onPageMetaFieldUpdate('favicons', favicons)
);
this.webviewRef.current.addEventListener(
'page-title-updated',
({title}) => this.props.onPageMetaFieldUpdate('title', title)
);
}
this.webviewRef.current.addEventListener('did-start-loading', () => {
this.setState({errorCode: null, errorDesc: null});
this.props.onLoadingStateChange(true);
@ -400,20 +412,20 @@ class WebView extends Component {
initEventTriggers = webview => {
this.getWebContentForId(webview.getWebContentsId()).executeJavaScript(`
responsivelyApp.deviceId = '${this.props.device.id}';
document.body.addEventListener('mouseleave', () => {
document.addEventListener('mouseleave', () => {
window.responsivelyApp.mouseOn = false;
if (responsivelyApp.domInspectorEnabled) {
responsivelyApp.domInspector.disable();
}
});
document.body.addEventListener('mouseenter', () => {
document.addEventListener('mouseenter', () => {
responsivelyApp.mouseOn = true;
if (responsivelyApp.domInspectorEnabled) {
responsivelyApp.domInspector.enable();
}
});
window.addEventListener('scroll', (e) => {
document.addEventListener('scroll', (e) => {
if (!responsivelyApp.mouseOn) {
return;
}

View file

@ -0,0 +1,121 @@
import React, {Fragment} from 'react';
export default function Globe({
width,
height,
color,
padding,
margin,
className,
}) {
return (
<svg
height={height}
width={width}
fill={color}
style={{enableBackground: 'new 0 0 356.926 356.926', padding, margin}}
version="1.1"
id="Capa_1"
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
x="0px"
y="0px"
viewBox="0 0 356.926 356.926"
xmlSpace="preserve"
className={`globeIcon ${className}`}
>
<g>
<g>
<path
d="M211.89,213.669c0-10.475-8.521-18.997-18.996-18.997c-0.401,0-0.799,0.017-1.193,0.041v2.406
c0.396-0.028,0.79-0.061,1.193-0.061c9.158,0,16.608,7.452,16.608,16.611s-7.45,16.61-16.608,16.61
c-0.269,0-0.53-0.027-0.795-0.041v0.897v1.509v4.723H186.2v3.182h13.388v-3.182h-5.104v-4.774
C204.218,231.781,211.89,223.607,211.89,213.669z"
/>
<g>
<polygon
points="260.072,79.408 260.398,82.045 256.447,82.882 255.913,88.517 260.677,88.517 266.998,87.913 270.251,84.021
266.788,82.678 264.883,80.488 262.024,75.858 260.677,69.329 255.286,70.409 253.799,72.721 253.799,75.312 256.378,77.084
"
/>
<polygon
points="255.495,81.569 255.773,78.037 252.637,76.683 248.233,77.706 244.945,82.94 244.945,86.344 248.768,86.344
"
/>
<path
d="M164.852,96.598l-0.976,2.498h-4.7v2.428h1.121c0,0,0.07,0.511,0.168,1.191l2.876-0.238l1.783-1.121l0.465-2.248
l2.335-0.204l0.912-1.888l-2.138-0.442L164.852,96.598z"
/>
<polygon points="152.739,101.001 152.565,103.366 155.976,103.081 156.324,100.705 154.279,99.096 " />
<path
d="M356.868,176.633c-0.047-5.223-0.313-10.398-0.802-15.505c-1.662-17.01-5.717-33.311-11.828-48.589
c-0.441-1.127-0.859-2.283-1.336-3.41c-8.121-19.183-19.531-36.646-33.474-51.721c-0.906-0.987-1.835-1.952-2.765-2.916
c-2.649-2.736-5.333-5.415-8.156-7.971C266.788,17.631,224.642,0,178.463,0C131.896,0,89.447,17.957,57.635,47.271
c-7.413,6.832-14.221,14.303-20.408,22.285C13.919,99.717,0,137.49,0,178.463c0,98.398,80.059,178.463,178.463,178.463
c69.225,0,129.316-39.643,158.897-97.399c6.32-12.327,11.247-25.491,14.569-39.294c0.837-3.486,1.58-7.018,2.208-10.585
c1.801-10.137,2.788-20.56,2.788-31.196C356.902,177.859,356.868,177.249,356.868,176.633z M323.278,105.306l1.022-1.162
c1.359,2.637,2.649,5.304,3.846,8.028l-1.708-0.07l-3.172,0.436v-7.233H323.278z M297.484,74.156l0.023-7.971
c2.812,2.975,5.508,6.036,8.087,9.214l-3.207,4.781l-11.247-0.111l-0.696-2.341L297.484,74.156z M82.214,54.364v-0.302h3.567
l0.325-1.226h5.838v2.55l-1.691,2.236h-8.052v-3.259H82.214z M87.925,62.323c0,0,3.578-0.61,3.892-0.61c0.296,0,0,3.573,0,3.573
l-8.081,0.511l-1.534-1.847L87.925,62.323z M334.642,133.156h-13.06l-7.971-5.92l-8.365,0.808v5.112h-2.648l-2.848-2.033
l-14.512-3.671v-9.4l-18.38,1.423l-5.705,3.062h-7.285l-3.59-0.36l-8.854,4.926v9.254l-18.097,13.065l1.5,5.583h3.677
l-0.964,5.315l-2.58,0.953l-0.133,13.884l15.633,17.823h6.819l0.407-1.081h12.246l3.531-3.265h6.948l3.812,3.811l10.328,1.069
l-1.359,13.757l11.503,20.28l-6.064,11.572l0.406,5.438l4.775,4.752v13.095l6.251,8.412v10.897h5.391
c-30.046,36.913-75.823,60.534-127.026,60.534c-90.312,0-163.783-73.454-163.783-163.777c0-22.732,4.665-44.401,13.077-64.089
v-5.106l5.855-7.11c2.033-3.846,4.212-7.582,6.542-11.235l0.25,2.974l-6.791,8.261c-2.108,3.985-4.084,8.052-5.855,12.217v9.312
l6.791,3.276v12.955l6.535,11.136l5.316,0.808l0.68-3.817l-6.245-9.661l-1.237-9.388h3.677l1.557,9.673l9.051,13.193l-2.33,4.27
l5.734,8.795l14.291,3.532v-2.306l5.711,0.808l-0.534,4.078l4.484,0.825l6.948,1.888l9.8,11.171l12.507,0.941l1.237,10.207
l-8.58,5.984l-0.39,9.115l-1.237,5.588l12.386,15.5l0.947,5.32c0,0,4.49,1.209,5.048,1.209c0.535,0,10.062,7.227,10.062,7.227
v28.024l3.393,0.964l-2.294,12.92l5.71,7.634l-1.068,12.827l7.563,13.269l9.696,8.47l9.731,0.197l0.952-3.148l-7.163-6.029
l0.418-2.986l1.272-3.684l0.273-3.741l-4.839-0.14l-2.44-3.066l4.021-3.881l0.546-2.916l-4.496-1.29l0.261-2.719l6.402-0.976
l9.73-4.672l3.265-6.006l10.196-13.06l-2.312-10.213l3.131-5.438l9.399,0.278l6.327-5.02l2.051-19.693l7.04-8.877l1.237-5.704
l-6.39-2.045l-4.224-6.942l-14.419-0.145l-11.444-4.351l-0.534-8.162l-3.811-6.675l-10.335-0.145l-5.995-9.382l-5.298-2.585
l-0.273,2.858l-9.672,0.569l-3.532-4.926l-10.079-2.045l-8.302,9.603l-13.065-2.23l-0.953-14.727l-9.527-1.632l3.805-7.221
l-1.092-4.148l-12.531,8.371l-7.877-0.964l-2.817-6.158l1.737-6.355l4.339-8.005l9.998-5.072h19.322l-0.064,5.891l6.948,3.235
l-0.558-10.062l5.007-5.037l10.103-6.64l0.703-4.659l10.068-10.486l10.707-5.937l-0.941-0.773l7.256-6.826l2.655,0.703
l1.214,1.522l2.76-3.062l0.68-0.296l-3.021-0.43l-3.084-0.987v-2.963l1.632-1.33h3.579l1.655,0.726l1.418,2.858l1.737-0.267
v-0.244l0.5,0.163l5.02-0.772l0.714-2.463l2.852,0.726v2.667l-2.666,1.818h0.018l0.377,2.928l9.115,2.794c0,0,0,0.035,0.023,0.11
l2.079-0.18l0.146-3.939l-7.209-3.282l-0.396-1.894l5.972-2.033l0.273-5.722l-6.245-3.805l-0.412-9.667l-8.581,4.218h-3.143
l0.837-7.355l-11.688-2.748l-4.816,3.654v11.119l-8.673,2.754l-3.486,7.244l-3.758,0.604v-9.277l-8.162-1.133l-4.096-2.667
l-1.639-6.007l14.611-8.54l7.14-2.179l0.72,4.804l3.991-0.215l0.308-2.411l4.166-0.599l0.07-0.842l-1.784-0.738l-0.407-2.544
l5.118-0.43l3.091-3.213l0.18-0.238l0.035,0.012l0.941-0.976l10.753-1.354l4.746,4.032l-12.467,6.64l15.871,3.747l2.045-5.31
h6.948l2.44-4.625l-4.903-1.226v-5.856l-15.359-6.803l-10.62,1.226l-6.001,3.125l0.407,7.628l-6.257-0.953l-0.964-4.212
l6.007-5.449l-10.898-0.535l-3.125,0.953l-1.359,3.677l4.084,0.686l-0.813,4.084l-6.936,0.406l-1.092,2.725L118.987,52.4
c0,0-0.273-5.711-0.703-5.711c-0.389,0,7.901-0.145,7.901-0.145l5.995-5.85l-3.271-1.632l-4.339,4.223l-7.222-0.406l-4.403-6.019
h-9.254L94.03,44.07h8.848l0.796,2.597l-2.307,2.172l9.807,0.279l1.487,3.532l-11.032-0.407l-0.546-2.725l-6.925-1.499
l-3.689-2.033l-8.255,0.069c27.043-19.699,60.284-31.358,96.226-31.358c41.403,0,79.263,15.476,108.124,40.915l-1.929,3.474
l-7.564,2.962l-3.194,3.462l0.743,4.02l3.893,0.546l2.358,5.867l6.704-2.713l1.127,7.86h-2.045l-5.519-0.819l-6.111,1.022
l-5.926,8.377l-8.458,1.319l-1.221,7.25l3.579,0.842l-1.046,4.665l-8.412-1.69l-7.703,1.69l-1.639,4.293l1.325,9.01l4.531,2.115
l7.61-0.046l5.123-0.465l1.58-4.078l8.018-10.422l5.264,1.081l5.193-4.7l0.976,3.678l12.78,8.621l-1.557,2.108l-5.763-0.308
l2.23,3.137l3.556,0.79l4.159-1.737l-0.093-5.002l1.859-0.923l-1.487-1.575l-8.528-4.758l-2.254-6.314h7.099l2.243,2.248
l6.134,5.257l0.244,6.367l6.332,6.733l2.348-9.231l4.392-2.394l0.802,7.552l4.287,4.7l8.54-0.139
c1.661,4.247,3.148,8.563,4.427,12.978L334.642,133.156z M97.324,81.092l4.27-2.044l3.881,0.929l-1.324,5.211l-4.183,1.319
L97.324,81.092z M120.073,93.35v3.37h-9.783l-3.689-1.028l0.918-2.341l4.7-1.94h6.437v1.94H120.073z M124.582,98.05v3.259
l-2.463,1.58l-3.044,0.575c0,0,0-4.903,0-5.415H124.582z M121.822,96.72v-3.893l3.363,3.067L121.822,96.72z M123.355,104.568
v3.178l-2.347,2.347h-5.211l0.813-3.573l2.463-0.215l0.5-1.226L123.355,104.568z M110.39,98.05h5.408l-6.948,9.696l-2.852-1.534
l0.616-4.084L110.39,98.05z M132.529,103.464v3.166h-5.211l-1.417-2.062v-2.951h0.406L132.529,103.464z M127.748,99.096
l1.475-1.557l2.498,1.557l-1.999,1.656L127.748,99.096z M337.291,141.428l0.511-0.61c0.232,0.93,0.441,1.859,0.662,2.789
L337.291,141.428z"
/>
<path d="M27.734,109.268v5.106c1.771-4.177,3.747-8.231,5.855-12.223L27.734,109.268z" />
</g>
</g>
</g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
</svg>
);
}

View file

@ -11,3 +11,6 @@ export const FLIP_ORIENTATION_ALL_DEVICES = 'FLIP_ORIENTATION_ALL_DEVICES';
export const ENABLE_INSPECTOR_ALL_DEVICES = 'ENABLE_INSPECTOR_ALL_DEVICES';
export const DISABLE_INSPECTOR_ALL_DEVICES = 'DISABLE_INSPECTOR_ALL_DEVICES';
export const STOP_LOADING = 'STOP_LOADING';
// status bar events
export const STATUS_BAR_VISIBILITY_CHANGE = 'status-bar-visibility-change';

View file

@ -2,3 +2,4 @@ export const ACTIVE_DEVICES = 'activeDevices';
export const CUSTOM_DEVICES = 'customDevices';
export const USER_PREFERENCES = 'userPreferences';
export const BOOKMARKS = 'bookmarks';
export const STATUS_BAR_VISIBILITY = 'statusBarVisibility';

View file

@ -6,13 +6,15 @@ import {bindActionCreators} from 'redux';
import AddressInput from '../../components/Addressinput';
import * as BrowserActions from '../../actions/browser';
import {toggleBookmarkUrl} from '../../actions/bookmarks'
import {toggleBookmarkUrl} from '../../actions/bookmarks';
const AddressBar = function(props) {
const handler = (_, url) => {
props.onAddressChange(url);
};
useEffect(() => {
ipcRenderer.on('address-change', (_, url) => {
props.onAddressChange(url);
});
ipcRenderer.on('address-change', handler);
return () => ipcRenderer.removeListener('address-change', handler);
}, []);
return (
<AddressInput
@ -21,7 +23,9 @@ const AddressBar = function(props) {
homepage={props.browser.homepage}
setHomepage={props.setCurrentAddressAsHomepage}
isBookmarked={props.isBookmarked}
toggleBookmark={props.toggleBookmarkUrl}
toggleBookmark={url =>
props.toggleBookmarkUrl(url, props.browser.currentPageMeta)
}
deleteCookies={props.deleteCookies}
deleteStorage={props.deleteStorage}
/>
@ -31,7 +35,9 @@ const AddressBar = function(props) {
function mapStateToProps(state) {
return {
browser: state.browser,
isBookmarked: state.bookmarks.bookmarks.some(b => b.url === state.browser.address)
isBookmarked: state.bookmarks.bookmarks.some(
b => b.url === state.browser.address
),
};
}

View file

@ -0,0 +1,36 @@
// @flow
import React, {useEffect} from 'react';
import {ipcRenderer} from 'electron';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import StatusBar from '../../components/StatusBar';
import {toggleStatusBarVisibility} from '../../actions/statusBar';
import {STATUS_BAR_VISIBILITY_CHANGE} from '../../constants/pubsubEvents';
const StatusBarContainer = props => {
useEffect(() => {
const handler = () => {
props.toggleStatusBarVisibility();
};
ipcRenderer.on(STATUS_BAR_VISIBILITY_CHANGE, handler);
return () =>
ipcRenderer.removeListener(STATUS_BAR_VISIBILITY_CHANGE, handler);
}, []);
return <StatusBar visible={props.visible} />;
};
function mapStateToProps(state) {
return {
visible: state.statusBar.visible,
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({toggleStatusBarVisibility}, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(StatusBarContainer);

View file

@ -297,7 +297,7 @@ const createWindow = async () => {
appUpdater.on('status-changed', nextStatus => {
menuBuilder.buildMenu(true);
// update status bar info
mainWindow.webContents.send('updater-status-changed', {nextStatus});
});
// Remove this if your app does not use auto updates
appUpdater.checkForUpdatesAndNotify();

View file

@ -14,10 +14,9 @@ import {
getAllShortcuts,
registerShortcut,
} from './shortcut-manager/main-shortcut-manager';
import {
appUpdater,
AppUpdaterState
} from './app-updater';
import {appUpdater, AppUpdaterStatus} from './app-updater';
import {statusBarSettings} from './settings/statusBarSettings';
import {STATUS_BAR_VISIBILITY_CHANGE} from './constants/pubsubEvents';
const path = require('path');
@ -105,13 +104,16 @@ export default class MenuBuilder {
id: 'CHECK_FOR_UPDATES',
click() {
appUpdater.checkForUpdatesAndNotify().then(r => {
if (r == null || r.updateInfo == null || r.updateInfo.version === pkg.version) {
dialog
.showMessageBox(BrowserWindow.getAllWindows()[0], {
type: 'info',
title: 'Responsively',
message: 'There are currently no updates available'
});
if (
r == null ||
r.updateInfo == null ||
r.updateInfo.version === pkg.version
) {
dialog.showMessageBox(BrowserWindow.getAllWindows()[0], {
type: 'info',
title: 'Responsively',
message: 'There are currently no updates available',
});
}
});
},
@ -122,12 +124,12 @@ export default class MenuBuilder {
click() {
const iconPath = path.join(__dirname, '../resources/icons/64x64.png');
const title = 'Responsively';
const description = pkg.description;
const {description} = pkg;
const version = pkg.version || 'Unknown';
const electron = process.versions['electron'] || 'Unknown';
const chrome = process.versions['chrome'] || 'Unknown';
const node = process.versions['node'] || 'Unknown';
const v8 = process.versions['v8'] || 'Unknown';
const electron = process.versions.electron || 'Unknown';
const chrome = process.versions.chrome || 'Unknown';
const node = process.versions.node || 'Unknown';
const v8 = process.versions.v8 || 'Unknown';
const osText =
`${os.type()} ${os.arch()} ${os.release()}`.trim() || 'Unknown';
const usefulInfo = `Version: ${version}\nElectron: ${electron}\nChrome: ${chrome}\nNode.js: ${node}\nV8: ${v8}\nOS: ${osText}`;
@ -179,7 +181,7 @@ export default class MenuBuilder {
}
let filePath = selected[0];
if (!filePath.startsWith('file://')) {
filePath = 'file://' + filePath;
filePath = `file://${filePath}`;
}
this.mainWindow.webContents.send('address-change', filePath);
},
@ -188,27 +190,42 @@ export default class MenuBuilder {
};
getCheckForUpdatesMenuState() {
const updaterState = appUpdater.getCurrentState();
const updaterStatus = appUpdater.getCurrentStatus();
let label = 'Check for Updates...';
let enabled = true;
if (updaterState === AppUpdaterState.Checking) {
enabled = false;
label = 'Checking for Updates...';
}
else if (updaterState === AppUpdaterState.Downloading) {
enabled = false;
label = 'Downloading Update...';
}
switch(updaterStatus) {
case AppUpdaterStatus.Idle:
label = 'Check for Updates...';
enabled = true;
break;
case AppUpdaterStatus.Checking:
label = 'Checking for Updates...';
enabled = false;
break;
case AppUpdaterStatus.NoUpdate:
label = 'No Updates';
enabled = false;
break;
case AppUpdaterStatus.Downloading:
label = 'Downloading Update...';
enabled = false;
break;
case AppUpdaterStatus.Downloaded:
label = 'Update Downloaded';
enabled = false;
break;
}
return {label, enabled};
}
buildMenu(isUpdate: boolean = false) {
if (isUpdate) {
const chkUpdtMenu = this.subMenuHelp.submenu.find(x => x.id === 'CHECK_FOR_UPDATES');
const {label, enabled} = this.getCheckForUpdatesMenuState();
const chkUpdtMenu = this.subMenuHelp.submenu.find(
x => x.id === 'CHECK_FOR_UPDATES'
);
const {label, enabled} = this.getCheckForUpdatesMenuState();
chkUpdtMenu.label = label;
chkUpdtMenu.enabled = enabled;
}
@ -340,6 +357,14 @@ export default class MenuBuilder {
this.mainWindow.toggleDevTools();
},
},
{
label: 'Show Status Bar',
type: 'checkbox',
checked: statusBarSettings.getVisibility(),
click: () => {
this.mainWindow.webContents.send(STATUS_BAR_VISIBILITY_CHANGE);
},
},
],
};
const subMenuViewProd = {
@ -373,6 +398,14 @@ export default class MenuBuilder {
this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
},
},
{
label: 'Show Status Bar',
type: 'checkbox',
checked: statusBarSettings.getVisibility(),
click: () => {
this.mainWindow.webContents.send(STATUS_BAR_VISIBILITY_CHANGE);
},
},
],
};
const subMenuWindow = {
@ -446,6 +479,16 @@ export default class MenuBuilder {
this.mainWindow.toggleDevTools();
},
},
{
label: 'Show Status Bar',
type: 'checkbox',
checked: statusBarSettings.getVisibility(),
click: () => {
this.mainWindow.webContents.send(
STATUS_BAR_VISIBILITY_CHANGE
);
},
},
]
: [
{
@ -480,6 +523,16 @@ export default class MenuBuilder {
);
},
},
{
label: 'Show Status Bar',
type: 'checkbox',
checked: statusBarSettings.getVisibility(),
click: () => {
this.mainWindow.webContents.send(
STATUS_BAR_VISIBILITY_CHANGE
);
},
},
],
},
this.subMenuHelp,

View file

@ -1,12 +1,13 @@
import settings from 'electron-settings';
import {TOGGLE_BOOKMARK, EDIT_BOOKMARK} from '../actions/bookmarks'
import {BOOKMARKS} from '../constants/settingKeys'
import { getWebsiteName } from '../components/WebView/screenshotUtil';
import {TOGGLE_BOOKMARK, EDIT_BOOKMARK} from '../actions/bookmarks';
import {BOOKMARKS} from '../constants/settingKeys';
import {getWebsiteName} from '../components/WebView/screenshotUtil';
import console from 'electron-timber';
type BookmarksType = {
title: string,
url: string
}
url: string,
};
function fetchBookmarks(): BookmarksType {
return settings.get(BOOKMARKS) || [];
@ -24,22 +25,24 @@ export default function browser(
) {
switch (action.type) {
case TOGGLE_BOOKMARK:
let bookmarks = state.bookmarks
let bookmarks = state.bookmarks;
const bookmark = {
title: getWebsiteName(action.url),
url: action.url
}
title: action.title || getWebsiteName(action.url),
url: action.url,
};
if (bookmarks.find(b => b.url === action.url)) {
bookmarks = bookmarks.filter(b => b.url !== action.url)
bookmarks = bookmarks.filter(b => b.url !== action.url);
} else {
bookmarks = [...bookmarks, bookmark]
bookmarks = [...bookmarks, bookmark];
}
persistBookmarks(bookmarks)
return {...state, bookmarks}
persistBookmarks(bookmarks);
return {...state, bookmarks};
case EDIT_BOOKMARK:
const updatedBookmarks = state.bookmarks.map(b => b === action.bookmark ? {...b, title: action.title, url: action.url} : b)
persistBookmarks(updatedBookmarks)
return {...state, bookmarks: updatedBookmarks}
const updatedBookmarks = state.bookmarks.map(b =>
b === action.bookmark ? {...b, title: action.title, url: action.url} : b
);
persistBookmarks(updatedBookmarks);
return {...state, bookmarks: updatedBookmarks};
default:
return state;
}

View file

@ -17,9 +17,8 @@ import {
NEW_INSPECTOR_STATUS,
NEW_WINDOW_SIZE,
DEVICE_LOADING,
DEVICE_FOCUS,
DEVICE_UNFOCUS,
NEW_FOCUSED_DEVICE,
NEW_PAGE_META_FIELD,
} from '../actions/browser';
import type {Action} from './types';
import getAllDevices from '../constants/devices';
@ -99,6 +98,11 @@ type PreviewerType = {
focusedDeviceId: string,
};
type PageMetaType = {
title: String,
favicons: Array<string>,
};
type UserPreferenceType = {
disableSSLValidation: boolean,
reopenLastAddress: boolean,
@ -114,6 +118,7 @@ export type BrowserStateType = {
devices: Array<Device>,
homepage: string,
address: string,
currentPageMeta: PageMetaType,
zoomLevel: number,
scrollPosition: ScrollPositionType,
navigatorStatus: NavigatorStatusType,
@ -214,6 +219,7 @@ export default function browser(
address: _getUserPreferences().reopenLastAddress
? getLastOpenedAddress()
: getHomepage(),
currentPageMeta: {},
zoomLevel: 0.6,
previousZoomLevel: null,
scrollPosition: {x: 0, y: 0},
@ -251,7 +257,15 @@ export default function browser(
switch (action.type) {
case NEW_ADDRESS:
saveLastOpenedAddress(action.address);
return {...state, address: action.address};
return {...state, address: action.address, currentPageMeta: {}};
case NEW_PAGE_META_FIELD:
return {
...state,
currentPageMeta: {
...state.currentPageMeta,
[action.name]: action.value,
},
};
case NEW_HOMEPAGE:
const {homepage} = action;
saveHomepage(homepage);

View file

@ -2,12 +2,14 @@
import {combineReducers} from 'redux';
import {connectRouter} from 'connected-react-router';
import browser from './browser';
import bookmarks from './bookmarks'
import bookmarks from './bookmarks';
import statusBar from './statusBar';
export default function createRootReducer(history: History) {
return combineReducers({
router: connectRouter(history),
browser,
bookmarks,
statusBar,
});
}

View file

@ -0,0 +1,20 @@
// @flow
import {TOGGLE_STATUS_BAR_VISIBILITY} from '../actions/statusBar';
import {statusBarSettings} from '../settings/statusBarSettings';
export type StatusBarStateType = {visible: boolean};
export default function app(
state: StatusBarStateType = {visible: statusBarSettings.getVisibility()},
action: Action
) {
switch (action.type) {
case TOGGLE_STATUS_BAR_VISIBILITY:
return {
...state,
visible: action.visible,
};
default:
return state;
}
}

View file

@ -0,0 +1,24 @@
import settings from 'electron-settings';
import {STATUS_BAR_VISIBILITY} from '../constants/settingKeys';
class StatusBarSettings {
constructor() {
const visibility = settings.get(STATUS_BAR_VISIBILITY);
if (visibility === undefined) {
settings.set(STATUS_BAR_VISIBILITY, true);
}
}
getVisibility() {
return settings.get(STATUS_BAR_VISIBILITY);
}
setVisibility(visible) {
settings.set(STATUS_BAR_VISIBILITY, visible);
}
}
const statusBarSettingsInstance = new StatusBarSettings();
export {statusBarSettingsInstance as statusBarSettings};

View file

@ -1,7 +1,7 @@
{
"name": "Responsively-App",
"productName": "ResponsivelyApp",
"version": "0.3.0",
"version": "0.4.0",
"description": "A developer-friendly browser for developing responsive web apps",
"scripts": {
"build": "concurrently \"yarn build-main\" \"yarn build-renderer\"",

View file

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="356.926px" height="356.926px" viewBox="0 0 356.926 356.926" style="enable-background:new 0 0 356.926 356.926;"
xml:space="preserve">
<g>
<g>
<path d="M211.89,213.669c0-10.475-8.521-18.997-18.996-18.997c-0.401,0-0.799,0.017-1.193,0.041v2.406
c0.396-0.028,0.79-0.061,1.193-0.061c9.158,0,16.608,7.452,16.608,16.611s-7.45,16.61-16.608,16.61
c-0.269,0-0.53-0.027-0.795-0.041v0.897v1.509v4.723H186.2v3.182h13.388v-3.182h-5.104v-4.774
C204.218,231.781,211.89,223.607,211.89,213.669z"/>
<g>
<polygon points="260.072,79.408 260.398,82.045 256.447,82.882 255.913,88.517 260.677,88.517 266.998,87.913 270.251,84.021
266.788,82.678 264.883,80.488 262.024,75.858 260.677,69.329 255.286,70.409 253.799,72.721 253.799,75.312 256.378,77.084
"/>
<polygon points="255.495,81.569 255.773,78.037 252.637,76.683 248.233,77.706 244.945,82.94 244.945,86.344 248.768,86.344
"/>
<path d="M164.852,96.598l-0.976,2.498h-4.7v2.428h1.121c0,0,0.07,0.511,0.168,1.191l2.876-0.238l1.783-1.121l0.465-2.248
l2.335-0.204l0.912-1.888l-2.138-0.442L164.852,96.598z"/>
<polygon points="152.739,101.001 152.565,103.366 155.976,103.081 156.324,100.705 154.279,99.096 "/>
<path d="M356.868,176.633c-0.047-5.223-0.313-10.398-0.802-15.505c-1.662-17.01-5.717-33.311-11.828-48.589
c-0.441-1.127-0.859-2.283-1.336-3.41c-8.121-19.183-19.531-36.646-33.474-51.721c-0.906-0.987-1.835-1.952-2.765-2.916
c-2.649-2.736-5.333-5.415-8.156-7.971C266.788,17.631,224.642,0,178.463,0C131.896,0,89.447,17.957,57.635,47.271
c-7.413,6.832-14.221,14.303-20.408,22.285C13.919,99.717,0,137.49,0,178.463c0,98.398,80.059,178.463,178.463,178.463
c69.225,0,129.316-39.643,158.897-97.399c6.32-12.327,11.247-25.491,14.569-39.294c0.837-3.486,1.58-7.018,2.208-10.585
c1.801-10.137,2.788-20.56,2.788-31.196C356.902,177.859,356.868,177.249,356.868,176.633z M323.278,105.306l1.022-1.162
c1.359,2.637,2.649,5.304,3.846,8.028l-1.708-0.07l-3.172,0.436v-7.233H323.278z M297.484,74.156l0.023-7.971
c2.812,2.975,5.508,6.036,8.087,9.214l-3.207,4.781l-11.247-0.111l-0.696-2.341L297.484,74.156z M82.214,54.364v-0.302h3.567
l0.325-1.226h5.838v2.55l-1.691,2.236h-8.052v-3.259H82.214z M87.925,62.323c0,0,3.578-0.61,3.892-0.61c0.296,0,0,3.573,0,3.573
l-8.081,0.511l-1.534-1.847L87.925,62.323z M334.642,133.156h-13.06l-7.971-5.92l-8.365,0.808v5.112h-2.648l-2.848-2.033
l-14.512-3.671v-9.4l-18.38,1.423l-5.705,3.062h-7.285l-3.59-0.36l-8.854,4.926v9.254l-18.097,13.065l1.5,5.583h3.677
l-0.964,5.315l-2.58,0.953l-0.133,13.884l15.633,17.823h6.819l0.407-1.081h12.246l3.531-3.265h6.948l3.812,3.811l10.328,1.069
l-1.359,13.757l11.503,20.28l-6.064,11.572l0.406,5.438l4.775,4.752v13.095l6.251,8.412v10.897h5.391
c-30.046,36.913-75.823,60.534-127.026,60.534c-90.312,0-163.783-73.454-163.783-163.777c0-22.732,4.665-44.401,13.077-64.089
v-5.106l5.855-7.11c2.033-3.846,4.212-7.582,6.542-11.235l0.25,2.974l-6.791,8.261c-2.108,3.985-4.084,8.052-5.855,12.217v9.312
l6.791,3.276v12.955l6.535,11.136l5.316,0.808l0.68-3.817l-6.245-9.661l-1.237-9.388h3.677l1.557,9.673l9.051,13.193l-2.33,4.27
l5.734,8.795l14.291,3.532v-2.306l5.711,0.808l-0.534,4.078l4.484,0.825l6.948,1.888l9.8,11.171l12.507,0.941l1.237,10.207
l-8.58,5.984l-0.39,9.115l-1.237,5.588l12.386,15.5l0.947,5.32c0,0,4.49,1.209,5.048,1.209c0.535,0,10.062,7.227,10.062,7.227
v28.024l3.393,0.964l-2.294,12.92l5.71,7.634l-1.068,12.827l7.563,13.269l9.696,8.47l9.731,0.197l0.952-3.148l-7.163-6.029
l0.418-2.986l1.272-3.684l0.273-3.741l-4.839-0.14l-2.44-3.066l4.021-3.881l0.546-2.916l-4.496-1.29l0.261-2.719l6.402-0.976
l9.73-4.672l3.265-6.006l10.196-13.06l-2.312-10.213l3.131-5.438l9.399,0.278l6.327-5.02l2.051-19.693l7.04-8.877l1.237-5.704
l-6.39-2.045l-4.224-6.942l-14.419-0.145l-11.444-4.351l-0.534-8.162l-3.811-6.675l-10.335-0.145l-5.995-9.382l-5.298-2.585
l-0.273,2.858l-9.672,0.569l-3.532-4.926l-10.079-2.045l-8.302,9.603l-13.065-2.23l-0.953-14.727l-9.527-1.632l3.805-7.221
l-1.092-4.148l-12.531,8.371l-7.877-0.964l-2.817-6.158l1.737-6.355l4.339-8.005l9.998-5.072h19.322l-0.064,5.891l6.948,3.235
l-0.558-10.062l5.007-5.037l10.103-6.64l0.703-4.659l10.068-10.486l10.707-5.937l-0.941-0.773l7.256-6.826l2.655,0.703
l1.214,1.522l2.76-3.062l0.68-0.296l-3.021-0.43l-3.084-0.987v-2.963l1.632-1.33h3.579l1.655,0.726l1.418,2.858l1.737-0.267
v-0.244l0.5,0.163l5.02-0.772l0.714-2.463l2.852,0.726v2.667l-2.666,1.818h0.018l0.377,2.928l9.115,2.794c0,0,0,0.035,0.023,0.11
l2.079-0.18l0.146-3.939l-7.209-3.282l-0.396-1.894l5.972-2.033l0.273-5.722l-6.245-3.805l-0.412-9.667l-8.581,4.218h-3.143
l0.837-7.355l-11.688-2.748l-4.816,3.654v11.119l-8.673,2.754l-3.486,7.244l-3.758,0.604v-9.277l-8.162-1.133l-4.096-2.667
l-1.639-6.007l14.611-8.54l7.14-2.179l0.72,4.804l3.991-0.215l0.308-2.411l4.166-0.599l0.07-0.842l-1.784-0.738l-0.407-2.544
l5.118-0.43l3.091-3.213l0.18-0.238l0.035,0.012l0.941-0.976l10.753-1.354l4.746,4.032l-12.467,6.64l15.871,3.747l2.045-5.31
h6.948l2.44-4.625l-4.903-1.226v-5.856l-15.359-6.803l-10.62,1.226l-6.001,3.125l0.407,7.628l-6.257-0.953l-0.964-4.212
l6.007-5.449l-10.898-0.535l-3.125,0.953l-1.359,3.677l4.084,0.686l-0.813,4.084l-6.936,0.406l-1.092,2.725L118.987,52.4
c0,0-0.273-5.711-0.703-5.711c-0.389,0,7.901-0.145,7.901-0.145l5.995-5.85l-3.271-1.632l-4.339,4.223l-7.222-0.406l-4.403-6.019
h-9.254L94.03,44.07h8.848l0.796,2.597l-2.307,2.172l9.807,0.279l1.487,3.532l-11.032-0.407l-0.546-2.725l-6.925-1.499
l-3.689-2.033l-8.255,0.069c27.043-19.699,60.284-31.358,96.226-31.358c41.403,0,79.263,15.476,108.124,40.915l-1.929,3.474
l-7.564,2.962l-3.194,3.462l0.743,4.02l3.893,0.546l2.358,5.867l6.704-2.713l1.127,7.86h-2.045l-5.519-0.819l-6.111,1.022
l-5.926,8.377l-8.458,1.319l-1.221,7.25l3.579,0.842l-1.046,4.665l-8.412-1.69l-7.703,1.69l-1.639,4.293l1.325,9.01l4.531,2.115
l7.61-0.046l5.123-0.465l1.58-4.078l8.018-10.422l5.264,1.081l5.193-4.7l0.976,3.678l12.78,8.621l-1.557,2.108l-5.763-0.308
l2.23,3.137l3.556,0.79l4.159-1.737l-0.093-5.002l1.859-0.923l-1.487-1.575l-8.528-4.758l-2.254-6.314h7.099l2.243,2.248
l6.134,5.257l0.244,6.367l6.332,6.733l2.348-9.231l4.392-2.394l0.802,7.552l4.287,4.7l8.54-0.139
c1.661,4.247,3.148,8.563,4.427,12.978L334.642,133.156z M97.324,81.092l4.27-2.044l3.881,0.929l-1.324,5.211l-4.183,1.319
L97.324,81.092z M120.073,93.35v3.37h-9.783l-3.689-1.028l0.918-2.341l4.7-1.94h6.437v1.94H120.073z M124.582,98.05v3.259
l-2.463,1.58l-3.044,0.575c0,0,0-4.903,0-5.415H124.582z M121.822,96.72v-3.893l3.363,3.067L121.822,96.72z M123.355,104.568
v3.178l-2.347,2.347h-5.211l0.813-3.573l2.463-0.215l0.5-1.226L123.355,104.568z M110.39,98.05h5.408l-6.948,9.696l-2.852-1.534
l0.616-4.084L110.39,98.05z M132.529,103.464v3.166h-5.211l-1.417-2.062v-2.951h0.406L132.529,103.464z M127.748,99.096
l1.475-1.557l2.498,1.557l-1.999,1.656L127.748,99.096z M337.291,141.428l0.511-0.61c0.232,0.93,0.441,1.859,0.662,2.789
L337.291,141.428z"/>
<path d="M27.734,109.268v5.106c1.771-4.177,3.747-8.231,5.855-12.223L27.734,109.268z"/>
</g>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.3 KiB