mirror of
https://github.com/responsively-org/responsively-app
synced 2024-11-10 14:54:12 +00:00
Merge branch 'master' of https://github.com/manojVivek/responsively-app into feature/focus-device
This commit is contained in:
commit
0ede51e7a3
30 changed files with 745 additions and 153 deletions
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
14
desktop-app/app/actions/statusBar.js
Normal file
14
desktop-app/app/actions/statusBar.js
Normal 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,
|
||||
};
|
||||
}
|
|
@ -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 };
|
|
@ -47,6 +47,10 @@ body {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
svg {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/*h2 {
|
||||
margin: 0;
|
||||
font-size: 2.25rem;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -4,29 +4,47 @@ 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}>
|
||||
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}/>
|
||||
<BookmarkItem
|
||||
bookmark={bookmark}
|
||||
onClick={onBookmarkClick}
|
||||
key={'bookmark' + k}
|
||||
onDelete={onBookmarkDelete}
|
||||
onEdit={onBookmarkEdit}
|
||||
/>
|
||||
))}
|
||||
</Grid>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const useToggle = function() {
|
||||
const [value, setValue] = useState(false)
|
||||
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}) {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const [renameDialog, openRenameDialog, closeRenameDialog] = useToggle(null)
|
||||
const [renameDialog, openRenameDialog, closeRenameDialog] = useToggle(null);
|
||||
|
||||
const handleContextMenu = function(event) {
|
||||
event.preventDefault();
|
||||
|
@ -38,37 +56,57 @@ function BookmarkItem ({bookmark, onClick, onDelete, onEdit}) {
|
|||
};
|
||||
|
||||
const handleClick = function() {
|
||||
onClick(bookmark)
|
||||
onClick(bookmark);
|
||||
};
|
||||
|
||||
const handleDelete = function() {
|
||||
onDelete(bookmark)
|
||||
setAnchorEl(null);
|
||||
onDelete(bookmark);
|
||||
};
|
||||
|
||||
const handleRename = function(title, url) {
|
||||
onEdit(bookmark, {title, url})
|
||||
setAnchorEl(null)
|
||||
}
|
||||
onEdit(bookmark, {title, url});
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const closeDialog = function() {
|
||||
closeRenameDialog()
|
||||
setAnchorEl(null)
|
||||
}
|
||||
closeRenameDialog();
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
return <Grid item key={bookmark.url}>
|
||||
<Button aria-controls="bookmark-menu" aria-haspopup="true" onClick={handleClick} onContextMenu={handleContextMenu}>
|
||||
{bookmark.title}
|
||||
</Button>
|
||||
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}>Rename</MenuItem>
|
||||
<MenuItem onClick={openRenameDialog}>Edit</MenuItem>
|
||||
<MenuItem onClick={handleDelete}>Delete</MenuItem>
|
||||
</Menu>
|
||||
<BookmarkEditDialog open={renameDialog} onSubmit={handleRename} onClose={closeDialog} bookmark={bookmark}/>
|
||||
</Grid>
|
||||
<BookmarkEditDialog
|
||||
open={renameDialog}
|
||||
onSubmit={handleRename}
|
||||
onClose={closeDialog}
|
||||
bookmark={bookmark}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
.bookmarks {
|
||||
padding: 0 10px;
|
||||
}
|
28
desktop-app/app/components/BookmarksBar/style.module.css
Normal file
28
desktop-app/app/components/BookmarksBar/style.module.css
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
121
desktop-app/app/components/icons/Globe.js
Normal file
121
desktop-app/app/components/icons/Globe.js
Normal 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>
|
||||
);
|
||||
}
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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) {
|
||||
useEffect(() => {
|
||||
ipcRenderer.on('address-change', (_, url) => {
|
||||
const handler = (_, url) => {
|
||||
props.onAddressChange(url);
|
||||
});
|
||||
};
|
||||
useEffect(() => {
|
||||
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
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
36
desktop-app/app/containers/StatusBarContainer/index.js
Normal file
36
desktop-app/app/containers/StatusBarContainer/index.js
Normal 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);
|
|
@ -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();
|
||||
|
|
|
@ -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,12 +104,15 @@ 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], {
|
||||
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'
|
||||
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,26 +190,41 @@ 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;
|
||||
switch(updaterStatus) {
|
||||
case AppUpdaterStatus.Idle:
|
||||
label = 'Check for Updates...';
|
||||
enabled = true;
|
||||
break;
|
||||
case AppUpdaterStatus.Checking:
|
||||
label = 'Checking for Updates...';
|
||||
}
|
||||
else if (updaterState === AppUpdaterState.Downloading) {
|
||||
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 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,
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import settings from 'electron-settings';
|
||||
import {TOGGLE_BOOKMARK, EDIT_BOOKMARK} from '../actions/bookmarks'
|
||||
import {BOOKMARKS} from '../constants/settingKeys'
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
20
desktop-app/app/reducers/statusBar.js
Normal file
20
desktop-app/app/reducers/statusBar.js
Normal 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;
|
||||
}
|
||||
}
|
24
desktop-app/app/settings/statusBarSettings.js
Normal file
24
desktop-app/app/settings/statusBarSettings.js
Normal 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};
|
|
@ -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\"",
|
||||
|
|
103
desktop-app/resources/globe.svg
Normal file
103
desktop-app/resources/globe.svg
Normal 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 |
Loading…
Reference in a new issue