mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-02 15:38:15 +00:00
Redesign (#6080)
* [top bar, side panel] modified UI of the top bar; redesigned the side panel(moved the content in the bottom to the side nav) * [font icons] updated the 'department' & 'invite Guest' icons * [linked devices] moved it from the 'home' side panel to the 'settings' page * ['settings' page] redesigned the empty tip for 'linked devices'
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from '@gatsbyjs/reach-router';
|
||||
import { gettext, siteRoot, canAddRepo, canGenerateShareLink, canGenerateUploadLink, canInvitePeople } from '../utils/constants';
|
||||
import { gettext, siteRoot, canAddRepo, canGenerateShareLink, canGenerateUploadLink, canInvitePeople,
|
||||
enableTC, sideNavFooterCustomHtml, additionalAppBottomLinks
|
||||
} from '../utils/constants';
|
||||
import { seafileAPI } from '../utils/seafile-api';
|
||||
import { Utils } from '../utils/utils';
|
||||
import toaster from './toast';
|
||||
@@ -83,7 +85,7 @@ class MainSideNav extends React.Component {
|
||||
className={`nav-link ellipsis ${this.getActiveClass(item.name)}`}
|
||||
onClick={(e) => this.tabItemClick(e, item.name, item.id)}
|
||||
>
|
||||
<span className={`${item.parent_group_id == 0 ? 'sf3-font-group sf3-font' : 'fas fa-building'} nav-icon`} aria-hidden="true"></span>
|
||||
<span className={`${item.parent_group_id == 0 ? 'sf3-font-group' : 'sf3-font-department'} sf3-font nav-icon`} aria-hidden="true"></span>
|
||||
<span className="nav-text">{item.name}</span>
|
||||
</Link>
|
||||
</li>
|
||||
@@ -181,6 +183,7 @@ class MainSideNav extends React.Component {
|
||||
return (
|
||||
<div className="side-nav">
|
||||
<div className="side-nav-con">
|
||||
<h2 className="mb-2 px-2 font-weight-normal heading">{gettext('Workspace')}</h2>
|
||||
<ul className="nav nav-pills flex-column nav-container">
|
||||
<li className="nav-item flex-column" id="files">
|
||||
<Link to={ siteRoot + 'libraries/' } className={`nav-link ellipsis ${this.getActiveClass('libraries')}`} title={gettext('Files')} onClick={(e) => this.tabItemClick(e, 'libraries')}>
|
||||
@@ -235,19 +238,13 @@ class MainSideNav extends React.Component {
|
||||
<span className="nav-text">{gettext('Wikis')}</span>
|
||||
</Link>
|
||||
</li>
|
||||
{canInvitePeople &&
|
||||
<li className="nav-item">
|
||||
<Link className={`nav-link ellipsis ${this.getActiveClass('linked-devices')}`} to={siteRoot + 'linked-devices/'} title={gettext('Linked Devices')} onClick={(e) => this.tabItemClick(e, 'linked-devices')}>
|
||||
<span className="sf3-font-devices sf3-font" aria-hidden="true"></span>
|
||||
<span className="nav-text">{gettext('Linked Devices')}</span>
|
||||
<Link className={`nav-link ellipsis ${this.getActiveClass('invitations')}`} to={siteRoot + 'invitations/'} title={gettext('Invite Guest')} onClick={(e) => this.tabItemClick(e, 'invitations')}>
|
||||
<span className="sf3-font-invite-visitors sf3-font" aria-hidden="true"></span>
|
||||
<span className="nav-text">{gettext('Invite Guest')}</span>
|
||||
</Link>
|
||||
</li>
|
||||
{canInvitePeople &&
|
||||
<li className="nav-item">
|
||||
<Link className={`nav-link ellipsis ${this.getActiveClass('invitations')}`} to={siteRoot + 'invitations/'} title={gettext('Invite Guest')} onClick={(e) => this.tabItemClick(e, 'invitations')}>
|
||||
<span className="sf2-icon-invite" aria-hidden="true"></span>
|
||||
<span className="nav-text">{gettext('Invite Guest')}</span>
|
||||
</Link>
|
||||
</li>
|
||||
}
|
||||
<li className="nav-item flex-column" id="share-admin-nav">
|
||||
<a className="nav-link ellipsis" title={gettext('Share Admin')} onClick={this.shExtend}>
|
||||
@@ -259,6 +256,47 @@ class MainSideNav extends React.Component {
|
||||
</li>
|
||||
{customNavItems && this.renderCustomNavItems()}
|
||||
</ul>
|
||||
|
||||
<h2 className="mb-2 pt-1 px-2 font-weight-normal heading">{gettext('Help and resources')}</h2>
|
||||
{sideNavFooterCustomHtml ? (
|
||||
<div className='side-nav-footer' dangerouslySetInnerHTML={{__html: sideNavFooterCustomHtml}}></div>
|
||||
) : (
|
||||
<ul className="nav nav-pills flex-column nav-container">
|
||||
<li className="nav-item">
|
||||
<a className={'nav-link'} href={siteRoot + 'help/'} title={gettext('Help')}>
|
||||
<span className="sf3-font-help sf3-font" aria-hidden="true"></span>
|
||||
<span className="nav-text">{gettext('Help')}</span>
|
||||
</a>
|
||||
</li>
|
||||
{enableTC &&
|
||||
<li className="nav-item">
|
||||
<a href={`${siteRoot}terms/`} className="nav-link">
|
||||
<span className="sf3-font-terms sf3-font" aria-hidden="true"></span>
|
||||
<span className="nav-text">{gettext('Terms')}</span>
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
{additionalAppBottomLinks && (
|
||||
<>
|
||||
{Object.keys(additionalAppBottomLinks).map((key, index) => {
|
||||
return (
|
||||
<a className="nav-link" href={additionalAppBottomLinks[key]}>
|
||||
<span className="sf3-font-terms sf3-font" aria-hidden="true"></span>
|
||||
<span className="nav-text">{key}</span>
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
<li className="nav-item">
|
||||
<a href={siteRoot + 'download_client_program/'} className="nav-link">
|
||||
<span className="sf3-font-devices sf3-font" aria-hidden="true"></span>
|
||||
<span className="nav-text">{gettext('Clients')}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@@ -1,57 +0,0 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { gettext, siteRoot, enableTC, sideNavFooterCustomHtml, additionalAppBottomLinks } from '../utils/constants';
|
||||
import ModalPortal from './modal-portal';
|
||||
import AboutDialog from './dialog/about-dialog';
|
||||
|
||||
class SideNavFooter extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isAboutDialogShow: false,
|
||||
};
|
||||
}
|
||||
|
||||
onAboutDialogToggle = (e) => {
|
||||
e.preventDefault();
|
||||
this.setState({isAboutDialogShow: !this.state.isAboutDialogShow});
|
||||
};
|
||||
|
||||
renderExternalAppLinks = () => {
|
||||
if (additionalAppBottomLinks && (typeof additionalAppBottomLinks) === 'object') {
|
||||
let keys = Object.keys(additionalAppBottomLinks);
|
||||
return keys.map((key, index) => {
|
||||
return <a key={index} className="item" href={additionalAppBottomLinks[key]}>{key}</a>;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
render() {
|
||||
|
||||
if (sideNavFooterCustomHtml) {
|
||||
return (<div className='side-nav-footer' dangerouslySetInnerHTML={{__html: sideNavFooterCustomHtml}}></div>);
|
||||
}
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="side-nav-footer flex-wrap">
|
||||
<a href={siteRoot + 'help/'} target="_blank" rel="noopener noreferrer" className="item">{gettext('Help')}</a>
|
||||
<a href="#" className="item" onClick={this.onAboutDialogToggle}>{gettext('About')}</a>
|
||||
{enableTC && <a href={`${siteRoot}terms/`} className="item">{gettext('Terms')}</a>}
|
||||
{this.renderExternalAppLinks()}
|
||||
<a href={siteRoot + 'download_client_program/'} className={`item ${additionalAppBottomLinks ? '' : 'last-item'}`}>
|
||||
<span aria-hidden="true" className="sf2-icon-monitor vam"></span>{' '}
|
||||
<span className="vam">{gettext('Clients')}</span>
|
||||
</a>
|
||||
</div>
|
||||
{this.state.isAboutDialogShow && (
|
||||
<ModalPortal>
|
||||
<AboutDialog onCloseAboutDialog={this.onAboutDialogToggle} />
|
||||
</ModalPortal>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SideNavFooter;
|
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Logo from './logo';
|
||||
import MainSideNav from './main-side-nav';
|
||||
import SideNavFooter from './side-nav-footer';
|
||||
|
||||
const propTypes = {
|
||||
isSidePanelClosed: PropTypes.bool.isRequired,
|
||||
@@ -22,9 +21,6 @@ class SidePanel extends React.Component {
|
||||
<div className="side-panel-center">
|
||||
<MainSideNav tabItemClick={this.props.tabItemClick} currentTab={this.props.currentTab} />
|
||||
</div>
|
||||
<div className="side-panel-footer">
|
||||
<SideNavFooter />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
240
frontend/src/components/user-settings/linked-devices.js
Normal file
240
frontend/src/components/user-settings/linked-devices.js
Normal file
@@ -0,0 +1,240 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import moment from 'moment';
|
||||
import { Dropdown, DropdownToggle, DropdownItem } from 'reactstrap';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
import { gettext } from '../../utils/constants';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import toaster from '../../components/toast';
|
||||
import ConfirmUnlinkDeviceDialog from '../../components/dialog/confirm-unlink-device';
|
||||
|
||||
class Content extends Component {
|
||||
|
||||
render() {
|
||||
const { loading, errorMsg, items } = this.props;
|
||||
|
||||
if (loading) {
|
||||
return <span className="loading-icon loading-tip"></span>;
|
||||
} else if (errorMsg) {
|
||||
return <p className="error text-center">{errorMsg}</p>;
|
||||
} else {
|
||||
const emptyTip = (
|
||||
<p>{gettext('No linked devices. You have not accessed your files with any client (desktop or mobile) yet. Configure clients on your devices to access your data more comfortably.')}</p>
|
||||
);
|
||||
|
||||
const desktopThead = (
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="13%">{gettext('Platform')}</th>
|
||||
<th width="30%">{gettext('Device Name')}</th>
|
||||
<th width="30%">{gettext('IP')}</th>
|
||||
<th width="17%">{gettext('Last Access')}</th>
|
||||
<th width="10%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
);
|
||||
const mobileThead = (
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="92%"></th>
|
||||
<th width="8%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
);
|
||||
|
||||
const isDesktop = Utils.isDesktop();
|
||||
return items.length ? (
|
||||
<table className={`table-hover ${isDesktop ? '': 'table-thead-hidden'}`}>
|
||||
{isDesktop ? desktopThead : mobileThead}
|
||||
<tbody>
|
||||
{items.map((item, index) => {
|
||||
return <Item key={index} data={item} isDesktop={isDesktop} />;
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
): emptyTip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Content.propTypes = {
|
||||
loading: PropTypes.bool.isRequired,
|
||||
errorMsg: PropTypes.string.isRequired,
|
||||
items: PropTypes.array.isRequired
|
||||
};
|
||||
|
||||
class Item extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isOpMenuOpen: false, // for mobile
|
||||
isOpIconShown: false,
|
||||
unlinked: false,
|
||||
isConfirmUnlinkDialogOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
toggleOpMenu = () => {
|
||||
this.setState({
|
||||
isOpMenuOpen: !this.state.isOpMenuOpen
|
||||
});
|
||||
};
|
||||
|
||||
handleMouseOver = () => {
|
||||
this.setState({
|
||||
isOpIconShown: true
|
||||
});
|
||||
};
|
||||
|
||||
handleMouseOut = () => {
|
||||
this.setState({
|
||||
isOpIconShown: false
|
||||
});
|
||||
};
|
||||
|
||||
toggleDialog = () => {
|
||||
this.setState({
|
||||
isConfirmUnlinkDialogOpen: !this.state.isConfirmUnlinkDialogOpen
|
||||
});
|
||||
};
|
||||
|
||||
handleClick = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const data = this.props.data;
|
||||
if (data.is_desktop_client) {
|
||||
this.toggleDialog();
|
||||
} else {
|
||||
const wipeDevice = true;
|
||||
this.unlinkDevice(wipeDevice);
|
||||
}
|
||||
};
|
||||
|
||||
unlinkDevice = (wipeDevice) => {
|
||||
const data = this.props.data;
|
||||
seafileAPI.unlinkDevice(data.platform, data.device_id, wipeDevice).then((res) => {
|
||||
this.setState({
|
||||
unlinked: true
|
||||
});
|
||||
let msg = gettext('Successfully unlinked %(name)s.');
|
||||
msg = msg.replace('%(name)s', data.device_name);
|
||||
toaster.success(msg);
|
||||
}).catch((error) => {
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
toaster.danger(errMessage);
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
if (this.state.unlinked) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = this.props.data;
|
||||
|
||||
let opClasses = 'sf2-icon-delete unlink-device action-icon';
|
||||
opClasses += this.state.isOpIconShown ? '' : ' invisible';
|
||||
|
||||
const desktopItem = (
|
||||
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} onFocus={this.handleMouseOver}>
|
||||
<td>{data.platform}</td>
|
||||
<td>{data.device_name}</td>
|
||||
<td>{data.last_login_ip}</td>
|
||||
<td>{moment(data.last_accessed).fromNow()}</td>
|
||||
<td>
|
||||
<a href="#" className={opClasses} title={gettext('Unlink')} role="button" aria-label={gettext('Unlink')} onClick={this.handleClick}></a>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
|
||||
const mobileItem = (
|
||||
<tr>
|
||||
<td>
|
||||
{data.device_name}<br />
|
||||
<span className="item-meta-info">{data.last_login_ip}</span>
|
||||
<span className="item-meta-info">{moment(data.last_accessed).fromNow()}</span>
|
||||
<span className="item-meta-info">{data.platform}</span>
|
||||
</td>
|
||||
<td>
|
||||
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
|
||||
<DropdownToggle
|
||||
tag="i"
|
||||
className="sf-dropdown-toggle fa fa-ellipsis-v ml-0"
|
||||
title={gettext('More operations')}
|
||||
aria-label={gettext('More operations')}
|
||||
data-toggle="dropdown"
|
||||
aria-expanded={this.state.isOpMenuOpen}
|
||||
/>
|
||||
<div className={this.state.isOpMenuOpen ? '' : 'd-none'} onClick={this.toggleOpMenu}>
|
||||
<div className="mobile-operation-menu-bg-layer"></div>
|
||||
<div className="mobile-operation-menu">
|
||||
<DropdownItem className="mobile-menu-item" onClick={this.handleClick}>{gettext('Unlink')}</DropdownItem>
|
||||
</div>
|
||||
</div>
|
||||
</Dropdown>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{this.props.isDesktop ? desktopItem : mobileItem}
|
||||
{this.state.isConfirmUnlinkDialogOpen &&
|
||||
<ConfirmUnlinkDeviceDialog
|
||||
executeOperation={this.unlinkDevice}
|
||||
toggleDialog={this.toggleDialog}
|
||||
/>
|
||||
}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Item.propTypes = {
|
||||
isDesktop: PropTypes.bool.isRequired,
|
||||
data: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
class LinkedDevices extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loading: true,
|
||||
errorMsg: '',
|
||||
items: []
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
seafileAPI.listLinkedDevices().then((res) => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
items: res.data
|
||||
});
|
||||
}).catch((error) => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
errorMsg: Utils.getErrorMsg(error, true) // true: show login tip if 403
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { loading, errorMsg, items } = this.state;
|
||||
return (
|
||||
<div className="setting-item" id="linked-devices">
|
||||
<h3 className="setting-item-heading">{gettext('Linked Devices')}</h3>
|
||||
<div className="cur-view-content">
|
||||
<Content
|
||||
loading={loading}
|
||||
errorMsg={errorMsg}
|
||||
items={items}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default LinkedDevices;
|
@@ -52,8 +52,9 @@
|
||||
padding: .5rem 1rem;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
background: #f4f4f7;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0, 10%);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
@@ -94,7 +95,7 @@
|
||||
position: relative; /* for the ':after' */
|
||||
padding: 8px 16px;
|
||||
max-height: 40px;
|
||||
background:#f9f9f9;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
|
@@ -76,7 +76,7 @@ class GroupItem extends React.Component {
|
||||
<div className="pb-3">
|
||||
<div className="d-flex justify-content-between mt-3 py-1 sf-border-bottom">
|
||||
<h4 className="sf-heading m-0 ellipsis">
|
||||
<span className={`${group.parent_group_id == 0 ? 'sf3-font-group sf3-font' : 'fas fa-building'} nav-icon`} aria-hidden="true"></span>
|
||||
<span className={`${group.parent_group_id == 0 ? 'sf3-font-group' : 'sf3-font-department'} sf3-font nav-icon`} aria-hidden="true"></span>
|
||||
<a href={`${siteRoot}group/${group.id}/`} title={group.name}>{group.name}</a>
|
||||
</h4>
|
||||
</div>
|
||||
|
@@ -429,7 +429,7 @@ class GroupView extends React.Component {
|
||||
<span>{currentGroup.name}</span>
|
||||
{isDepartmentGroup && (
|
||||
<Fragment>
|
||||
<span className="department-group-icon fas fa-building" title={gettext('This is a special group representing a department.')}></span>
|
||||
<span className="department-group-icon sf3-font-department sf3-font" title={gettext('This is a special group representing a department.')}></span>
|
||||
{currentGroup.group_quota > 0 &&
|
||||
<span className="department-usage-container">
|
||||
<div className="department-usage">
|
||||
|
@@ -18,6 +18,7 @@ import TwoFactorAuthentication from './components/user-settings/two-factor-auth'
|
||||
import SocialLogin from './components/user-settings/social-login';
|
||||
import SocialLoginDingtalk from './components/user-settings/social-login-dingtalk';
|
||||
import SocialLoginSAML from './components/user-settings/social-login-saml';
|
||||
import LinkedDevices from './components/user-settings/linked-devices';
|
||||
import DeleteAccount from './components/user-settings/delete-account';
|
||||
|
||||
import './css/toolbar.css';
|
||||
@@ -53,6 +54,7 @@ class Settings extends React.Component {
|
||||
{show: isPro, href: '#email-notice', text: gettext('Email Notification')},
|
||||
{show: twoFactorAuthEnabled, href: '#two-factor-auth', text: gettext('Two-Factor Authentication')},
|
||||
{show: (enableWechatWork || enableDingtalk || enableADFS || (enableMultiADFS || isOrgContext)), href: '#social-auth', text: gettext('Social Login')},
|
||||
{show: true, href: '#linked-devices', text: gettext('Linked Devices')},
|
||||
{show: enableDeleteAccount, href: '#del-account', text: gettext('Delete Account')},
|
||||
];
|
||||
|
||||
@@ -146,6 +148,7 @@ class Settings extends React.Component {
|
||||
{enableWechatWork && <SocialLogin />}
|
||||
{enableDingtalk && <SocialLoginDingtalk />}
|
||||
{(enableADFS || (enableMultiADFS && isOrgContext)) && <SocialLoginSAML />}
|
||||
<LinkedDevices />
|
||||
{enableDeleteAccount && <DeleteAccount />}
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -653,6 +653,11 @@ a, a:hover { color: #ec8000; }
|
||||
margin-left:auto;
|
||||
}
|
||||
|
||||
.side-nav-con .heading {
|
||||
font-size: .9375rem;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.side-nav-con>.nav {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
@font-face {
|
||||
font-family: "sf3-font"; /* Project id 1230969 */
|
||||
src: url('iconfont.eot?t=1714979170396'); /* IE9 */
|
||||
src: url('iconfont.eot?t=1714979170396#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('iconfont.woff2?t=1714979170396') format('woff2'),
|
||||
url('iconfont.woff?t=1714979170396') format('woff'),
|
||||
url('iconfont.ttf?t=1714979170396') format('truetype'),
|
||||
url('iconfont.svg?t=1714979170396#sf3-font') format('svg');
|
||||
src: url('iconfont.eot?t=1715225728872'); /* IE9 */
|
||||
src: url('iconfont.eot?t=1715225728872#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('iconfont.woff2?t=1715225728872') format('woff2'),
|
||||
url('iconfont.woff?t=1715225728872') format('woff'),
|
||||
url('iconfont.ttf?t=1715225728872') format('truetype'),
|
||||
url('iconfont.svg?t=1715225728872#sf3-font') format('svg');
|
||||
}
|
||||
|
||||
.sf3-font {
|
||||
@@ -16,6 +16,30 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.sf3-font-clients:before {
|
||||
content: "\e80f";
|
||||
}
|
||||
|
||||
.sf3-font-about:before {
|
||||
content: "\e810";
|
||||
}
|
||||
|
||||
.sf3-font-terms:before {
|
||||
content: "\e811";
|
||||
}
|
||||
|
||||
.sf3-font-help:before {
|
||||
content: "\e812";
|
||||
}
|
||||
|
||||
.sf3-font-invite-visitors:before {
|
||||
content: "\e80e";
|
||||
}
|
||||
|
||||
.sf3-font-department:before {
|
||||
content: "\e80d";
|
||||
}
|
||||
|
||||
.sf3-font-starred:before {
|
||||
content: "\e80b";
|
||||
}
|
||||
|
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -14,6 +14,18 @@
|
||||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="clients" unicode="" d="M937.6 800c12.8 0 22.4-9.6 22.4-22.4v-611.2c0-12.8-9.6-22.4-22.4-22.4h-300.8v-41.6c0-32 28.8-64 64-64h41.6v-83.2H291.2v83.2h41.6c32 0 64 28.8 64 64v41.6H86.4c-12.8 0-22.4 9.6-22.4 22.4V777.6c0 12.8 9.6 22.4 22.4 22.4h851.2z m-57.6-83.2h-736v-409.6h736V716.8z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="about" unicode="" d="M512 864c265.6 0 480-214.4 480-480s-214.4-480-480-480S32 118.4 32 384 246.4 864 512 864z m12.8-384h-25.6c-28.8 0-51.2-22.4-51.2-48v-288c0-25.6 22.4-48 51.2-48h25.6c28.8 0 51.2 22.4 51.2 48v288c0 25.6-22.4 48-51.2 48zM512 672c-35.2 0-64-28.8-64-64s28.8-64 64-64 64 28.8 64 64-28.8 64-64 64z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="terms" unicode="" d="M768 832c35.2 0 64-28.8 64-64v-121.6L448 272v-166.4h153.6l230.4 224V0c0-35.2-28.8-64-64-64H128c-35.2 0-64 28.8-64 64V768c0 35.2 28.8 64 64 64h640zM275.2 217.6h-3.2c-25.6-3.2-57.6-25.6-96-70.4-25.6-32-44.8-60.8-44.8-64-6.4-6.4-3.2-19.2 6.4-22.4 3.2 0 3.2-3.2 6.4-3.2 6.4 0 16 3.2 19.2 9.6 35.2 54.4 86.4 115.2 112 118.4h3.2s6.4-6.4 0-32v-3.2c-3.2-12.8-12.8-54.4 19.2-67.2h6.4c28.8-3.2 44.8 19.2 57.6 32 0 0 0 3.2 3.2 3.2l6.4 6.4h3.2c-6.4-16-3.2-35.2 9.6-44.8 6.4-6.4 19.2-9.6 28.8-9.6 25.6 3.2 35.2 28.8 38.4 38.4 6.4 16 0 22.4-6.4 25.6-9.6 3.2-19.2 0-25.6-6.4-3.2-3.2-6.4-6.4-6.4-9.6 3.2 12.8 6.4 35.2-12.8 48-32 16-57.6-19.2-67.2-28.8-6.4-9.6-9.6-12.8-12.8-12.8h-3.2c0 3.2-3.2 9.6 0 22.4v3.2c3.2 16 9.6 38.4-6.4 57.6-6.4 9.6-16 12.8-28.8 12.8l-6.4-3.2z m515.2 304c6.4 6.4 16 6.4 19.2 3.2l54.4-54.4c3.2-3.2 3.2-12.8-3.2-19.2l-281.6-281.6c-6.4-6.4-16-6.4-19.2-3.2l-73.6-19.2 19.2 73.6c-3.2 3.2-3.2 12.8 3.2 19.2l281.6 281.6zM480 480H224v-96h256v96z m403.2 134.4c6.4 6.4 16 6.4 22.4 0l51.2-51.2c6.4-6.4 6.4-16 0-22.4L896 483.2c-6.4-6.4-16-6.4-22.4 0l-51.2 51.2c-6.4 6.4-6.4 16 0 22.4l60.8 57.6zM672 672H224v-96h448V672z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="help" unicode="" d="M512 864c262.4 0 480-217.6 480-480s-217.6-480-480-480S32 121.6 32 384 249.6 864 512 864z m32-649.6h-64c-9.6 0-16-6.4-16-16v-67.2c0-9.6 6.4-16 16-16h64c9.6 0 16 6.4 16 16v67.2c0 6.4-6.4 16-16 16zM512 652.8c-44.8 0-83.2-16-115.2-38.4-28.8-25.6-48-64-51.2-108.8 0-6.4 0-9.6 3.2-12.8s9.6-6.4 12.8-6.4h64c9.6 0 16 6.4 16 16 9.6 51.2 28.8 73.6 73.6 73.6 22.4 0 38.4-6.4 51.2-19.2s19.2-28.8 19.2-48c0-9.6-3.2-22.4-6.4-25.6s-12.8-19.2-41.6-41.6c-25.6-22.4-44.8-44.8-54.4-64-9.6-22.4-16-51.2-16-92.8 0-9.6 6.4-16 16-16h57.6c9.6 0 16 6.4 16 16 0 32 3.2 51.2 6.4 57.6s16 22.4 44.8 44.8c25.6 25.6 48 44.8 57.6 64 9.6 22.4 16 41.6 16 67.2 3.2 28.8-16 70.4-44.8 96-35.2 25.6-73.6 38.4-124.8 38.4z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="invite-visitors" unicode="" d="M384 288c214.4 0 384-118.4 384-262.4 0-102.4-48-121.6-374.4-121.6h-25.6C44.8-96 0-76.8 0 25.6 0 172.8 169.6 288 384 288zM864 630.4v-166.4h160v-96h-160v-169.6h-86.4v169.6h-156.8v96h156.8V630.4H864zM384 864c108.8 0 195.2-96 195.2-211.2s-73.6-313.6-195.2-313.6-195.2 195.2-195.2 313.6S278.4 864 384 864z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="department" unicode="" d="M790.4 864c25.6 0 48-9.6 67.2-25.6 19.2-19.2 28.8-41.6 28.8-67.2v-800H928c16 0 32-12.8 32-32 0-16-12.8-38.4-32-38.4L96-96c-16 0-32 19.2-32 38.4s12.8 32 32 32h44.8V771.2c0 25.6 9.6 48 28.8 67.2S211.2 864 236.8 864h553.6zM576 160h-128v-192h128v192z m-160 192H288v-128h128v128z m320 0h-128v-128h128v128z m-320 192H288v-128h128v128z m320 0h-128v-128h128v128z m0 192h-128v-128h128V736zM416 736H288v-128h128V736z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="starred" unicode="" d="M537.6 816l128-256c3.2-9.6 12.8-12.8 19.2-16l284.8-41.6c22.4-3.2 32-32 16-48L777.6 256c-6.4-6.4-9.6-16-6.4-25.6l48-281.6c3.2-22.4-19.2-38.4-38.4-28.8l-252.8 134.4c-6.4 3.2-16 3.2-25.6 0l-252.8-134.4c-19.2-9.6-44.8 6.4-38.4 28.8l48 281.6c0 9.6 0 19.2-6.4 25.6l-204.8 201.6c-16 16-6.4 44.8 16 48l284.8 41.6c9.6 0 16 6.4 19.2 16l128 256c0 19.2 32 19.2 41.6-3.2z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="devices" unicode="" d="M937.6 800c12.8 0 22.4-9.6 22.4-22.4v-611.2c0-12.8-9.6-22.4-22.4-22.4h-300.8v-41.6c0-32 28.8-64 64-64h41.6v-83.2H291.2v83.2h41.6c32 0 64 28.8 64 64v41.6H86.4c-12.8 0-22.4 9.6-22.4 22.4V777.6c0 12.8 9.6 22.4 22.4 22.4h851.2z m-57.6-83.2h-736v-409.6h736V716.8z" horiz-adv-x="1024" />
|
||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 39 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user