1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-02 15:38:15 +00:00

File view op (#4836)

* [file view] added 'Details' & 'open via client'

* [file view] adjusted places of operations

* [file view] 'open via client': use a new icon

* [file view] 'open via client': updated the icon
This commit is contained in:
llj
2021-03-18 17:31:21 +08:00
committed by GitHub
parent 2405ba671e
commit 06254447e4
12 changed files with 232 additions and 27 deletions

View File

@@ -0,0 +1,127 @@
import React from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import { siteRoot, gettext } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import toaster from '../toast';
import FileTag from '../../models/file-tag';
import '../../css/dirent-detail.css';
const propTypes = {
repoID: PropTypes.string.isRequired,
repoName: PropTypes.string.isRequired,
dirent: PropTypes.object.isRequired,
path: PropTypes.string.isRequired,
togglePanel: PropTypes.func.isRequired
};
class FileDetails extends React.Component {
constructor(props) {
super(props);
this.state = {
direntType: '',
direntDetail: '',
fileTagList: []
};
}
componentDidMount() {
let { dirent, path, repoID } = this.props;
let direntPath = Utils.joinPath(path, dirent.name);
seafileAPI.getFileInfo(repoID, direntPath).then(res => {
this.setState({
direntType: 'file',
direntDetail: res.data
});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
seafileAPI.listFileTags(repoID, direntPath).then(res => {
let fileTagList = [];
res.data.file_tags.forEach(item => {
let file_tag = new FileTag(item);
fileTagList.push(file_tag);
});
this.setState({fileTagList: fileTagList});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}
renderHeader = (smallIconUrl, direntName) => {
return (
<div className="detail-header">
<div className="detail-control sf2-icon-x1" onClick={this.props.togglePanel}></div>
<div className="detail-title dirent-title">
<img src={smallIconUrl} width="24" height="24" alt="" />{' '}
<span className="name ellipsis" title={direntName}>{direntName}</span>
</div>
</div>
);
}
renderDetailBody = (bigIconUrl) => {
const { direntDetail, fileTagList } = this.state;
const { repoName, path } = this.props;
return (
<div className="detail-body dirent-info">
<div className="img"><img src={bigIconUrl} className="thumbnail" alt="" /></div>
{this.state.direntDetail &&
<div className="dirent-table-container">
<table className="table-thead-hidden">
<thead>
<tr><th width="35%"></th><th width="65%"></th></tr>
</thead>
<tbody>
<tr><th>{gettext('Size')}</th><td>{Utils.bytesToSize(direntDetail.size)}</td></tr>
<tr><th>{gettext('Location')}</th><td>{repoName + path}</td></tr>
<tr><th>{gettext('Last Update')}</th><td>{moment(direntDetail.last_modified).fromNow()}</td></tr>
<tr className="file-tag-container">
<th>{gettext('Tags')}</th>
<td>
<ul className="file-tag-list">
{fileTagList.map((fileTag) => {
return (
<li key={fileTag.id} className="file-tag-item">
<span className="file-tag" style={{backgroundColor:fileTag.color}}></span>
<span className="tag-name" title={fileTag.name}>{fileTag.name}</span>
</li>
);
})}
</ul>
</td>
</tr>
</tbody>
</table>
</div>
}
</div>
);
}
render() {
let { dirent, repoID, path } = this.props;
const smallIconUrl = Utils.getFileIconUrl(dirent.name);
let bigIconUrl = Utils.getFileIconUrl(dirent.name, 192);
const isImg = Utils.imageCheck(dirent.name);
if (isImg) {
bigIconUrl = `${siteRoot}thumbnail/${repoID}/1024` + Utils.encodePath(`${path === '/' ? '' : path}/${dirent.name}`);
}
return (
<div className="detail-container file-details-container">
{this.renderHeader(smallIconUrl, dirent.name)}
{this.renderDetailBody(bigIconUrl)}
</div>
);
}
}
FileDetails.propTypes = propTypes;
export default FileDetails;

View File

@@ -1,6 +1,6 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { ButtonGroup, Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import { ButtonGroup, ButtonDropdown, Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import IconButton from '../icon-button';
import { gettext, siteRoot } from '../../utils/constants';
import { Utils } from '../../utils/utils';
@@ -14,11 +14,12 @@ const propTypes = {
isSaving: PropTypes.bool,
needSave: PropTypes.bool,
toggleLockFile: PropTypes.func.isRequired,
toggleCommentPanel: PropTypes.func.isRequired
toggleCommentPanel: PropTypes.func.isRequired,
toggleDetailsPanel: PropTypes.func.isRequired
};
const {
canLockUnlockFile, canGenerateShareLink,
canLockUnlockFile,
repoID, repoName, repoEncrypted, parentDir, filePerm, filePath,
fileName,
canEditFile, err,
@@ -32,7 +33,8 @@ class FileToolbar extends React.Component {
super(props);
this.state = {
dropdownOpen: false,
isShareDialogOpen: false
moreDropdownOpen: false,
isShareDialogOpen: false,
};
}
@@ -40,14 +42,25 @@ class FileToolbar extends React.Component {
this.setState({isShareDialogOpen: !this.state.isShareDialogOpen});
}
toggleMoreOpMenu = () => {
this.setState({
moreDropdownOpen: !this.state.moreDropdownOpen
});
}
toggle = () => {
this.setState({
dropdownOpen: !this.state.dropdownOpen
});
}
openFileViaClient = () => {
location.href = `seafile://openfile?repo_id=${encodeURIComponent(repoID)}&path=${encodeURIComponent(filePath)}`;
}
render() {
const { isLocked, lockedByMe } = this.props;
const { moreDropdownOpen } = this.state;
let showLockUnlockBtn = false;
let lockUnlockText, lockUnlockIcon;
if (canLockUnlockFile) {
@@ -95,15 +108,7 @@ class FileToolbar extends React.Component {
onClick={this.toggleShareDialog}
/>
)}
{filePerm == 'rw' && (
<IconButton
id="history"
icon="fa fa-history"
text={gettext('History')}
tag="a"
href={`${siteRoot}repo/file_revisions/${repoID}/?p=${encodeURIComponent(filePath)}`}
/>
)}
{(canEditFile && !err) &&
( this.props.isSaving ?
<button type={'button'} className={'btn btn-icon btn-secondary btn-active'}>
@@ -132,14 +137,40 @@ class FileToolbar extends React.Component {
href="?dl=1"
/>
)}
{enableComment && (
<IconButton
id="file-details"
icon='fas fa-info'
text={gettext('Details')}
onClick={this.props.toggleDetailsPanel}
/>
{filePerm == 'rw' && (
<IconButton
id="comment"
icon="fa fa-comments"
text={gettext('Comment')}
onClick={this.props.toggleCommentPanel}
id="open-via-client"
icon="sf3-font sf3-font-desktop"
text={gettext('Open via Client')}
tag="a"
href={`seafile://openfile?repo_id=${encodeURIComponent(repoID)}&path=${encodeURIComponent(filePath)}`}
/>
)}
<ButtonDropdown isOpen={moreDropdownOpen} toggle={this.toggleMoreOpMenu}>
<DropdownToggle>
<span className="fas fa-ellipsis-v"></span>
</DropdownToggle>
<DropdownMenu right={true}>
{enableComment && (
<DropdownItem onClick={this.props.toggleCommentPanel}>
{gettext('Comment')}
</DropdownItem>
)}
{filePerm == 'rw' && (
<DropdownItem>
<a href={`${siteRoot}repo/file_revisions/${repoID}/?p=${encodeURIComponent(filePath)}&referer=${encodeURIComponent(location.href)}`} className="text-inherit">
{gettext('History')}
</a>
</DropdownItem>
)}
</DropdownMenu>
</ButtonDropdown>
</ButtonGroup>
<Dropdown isOpen={this.state.dropdownOpen} toggle={this.toggle} className="d-block d-md-none">
@@ -202,6 +233,7 @@ class FileToolbar extends React.Component {
{gettext('Comment')}
</DropdownItem>
)}
<DropdownItem onClick={this.props.toggleDetailsPanel}>{gettext('Details')}</DropdownItem>
</DropdownMenu>
</Dropdown>

View File

@@ -8,6 +8,7 @@ import toaster from '../toast';
import FileInfo from './file-info';
import FileToolbar from './file-toolbar';
import CommentPanel from './comment-panel';
import FileDetails from '../dirent-detail/file-details';
import '../../css/file-view.css';
@@ -21,7 +22,8 @@ const propTypes = {
};
const { isStarred, isLocked, lockedByMe,
repoID, filePath, enableWatermark, userNickName
repoID, filePath, enableWatermark, userNickName,
repoName, parentDir, fileName
} = window.app.pageOptions;
@@ -34,9 +36,14 @@ class FileView extends React.Component {
isLocked: isLocked,
lockedByMe: lockedByMe,
isCommentPanelOpen: false,
isDetailsPanelOpen: false
};
}
toggleDetailsPanel = () => {
this.setState({isDetailsPanelOpen: !this.state.isDetailsPanelOpen});
}
toggleCommentPanel = () => {
this.setState({
isCommentPanelOpen: !this.state.isCommentPanelOpen
@@ -90,6 +97,7 @@ class FileView extends React.Component {
}
render() {
const { isDetailsPanelOpen } = this.state;
return (
<div className="h-100 d-flex flex-column">
<div className="file-view-header d-flex justify-content-between align-items-center">
@@ -106,6 +114,7 @@ class FileView extends React.Component {
needSave={this.props.needSave}
toggleLockFile={this.toggleLockFile}
toggleCommentPanel={this.toggleCommentPanel}
toggleDetailsPanel={this.toggleDetailsPanel}
/>
</div>
<div className="file-view-body flex-auto d-flex o-hidden">
@@ -117,6 +126,15 @@ class FileView extends React.Component {
onParticipantsChange={this.props.onParticipantsChange}
/>
}
{isDetailsPanelOpen &&
<FileDetails
repoID={repoID}
repoName={repoName}
path={parentDir}
dirent={{'name': fileName, type: 'file'}}
togglePanel={this.toggleDetailsPanel}
/>
}
</div>
</div>
);

View File

@@ -29,7 +29,7 @@ class IconButton extends React.Component {
const className = 'btn-icon';
const btnContent = (
<React.Fragment>
<span className={this.props.icon}></span>
<i className={this.props.icon}></i>
<Tooltip
toggle={this.toggle}
delay={{show: 0, hide: 0}}

View File

@@ -40,6 +40,27 @@ body {
.tip {
color: #808080;
}
.file-details-container {
position: absolute;
right: 0;
background-color: #fff;
width: 300px;
height: 100%;
box-shadow: -1px 0 3px 0 #ccc;
animation: move .5s ease-in-out 1;
z-index: 50;
}
@keyframes move {
from {
right: -500px;
opacity: 0.5;
}
to {
right: 0px;
opacity: 1;
}
}
/* for mobile */
.file-view-body .seafile-comment {
width: 100%;

View File

@@ -1,10 +1,10 @@
@font-face {font-family: "sf3-font";
src: url('iconfont.eot?t=1611200069054'); /* IE9 */
src: url('iconfont.eot?t=1611200069054#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAtcAAsAAAAAFYgAAAsNAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCFGgqaXJUdATYCJANECyQABCAFhG0HgWIb2xEzo7aLkxIh+68S6Cl7tDyjEd62rd06I+0HjEfJ/Llb1zX+M1mkz5iOpzn7ebsbe7vJJkC0jqdNDag4ZvVsgtVDqMOlZ7JpPalfhJTeEfBQtaRQ9QB3zn2Bc08A8Py/t/u2f8YzCySwRJPAAgyxNIKkNDelhLEJJrYHpzan1jVQHj00emZ3sdJffHLFlkcz5JOV9Pr/t9+vKhpFow7eCMVTJ8SZ7yPIxR+qlojQOCSiqDdWNMT1ELduaBtK3VDyWohXnewLYeFUOPJsgABgQxmgNbfYCGIUzhDK7auqloE4EYoqMUHEgULLngXoAgFx20HcB4A93tdHP6REDEAQdOBbzrPmWCC9Hw2oSD7CR4XRAkV/EgC87QdAAjAAoAB6rTHXgQyowePYVp1SC6Ajz/zmj+hfyGwZmxccd94l4QF2QBWJ9CO77lGDZ63hsxGdwUJ3uHbsf+IBsORkpBg0TEJETEiAQiIggAaAM6T/OFcO+pFyByzoJ+Q2sRAAMggzAKQQywDAQNgAQEO8AAAMcRQAEohjABBBHAeAGOI8AIQQlwAggHgGAAoiDHdAggEWgPCECsr9jyvMHrEACgCoDUCwAA/avMSc2Uc5QTEIdcRgHJlCkhBMEaUUMHK5gGIlmJIxrMzCIolYkq46VqtlmAkMJeRGsZRGJKpgOaNmhkpmmBSe5EeOjlEqS6paAkDw7fFMawci7YeSXoHa2G4YYcCoHGhEtwS08K4sAyO27GL0OpUtfLzLoWq1L3E2NsOMoyStcAa0RG3SWEfWyStTqWbrGzyjlq+NcTlaD9jrqp0Bvt3RYT/02oGORFnzeQ3UcoxozjPI20Y7A8ruJFcr976M/ZDaHQC+fSUUfT4H3tUx4AvQ0p4yREPdtVEMSOvqB+EV4bCxu5vr7TX39BhbLvBBx1Fd3SWj2a00elTGukPOC/x5Rwfn9ao5lytmrjMUP37jsWU9/abeAXP3/7nw/xY72oHgAzTtPLQQUgcu+dYHbUR6paa+yScZhHyS0STs8ORTb/GZ6lQmjyPG6PIl0E43AO/C1czvH6SWIo/a61ZWuvkYi6tVjcoANwc1hC+UQAO+2RNr9yCy/tq0NnoinV9dluOVHjaMS6aNZmx2Ncfwp2d6jqqT2sSWSY5wYuvVoR57wplupacnUWYP83iV3MSuONj1GiEFhsAkg6RkuQL6NYJBNJIBDQwZGWOEl5cCBryuqq5e5/Go2JbWjptBv56TNQf5UAJrbMcSgRujHPQGDLQZJZAFYZCuCMDWNCXiZM2wlz6YbDX9ejl75skQ6uDjNNnZp0MF9c9em36RirF2D8Yp+XZbw+lFYzw9Q5t6K1enfEVWKvfaVZ4Yo0lluXglZ9SJbrWZA8lLMjl71+1JKwqMrmbcellnr1Ob949t9Jzv4OHTI02Ur/1VPtTlGp32y4lM8+FSaVuQFARf6FM6Zj+6J2oOI+VIFaJPs7JFH462zpVyW0Sbqsq2dQ4SHLicuGQPBIBXit8I60tp0i9S78r7gsuabbtstX26lHTghNZ34dwx3eFyjda7Iz1ml6b2eLIroFYfupfUduzdi/EOl6l2rS1Jt9zRuw+pVB0ndQdyns/lMnZlNx/Wut3KgHOQF9WdGuVVeRzWcHhe0BDu5nwhvRHcLUrnXny0JHPLDbrX3Nox6HR4Im5N9LhisFG+Iw9SqwcN8h5QXRxztSf12LTO3rxzE250z3Af0foaANrOKJX1PWOOznzaY7p5rBSyFQWKbCj0qk94Lk8PaXL9PL7U3Nzmec16yIYHP8XCfxpZnHhn4a8/sSp7is4OOrtn2m6z6O5p3W5FtqJQ8XHdRaRFdRtyc259+iWFvNL4s5VU9tNNr+7NG9pbtFR13yC0gh8ppDb2iyP81qXDxIf/fDQ3lBVqT9m9KZcWsVGDWZLdJ9wmYlOksriuvhSGjcvUDw9lHdmwPVYYgqqotRlj+zOzQtF/n9zP95MxVctb/x98lWhoIF51sCFaGb1sU8PM0hp2PIz/XpTMbt29KnPml2tzNLmVw8SR8WwKOz4Cktxy7VtZOWvFazQwnh3/SN4HkSV3KLmMukeYIu5QrIpM9tU3bCobrQKyvPDMgzEVOxr8EbWGcW5FJah6876VUuk6N78GBDY4wAmcWRZVoxLn1jWMX3Ifq20lZsXbR0/+5+GQhyf/77RBGYL9GEeF6X+IJLfEX+C64/ixNLysYaKJs0ZZ9V0d7dJw43ezb/VtYQMMlfZB8eNxhRmNAoP4uKGeC46YM8ip6WIjZ8qoEtP02nHyyy9JrTlOBGr6WyS/nLCrQV+458awLVOVpT9f+Im6e33EifMXJhrDE7JFNrhWeXq+IrqtzKvir56fNWv3kDkIpvClyQsTuPj5utVjLSUQT6bzPBpmdVK16QjS0/muLon9sMlETEFPCq/r11b/4NhIKJDqxZhVr1TxHw1O/vqXs99vTy/v6/rxx1w60XJlK4Gg+rs+fu2CT/su9BFfX+u7NtLHIlnThQ36YF9Qei3YJEPs7YlvgwZs672tFHTtzZZ0SbL3ekvA4KalFrRlC7II6y2bLUTI5s3RU23eEr/iL/wp0/Uy4fcTL5vI2qgO/A3zV2JMrixTPlcyiyOes6GFsN5gW0hwG65aY9MyVXLLt58UFM8t/uRbq7yyoKigwKqwfPNxQXF+sSEF2H1ZSUYW/Jmh+Zaev9zmmETXKEQMtyM0cLOE1qR0Dlxjf+hLWfKCcco742xf6KI1MzTRaVE1M/b+OGX3azVRE0JCpx6kJaIndtb8J+2/mk71Tzrtj/B+i6vA65XYn8415eASrlMw05+KeZzq5735oT4yC6wak4xJ9WXwS/OV+/Xf3v4toH5/rY9c2Dz4xZwHlsp0N9GMU4zd879BhQ2xvtjauLTCp5z1ntWEz/o93xv+/TSqWRdXG7sjJbPF8EIut/nC8LLjYc5qVa21gKHv7+hCf+r2HQjP/6BQtGkawVXHFeGGMdnXdo1jKqT02OPkcpK8z+n/6B5WDMXqSXOiyueKjfja7WXfZ1E5+lhynGCKYUGlNt3yzqU2+q27Snb7mpTeU00Dq1JWfrfRdu7mIEaTdS9WI51LVnOx/Mx80fZw8FaED4DINUNkumf7vqfJ4TX89pFLAeCuT4YZ5EN8b4uKdCl4OibdqCvpb+RyUmRWjN9w3bmX/dG4NiYnCXlfO0CqH9HWglsVGZaw03/Z0E9yMz4aq872IOLvt9pSABAjcIZ6kD1+NaAQQOTvpN5VFKao7w5SylmlgULgcSCLAIDFIIBHr4Qon4wbpLzVlhBxQvGGCCJDEEksXpvSNyABWhoSEpuFsFHy9qdFswEJlQQARtriIETuGCLIdCKS3ANtSv9jJKDyDRKSh0SYCUUfkbbzS9LulREEnaofKlnqvSwmu+Iv2i//hWFogeMqz+YPuaR0dTLHdP4n9sh9bFPGcBbxyjN16sM5H7Ytqcx0QysmiuTr4eBt2xpL3WTnlRHEuHRK/fCYLPV+M9kp/kJnvvwXhqEFLmn2J+YPa/CEhSsnxhHan7yv1excMIqO4UxI8krVZeqUD5KwFTmkZPtqN7RixBZZ+erAuvN1uVnKgG63p4BW8J0VmSHJYLLYnBvOG3J5fIpOlSfrg7Ulh88lAqPeBEtpkoisC/Ior10WknJZDbklcKuWAg2ycakPAm2zxn5zJwZc9WYXpvs2Q0Bd0j8uk8dbCtQtVhZ6i61O/ZgEZEdYbVGIZQ7O7V0p011Chdt3J86cCuo72ggymQAAAA==') format('woff2'),
url('iconfont.woff?t=1611200069054') format('woff'),
url('iconfont.ttf?t=1611200069054') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('iconfont.svg?t=1611200069054#sf3-font') format('svg'); /* iOS 4.1- */
src: url('iconfont.eot?t=1615973526249'); /* IE9 */
src: url('iconfont.eot?t=1615973526249#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),
url('iconfont.woff?t=1615973526249') format('woff'),
url('iconfont.ttf?t=1615973526249') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('iconfont.svg?t=1615973526249#sf3-font') format('svg'); /* iOS 4.1- */
}
.sf3-font {
@@ -15,6 +15,10 @@
-moz-osx-font-smoothing: grayscale;
}
.sf3-font-desktop:before {
content: "\e720";
}
.sf3-font-qr-code:before {
content: "\e716";
}

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -20,6 +20,9 @@ Created by iconfont
/>
<missing-glyph />
<glyph glyph-name="desktop" unicode="&#59168;" d="M928 832c35.2 0 64-28.8 64-64v-608c0-35.2-28.8-64-64-64H604.8c3.2-25.6 9.6-44.8 16-64h121.6c32 0 57.6-25.6 57.6-57.6s-25.6-57.6-57.6-57.6H281.6c-32 0-57.6 25.6-57.6 57.6S249.6 32 281.6 32h121.6c6.4 19.2 12.8 38.4 19.2 64H96c-35.2 0-64 28.8-64 64V768c0 35.2 28.8 64 64 64h832z m-51.2-112H147.2v-486.4h729.6V720z" horiz-adv-x="1024" />
<glyph glyph-name="qr-code" unicode="&#59158;" d="M432 345.6c22.4 0 38.4-16 38.4-38.4v-329.6c0-22.4-16-38.4-38.4-38.4H102.4c-22.4 0-38.4 16-38.4 38.4V307.2c0 22.4 16 38.4 38.4 38.4h329.6z m524.8-326.4v-41.6c0-22.4-16-38.4-38.4-38.4h-41.6v80h80z m-160 0v-80h-80v80h80z m0 326.4v-163.2h80v163.2h41.6c22.4 0 38.4-16 38.4-38.4v-204.8h-243.2v80h-80v-243.2h-41.6c-22.4 0-38.4 16-38.4 38.4V307.2c0 22.4 16 38.4 38.4 38.4h204.8z m-406.4-83.2H144v-243.2h243.2v243.2z m-147.2-76.8c16 9.6 35.2 9.6 51.2 0s25.6-25.6 25.6-44.8-9.6-35.2-25.6-44.8-35.2-9.6-51.2 0-25.6 25.6-25.6 44.8 9.6 35.2 25.6 44.8zM432 832c22.4 0 38.4-16 38.4-38.4v-329.6c0-22.4-16-38.4-38.4-38.4H102.4c-22.4 0-38.4 16-38.4 38.4V793.6C64 816 80 832 102.4 832h329.6z m486.4 0c22.4 0 38.4-16 38.4-38.4v-329.6c0-22.4-16-38.4-38.4-38.4H588.8c-22.4 0-38.4 16-38.4 38.4V793.6c0 22.4 16 38.4 38.4 38.4h329.6zM390.4 752H144v-243.2h243.2V752z m486.4 0h-243.2v-243.2h243.2V752zM243.2 672c16 9.6 35.2 9.6 51.2 0s25.6-25.6 25.6-44.8-12.8-32-28.8-41.6c-12.8-9.6-32-9.6-48 0s-25.6 25.6-25.6 41.6 9.6 35.2 25.6 44.8z m512 6.4c28.8 0 51.2-22.4 51.2-51.2s-22.4-51.2-51.2-51.2c-28.8 0-51.2 22.4-51.2 51.2s22.4 51.2 51.2 51.2z" horiz-adv-x="1024" />

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.