Fixed styles before merge master
This commit is contained in:
commit
093fd8f5ed
183
apps/common/mobile/lib/component/ThemeColorPalette.jsx
Normal file
183
apps/common/mobile/lib/component/ThemeColorPalette.jsx
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { f7, ListItem, List, Icon } from 'framework7-react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const ThemeColors = ({ themeColors, onColorClick, curColor }) => {
|
||||||
|
return (
|
||||||
|
<div className='palette'>
|
||||||
|
{themeColors.map((row, rowIndex) => {
|
||||||
|
return(
|
||||||
|
<div key={`tc-row-${rowIndex}`} className='row'>
|
||||||
|
{row.map((effect, index) => {
|
||||||
|
return(
|
||||||
|
<a key={`tc-${rowIndex}-${index}`}
|
||||||
|
className={curColor && curColor.color === effect.color && curColor.effectValue === effect.effectValue ? 'active' : ''}
|
||||||
|
style={{ background: `#${effect.color}`}}
|
||||||
|
onClick={() => {onColorClick(effect.color, effect.effectId)}}
|
||||||
|
></a>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const StandartColors = ({ options, standartColors, onColorClick, curColor }) => {
|
||||||
|
return (
|
||||||
|
<div className='palette'>
|
||||||
|
{standartColors.map((color, index) => {
|
||||||
|
return(
|
||||||
|
index === 0 && options.transparent ?
|
||||||
|
<a key={`sc-${index}`}
|
||||||
|
className={`transparent ${'transparent' === curColor ? 'active' : ''}`}
|
||||||
|
onClick={() => {onColorClick('transparent')}}
|
||||||
|
></a> :
|
||||||
|
<a key={`sc-${index}`}
|
||||||
|
className={curColor && curColor === color ? ' active' : ''}
|
||||||
|
style={{ background: `#${color}` }}
|
||||||
|
onClick={() => {onColorClick(color)}}
|
||||||
|
></a>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const CustomColors = ({ options, customColors, onColorClick, curColor }) => {
|
||||||
|
const colors = customColors.length > 0 ? customColors : [];
|
||||||
|
const emptyItems = [];
|
||||||
|
if (colors.length < options.customcolors) {
|
||||||
|
for (let i = colors.length; i < options.customcolors; i++) {
|
||||||
|
emptyItems.push(<a className='empty-color'
|
||||||
|
key={`dc-empty${i}`}
|
||||||
|
onClick={() => {onColorClick('empty')}}
|
||||||
|
></a>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className='palette'>
|
||||||
|
{colors && colors.length > 0 && colors.map((color, index) => {
|
||||||
|
return(
|
||||||
|
<a key={`dc-${index}`}
|
||||||
|
className={curColor && curColor === color ? 'active' : ''}
|
||||||
|
style={{background: `#${color}`}}
|
||||||
|
onClick={() => {onColorClick(color)}}
|
||||||
|
></a>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
{emptyItems.length > 0 && emptyItems}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const ThemeColorPalette = props => {
|
||||||
|
const {t} = useTranslation();
|
||||||
|
const _t = t('Common.ThemeColorPalette', {returnObjects: true});
|
||||||
|
const options = {
|
||||||
|
customcolors: props.customcolors || 10,
|
||||||
|
standardcolors: props.standardcolors || 10,
|
||||||
|
themecolors: props.themecolors || 10,
|
||||||
|
effects: props.effects || 5,
|
||||||
|
//allowReselect: props.allowReselect !== false,
|
||||||
|
transparent: props.transparent || false,
|
||||||
|
value: props.value || '000000',
|
||||||
|
cls: props.cls || ''
|
||||||
|
};
|
||||||
|
const curColor = props.curColor;
|
||||||
|
const themeColors = [];
|
||||||
|
const effectColors = Common.Utils.ThemeColor.getEffectColors();
|
||||||
|
let row = -1;
|
||||||
|
effectColors.forEach((effect, index) => {
|
||||||
|
if (0 == index % options.themecolors) {
|
||||||
|
themeColors.push([]);
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
themeColors[row].push(effect);
|
||||||
|
});
|
||||||
|
const standartColors = Common.Utils.ThemeColor.getStandartColors();
|
||||||
|
// custom color
|
||||||
|
let customColors = props.customColors;
|
||||||
|
if (customColors.length < 1) {
|
||||||
|
customColors = localStorage.getItem('mobile-custom-colors');
|
||||||
|
customColors = customColors ? customColors.toLowerCase().split(',') : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={'color-palettes' + (props.cls ? (' ' + props.cls) : '')}>
|
||||||
|
<List>
|
||||||
|
<ListItem className='theme-colors'>
|
||||||
|
<div>{ _t.textThemeColors }</div>
|
||||||
|
<ThemeColors themeColors={themeColors} onColorClick={props.changeColor} curColor={curColor}/>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem className='standart-colors'>
|
||||||
|
<div>{ _t.textStandartColors }</div>
|
||||||
|
<StandartColors options={options} standartColors={standartColors} onColorClick={props.changeColor} curColor={curColor}/>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem className='dynamic-colors'>
|
||||||
|
<div>{ _t.textCustomColors }</div>
|
||||||
|
<CustomColors options={options} customColors={customColors} onColorClick={props.changeColor} curColor={curColor}/>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const CustomColorPicker = props => {
|
||||||
|
//Function to convert rgb color to hex format
|
||||||
|
const hexDigits = new Array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f");
|
||||||
|
const hex = x => {
|
||||||
|
return isNaN(x) ? "00" : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16];
|
||||||
|
};
|
||||||
|
const rgb2hex = rgb => {
|
||||||
|
rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
|
||||||
|
return hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
|
||||||
|
};
|
||||||
|
|
||||||
|
let currentColor = props.currentColor;
|
||||||
|
if (props.autoColor) {
|
||||||
|
currentColor = rgb2hex(props.autoColor);
|
||||||
|
}
|
||||||
|
const countDynamicColors = props.countdynamiccolors || 10;
|
||||||
|
const [stateColor, setColor] = useState(`#${currentColor}`);
|
||||||
|
useEffect(() => {
|
||||||
|
if (document.getElementsByClassName('color-picker-wheel').length < 1) {
|
||||||
|
const colorPicker = f7.colorPicker.create({
|
||||||
|
containerEl: document.getElementsByClassName('color-picker-container')[0],
|
||||||
|
value: {
|
||||||
|
hex: `#${currentColor}`
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
change: function (value) {
|
||||||
|
setColor(value.getValue().hex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const addNewColor = (color) => {
|
||||||
|
let colors = localStorage.getItem('mobile-custom-colors');
|
||||||
|
colors = colors ? colors.split(',') : [];
|
||||||
|
const newColor = color.slice(1);
|
||||||
|
if (colors.push(newColor) > countDynamicColors) colors.shift(); // 10 - dynamiccolors
|
||||||
|
localStorage.setItem('mobile-custom-colors', colors.join().toLowerCase());
|
||||||
|
props.onAddNewColor && props.onAddNewColor(colors, newColor);
|
||||||
|
};
|
||||||
|
return(
|
||||||
|
<div id='color-picker'>
|
||||||
|
<div className='color-picker-container'></div>
|
||||||
|
<div className='right-block'>
|
||||||
|
<div className='color-hsb-preview'>
|
||||||
|
<div className='new-color-hsb-preview' style={{backgroundColor: stateColor}}></div>
|
||||||
|
<div className='current-color-hsb-preview' style={{backgroundColor: `#${currentColor}`}}></div>
|
||||||
|
</div>
|
||||||
|
<a href='#' id='add-new-color' className='button button-round' onClick={()=>{addNewColor(stateColor)}}>
|
||||||
|
<Icon icon={'icon-plus'} slot="media" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
export { ThemeColorPalette, CustomColorPicker };
|
|
@ -160,6 +160,19 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.list {
|
.list {
|
||||||
|
.item-content {
|
||||||
|
.color-preview {
|
||||||
|
width: 22px;
|
||||||
|
height: 8px;
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 21px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, .15) inset;
|
||||||
|
&.auto {
|
||||||
|
background-color: @autoColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
li.no-indicator {
|
li.no-indicator {
|
||||||
.item-link {
|
.item-link {
|
||||||
.item-inner:before {
|
.item-inner:before {
|
||||||
|
@ -299,4 +312,15 @@
|
||||||
.dialog {
|
.dialog {
|
||||||
background-color: rgba(var(--f7-dialog-bg-color-rgb), 1);
|
background-color: rgba(var(--f7-dialog-bg-color-rgb), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#color-picker {
|
||||||
|
.right-block {
|
||||||
|
.button-round {
|
||||||
|
.icon {
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,6 +178,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.item-content {
|
||||||
|
.color-preview {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 16px;
|
||||||
|
margin-top: -3px;
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, .15) inset;
|
||||||
|
&.auto {
|
||||||
|
background-color: @autoColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Bullets and numbers
|
// Bullets and numbers
|
||||||
.bullets,
|
.bullets,
|
||||||
|
@ -230,4 +242,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Color palette
|
||||||
|
#color-picker {
|
||||||
|
.right-block {
|
||||||
|
.button-round {
|
||||||
|
background-color: @themeColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
@black: #000000;
|
@black: #000000;
|
||||||
@gray: #c4c4c4;
|
@gray: #c4c4c4;
|
||||||
@green: #4cd964;
|
@green: #4cd964;
|
||||||
|
@background-normal: @white;
|
||||||
|
@autoColor: @black;
|
||||||
|
|
||||||
.popup, .popover, .sheet-modal {
|
.popup, .popover, .sheet-modal {
|
||||||
.list:first-child {
|
.list:first-child {
|
||||||
|
@ -228,5 +229,107 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-color-auto {
|
||||||
|
.color-auto {
|
||||||
|
width:22px;
|
||||||
|
height: 22px;
|
||||||
|
background-color: @autoColor;
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
.color-auto {
|
||||||
|
box-shadow: 0 0 0 1px @background-normal, 0 0 0 4px @themeColor;
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-palettes {
|
||||||
|
.palette {
|
||||||
|
padding: 8px 0px;
|
||||||
|
a {
|
||||||
|
flex-grow: 1;
|
||||||
|
position: relative;
|
||||||
|
min-width: 10px;
|
||||||
|
min-height: 26px;
|
||||||
|
margin: 1px 1px 0 0;
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, .15) inset;
|
||||||
|
&.active:after {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-shadow: 0 0 0 1px @background-normal, 0 0 0 4px @themeColor;
|
||||||
|
z-index: 1;
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
&.transparent {
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
.encoded-svg-background("<svg xmlns='http://www.w3.org/2000/svg' x='0px' y='0px' viewBox='0 0 22 22' xml:space='preserve'><line stroke='#ff0000' stroke-linecap='undefined' stroke-linejoin='undefined' id='svg_1' y2='0' x2='22' y1='22' x1='0' stroke-width='2' fill='none'/></svg>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.row {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.list .item-inner {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.standart-colors, .dynamic-colors {
|
||||||
|
.palette {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dynamic-colors {
|
||||||
|
.empty-color {
|
||||||
|
background-color: @background-normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#color-picker {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
max-width: 300px;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-top: 4px;
|
||||||
|
.color-picker-container {
|
||||||
|
width: calc(100% - 94px);
|
||||||
|
position: relative;
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
font-size: 0;
|
||||||
|
.color-picker-module-wheel {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.right-block {
|
||||||
|
margin-left: 20px;
|
||||||
|
.color-hsb-preview {
|
||||||
|
width: 72px;
|
||||||
|
height: 72px;
|
||||||
|
border-radius: 100px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid @gray;
|
||||||
|
.new-color-hsb-preview, .current-color-hsb-preview {
|
||||||
|
width: 100%;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.button-round {
|
||||||
|
height: 72px;
|
||||||
|
width: 72px;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 100px;
|
||||||
|
background-color: @white;
|
||||||
|
box-shadow: 0 4px 4px rgba(0,0,0,.25);
|
||||||
|
border-color: transparent;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
{
|
{
|
||||||
|
"Common": {
|
||||||
|
"ThemeColorPalette": {
|
||||||
|
"textThemeColors": "Theme Colors",
|
||||||
|
"textStandartColors": "Standart Colors",
|
||||||
|
"textCustomColors": "Custom Colors"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Settings": {
|
"Settings": {
|
||||||
"textCancel": "Cancel",
|
"textCancel": "Cancel",
|
||||||
"textSettings": "Settings",
|
"textSettings": "Settings",
|
||||||
|
@ -164,7 +171,11 @@
|
||||||
"textDifferentOddAndEvenPages": "Different odd and even pages",
|
"textDifferentOddAndEvenPages": "Different odd and even pages",
|
||||||
"textLinkToPrevious": "Link to Previous",
|
"textLinkToPrevious": "Link to Previous",
|
||||||
"textContinueFromPreviousSection": "Continue from previous section",
|
"textContinueFromPreviousSection": "Continue from previous section",
|
||||||
"textStartAt": "Start at"
|
"textStartAt": "Start at",
|
||||||
|
"textFontColors": "Font Colors",
|
||||||
|
"textAutomatic": "Automatic",
|
||||||
|
"textAddCustomColor": "Add Custom Color",
|
||||||
|
"textCustomColor": "Custom Color"
|
||||||
},
|
},
|
||||||
"Add": {
|
"Add": {
|
||||||
"textTable": "Table",
|
"textTable": "Table",
|
||||||
|
|
|
@ -172,6 +172,10 @@ class MainController extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
bindEvents() {
|
bindEvents() {
|
||||||
|
this.api.asc_registerCallback('asc_onSendThemeColors', (colors, standart_colors) => {
|
||||||
|
Common.Utils.ThemeColor.setColors(colors, standart_colors);
|
||||||
|
});
|
||||||
|
|
||||||
const storeDocumentSettings = this.props.storeDocumentSettings;
|
const storeDocumentSettings = this.props.storeDocumentSettings;
|
||||||
this.api.asc_registerCallback('asc_onPageOrient', isPortrait => {
|
this.api.asc_registerCallback('asc_onPageOrient', isPortrait => {
|
||||||
storeDocumentSettings.resetPortrait(isPortrait);
|
storeDocumentSettings.resetPortrait(isPortrait);
|
||||||
|
|
|
@ -33,6 +33,27 @@ class EditTextController extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onTextColorAuto() {
|
||||||
|
const api = Common.EditorApi.get();
|
||||||
|
const color = new Asc.asc_CColor();
|
||||||
|
color.put_auto(true);
|
||||||
|
api.put_TextColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
onTextColor(color) {
|
||||||
|
const api = Common.EditorApi.get();
|
||||||
|
api.put_TextColor(Common.Utils.ThemeColor.getRgbColor(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
onBackgroundColor(color) {
|
||||||
|
const api = Common.EditorApi.get();
|
||||||
|
if (color == 'transparent') {
|
||||||
|
api.put_ParagraphShade(false);
|
||||||
|
} else {
|
||||||
|
api.put_ParagraphShade(true, Common.Utils.ThemeColor.getRgbColor(color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
toggleBold(value) {
|
toggleBold(value) {
|
||||||
const api = Common.EditorApi.get();
|
const api = Common.EditorApi.get();
|
||||||
if (api) {
|
if (api) {
|
||||||
|
@ -174,6 +195,9 @@ class EditTextController extends Component {
|
||||||
return (
|
return (
|
||||||
<EditText changeFontSize={this.changeFontSize}
|
<EditText changeFontSize={this.changeFontSize}
|
||||||
changeFontFamily={this.changeFontFamily}
|
changeFontFamily={this.changeFontFamily}
|
||||||
|
onTextColorAuto={this.onTextColorAuto}
|
||||||
|
onTextColor={this.onTextColor}
|
||||||
|
onBackgroundColor={this.onBackgroundColor}
|
||||||
toggleBold={this.toggleBold}
|
toggleBold={this.toggleBold}
|
||||||
toggleItalic={this.toggleItalic}
|
toggleItalic={this.toggleItalic}
|
||||||
toggleUnderline={this.toggleUnderline}
|
toggleUnderline={this.toggleUnderline}
|
||||||
|
|
|
@ -10,38 +10,6 @@
|
||||||
@import './icons-ios.less';
|
@import './icons-ios.less';
|
||||||
@import './icons-material.less';
|
@import './icons-material.less';
|
||||||
|
|
||||||
/* Left Panel right border when it is visible by breakpoint */
|
|
||||||
.panel-left.panel-in-breakpoint:before {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
height: 100%;
|
|
||||||
width: 1px;
|
|
||||||
background: rgba(0,0,0,0.1);
|
|
||||||
content: '';
|
|
||||||
z-index: 6000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hide navbar link which opens left panel when it is visible by breakpoint */
|
|
||||||
.panel-left.panel-in-breakpoint ~ .view .navbar .panel-open[data-panel="left"] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Extra borders for main view and left panel for iOS theme when it behaves as panel (before breakpoint size)
|
|
||||||
*/
|
|
||||||
.ios .panel-left:not(.panel-in-breakpoint).panel-in ~ .view-main:before,
|
|
||||||
.ios .panel-left:not(.panel-in-breakpoint).panel-closing ~ .view-main:before {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
height: 100%;
|
|
||||||
width: 1px;
|
|
||||||
background: rgba(0,0,0,0.1);
|
|
||||||
content: '';
|
|
||||||
z-index: 6000;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--f7-popover-width: 360px;
|
--f7-popover-width: 360px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,6 +160,16 @@
|
||||||
height: 22px;
|
height: 22px;
|
||||||
.encoded-svg-background('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 22 22" fill="@{themeColor}"><g><polygon id="XMLID_7_" points="22,4 22,3 12,3 11,3 1,3 1,4 11,4 11,4.3 8,7.4 8.7,8.1 11,5.7 11,17.3 8.7,14.9 8,15.6 11,18.7 11,19 1,19 1,20 11,20 12,20 22,20 22,19 12,19 12,18.6 15,15.6 14.3,14.9 12,17.2 12,5.8 14.3,8.1 15,7.4 12,4.4 12,4 "/></g></svg>');
|
.encoded-svg-background('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 22 22" fill="@{themeColor}"><g><polygon id="XMLID_7_" points="22,4 22,3 12,3 11,3 1,3 1,4 11,4 11,4.3 8,7.4 8.7,8.1 11,5.7 11,17.3 8.7,14.9 8,15.6 11,18.7 11,19 1,19 1,20 11,20 12,20 22,20 22,19 12,19 12,18.6 15,15.6 14.3,14.9 12,17.2 12,5.8 14.3,8.1 15,7.4 12,4.4 12,4 "/></g></svg>');
|
||||||
}
|
}
|
||||||
|
&.icon-text-color {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
.encoded-svg-background('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 22 22" fill="@{themeColor}"><g><path d="M8.9,12l2.3-6.3l2.2,6.3H8.9z M4.7,17.8h2l1.6-4.3h5.6l1.5,4.3h2.1L12.3,3.5h-2.2L4.7,17.8z"/></g></svg>');
|
||||||
|
}
|
||||||
|
&.icon-text-selection {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
.encoded-svg-background('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 22 22" fill="@{themeColor}"><g><path d="M7.6,10.3c0.2,0.3,0.4,0.4,0.5,0.5c0.3,0.2,0.6,0.3,1,0.3c0.7,0,1.3-0.3,1.7-0.8c0.4-0.5,0.6-1.2,0.6-2.1c0-0.9-0.2-1.5-0.6-2c-0.4-0.4-0.9-0.7-1.6-0.7c-0.3,0-0.6,0.1-0.9,0.2C8,6,7.8,6.2,7.6,6.4V3.8H6.8V11h0.8V10.3z M8,6.9c0.3-0.3,0.7-0.4,1.1-0.4c0.5,0,0.8,0.2,1,0.5c0.2,0.4,0.4,0.8,0.4,1.4c0,0.6-0.1,1.1-0.4,1.5c-0.2,0.4-0.6,0.6-1.1,0.6c-0.6,0-1.1-0.3-1.3-0.9C7.6,9.2,7.6,8.8,7.6,8.3C7.6,7.7,7.7,7.2,8,6.9z M5.7,10.4c-0.1,0-0.2,0-0.2-0.1c0-0.1-0.1-0.1-0.1-0.2v-3c0-0.5-0.2-0.9-0.6-1.1C4.4,5.8,4,5.6,3.3,5.6c-0.5,0-1,0.1-1.4,0.4C1.5,6.3,1.3,6.7,1.3,7.4h0.8c0-0.3,0.1-0.5,0.2-0.6c0.2-0.2,0.5-0.4,1-0.4c0.4,0,0.7,0.1,0.9,0.2c0.2,0.1,0.3,0.4,0.3,0.7c0,0.1,0,0.3-0.1,0.3C4.4,7.7,4.3,7.8,4.1,7.8L2.7,8C2.2,8.1,1.8,8.2,1.5,8.5C1.2,8.8,1,9.1,1,9.6c0,0.4,0.2,0.8,0.5,1.1c0.3,0.3,0.7,0.4,1.2,0.4c0.4,0,0.8-0.1,1.1-0.3c0.3-0.2,0.6-0.4,0.8-0.6c0,0.2,0.1,0.4,0.2,0.5c0.1,0.2,0.4,0.3,0.7,0.3c0.1,0,0.2,0,0.3,0c0.1,0,0.2,0,0.3-0.1v-0.6c-0.1,0-0.1,0-0.2,0C5.8,10.4,5.7,10.4,5.7,10.4z M4.5,9.1c0,0.5-0.2,0.9-0.7,1.2c-0.3,0.1-0.6,0.2-0.9,0.2c-0.3,0-0.5-0.1-0.7-0.2C2,10.1,2,9.9,2,9.6C2,9.3,2.1,9,2.4,8.9c0.2-0.1,0.4-0.2,0.7-0.2l0.5-0.1c0.2,0,0.3-0.1,0.5-0.1c0.2,0,0.3-0.1,0.4-0.2V9.1z M18.5,5L8.3,15.3l-0.5,2c-0.6,0.4-1.3,0.3-1.5,0.6c-0.3,0.4,0.9,0.4,1.5,0.3c0.4,0,0.5,0,0.5-0.2l2.2-0.6L20.7,7.1L18.5,5z M9,15.3l9.5-9.5L20,7.1l-9.5,9.5L9,15.3z"/></g></svg>');
|
||||||
|
}
|
||||||
// Align
|
// Align
|
||||||
&.icon-text-align-left {
|
&.icon-text-align-left {
|
||||||
width: 22px;
|
width: 22px;
|
||||||
|
|
|
@ -60,6 +60,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i.icon {
|
i.icon {
|
||||||
|
&.icon-plus {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
.encoded-svg-background('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 22 22" fill="@{navBarIconColor}"><g><path d="M21,12h-9v9h-2v-9H1v-2h9V1h2v9h9V12z"/></g></svg>');
|
||||||
|
}
|
||||||
&.icon-expand-down {
|
&.icon-expand-down {
|
||||||
width: 17px;
|
width: 17px;
|
||||||
height: 17px;
|
height: 17px;
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {storeChartSettings} from "./chartSettings";
|
||||||
import {storeDocumentInfo} from "./documentInfo";
|
import {storeDocumentInfo} from "./documentInfo";
|
||||||
import {storeApplicationSettings} from './applicationSettings';
|
import {storeApplicationSettings} from './applicationSettings';
|
||||||
import {storeAppOptions} from "./appOptions";
|
import {storeAppOptions} from "./appOptions";
|
||||||
|
import {storePalette} from "./palette";
|
||||||
|
|
||||||
export const stores = {
|
export const stores = {
|
||||||
storeAppOptions: new storeAppOptions(),
|
storeAppOptions: new storeAppOptions(),
|
||||||
|
@ -24,6 +25,7 @@ export const stores = {
|
||||||
storeImageSettings: new storeImageSettings(),
|
storeImageSettings: new storeImageSettings(),
|
||||||
storeTableSettings: new storeTableSettings(),
|
storeTableSettings: new storeTableSettings(),
|
||||||
storeDocumentInfo: new storeDocumentInfo(),
|
storeDocumentInfo: new storeDocumentInfo(),
|
||||||
storeApplicationSettings: new storeApplicationSettings()
|
storeApplicationSettings: new storeApplicationSettings(),
|
||||||
|
storePalette: new storePalette()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
9
apps/documenteditor/mobile/src/store/palette.js
Normal file
9
apps/documenteditor/mobile/src/store/palette.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import {action, observable} from 'mobx';
|
||||||
|
|
||||||
|
export class storePalette {
|
||||||
|
@observable customColors = [];
|
||||||
|
|
||||||
|
@action changeCustomColors (colors) {
|
||||||
|
this.customColors = colors;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ export class storeTextSettings {
|
||||||
@observable typeNumbers = undefined;
|
@observable typeNumbers = undefined;
|
||||||
@observable paragraphAlign = undefined;
|
@observable paragraphAlign = undefined;
|
||||||
@observable textColor = undefined;
|
@observable textColor = undefined;
|
||||||
|
@observable customTextColors = [];
|
||||||
@observable lineSpacing = undefined;
|
@observable lineSpacing = undefined;
|
||||||
@observable backgroundColor = undefined;
|
@observable backgroundColor = undefined;
|
||||||
|
|
||||||
|
@ -97,7 +98,7 @@ export class storeTextSettings {
|
||||||
let value;
|
let value;
|
||||||
if (color) {
|
if (color) {
|
||||||
if (color.get_auto()) {
|
if (color.get_auto()) {
|
||||||
value = '000000';
|
value = 'auto';
|
||||||
} else {
|
} else {
|
||||||
if (color.get_type() == Asc.c_oAscColor.COLOR_TYPE_SCHEME) {
|
if (color.get_type() == Asc.c_oAscColor.COLOR_TYPE_SCHEME) {
|
||||||
value = {
|
value = {
|
||||||
|
@ -112,6 +113,10 @@ export class storeTextSettings {
|
||||||
this.textColor = value;
|
this.textColor = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action changeCustomTextColors (colors) {
|
||||||
|
this.customTextColors = colors;
|
||||||
|
}
|
||||||
|
|
||||||
@action resetLineSpacing (vc) {
|
@action resetLineSpacing (vc) {
|
||||||
let line = (vc.get_Line() === null || vc.get_LineRule() === null || vc.get_LineRule() != 1) ? -1 : vc.get_Line();
|
let line = (vc.get_Line() === null || vc.get_LineRule() === null || vc.get_LineRule() != 1) ? -1 : vc.get_Line();
|
||||||
this.lineSpacing = line;
|
this.lineSpacing = line;
|
||||||
|
|
|
@ -31,51 +31,9 @@ export default class extends React.Component {
|
||||||
return (
|
return (
|
||||||
<App params={ this.state.f7params } >
|
<App params={ this.state.f7params } >
|
||||||
|
|
||||||
{/* Left panel with cover effect when hidden */}
|
|
||||||
<Panel left cover themeDark visibleBreakpoint={960}>
|
|
||||||
<View>
|
|
||||||
<Page>
|
|
||||||
<Navbar title="Left Panel"/>
|
|
||||||
<BlockTitle>Left View Navigation</BlockTitle>
|
|
||||||
<List>
|
|
||||||
<ListItem link="/left-page-1/" title="Left Page 1"/>
|
|
||||||
<ListItem link="/left-page-2/" title="Left Page 2"/>
|
|
||||||
</List>
|
|
||||||
</Page>
|
|
||||||
</View>
|
|
||||||
</Panel>
|
|
||||||
|
|
||||||
|
|
||||||
{/* Right panel with reveal effect*/}
|
|
||||||
<Panel right reveal themeDark>
|
|
||||||
<View>
|
|
||||||
<Page>
|
|
||||||
<Navbar title="Right Panel"/>
|
|
||||||
<Block>Right panel content goes here</Block>
|
|
||||||
</Page>
|
|
||||||
</View>
|
|
||||||
</Panel>
|
|
||||||
|
|
||||||
|
|
||||||
{/* Your main view, should have "view-main" class */}
|
{/* Your main view, should have "view-main" class */}
|
||||||
<View main className="safe-areas" url="/" />
|
<View main className="safe-areas" url="/" />
|
||||||
<MainController />
|
<MainController />
|
||||||
|
|
||||||
{/* Popup */}
|
|
||||||
<Popup id="my-popup">
|
|
||||||
<View>
|
|
||||||
<Page>
|
|
||||||
<Navbar title="Popup">
|
|
||||||
<NavRight>
|
|
||||||
<Link popupClose>Close</Link>
|
|
||||||
</NavRight>
|
|
||||||
</Navbar>
|
|
||||||
<Block>
|
|
||||||
<p>Popup content goes here.</p>
|
|
||||||
</Block>
|
|
||||||
</Page>
|
|
||||||
</View>
|
|
||||||
</Popup>
|
|
||||||
</App>
|
</App>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import EditChartController from "../../controller/edit/EditChart";
|
||||||
import EditHyperlinkController from "../../controller/edit/EditHyperlink";
|
import EditHyperlinkController from "../../controller/edit/EditHyperlink";
|
||||||
import EditHeaderController from "../../controller/edit/EditHeader";
|
import EditHeaderController from "../../controller/edit/EditHeader";
|
||||||
|
|
||||||
import {PageAdditionalFormatting, PageBullets, PageFonts, PageLineSpacing, PageNumbers} from "./EditText";
|
import {PageTextFonts, PageTextAddFormatting, PageTextBullets, PageTextNumbers, PageTextLineSpacing, PageTextFontColor, PageTextCustomFontColor, PageTextBackgroundColor, PageTextCustomBackColor} from "./EditText";
|
||||||
import {PageAdvancedSettings} from "./EditParagraph";
|
import {PageAdvancedSettings} from "./EditParagraph";
|
||||||
import {PageWrap, PageReorder, PageReplace} from "./EditShape";
|
import {PageWrap, PageReorder, PageReplace} from "./EditShape";
|
||||||
import {PageImageReorder, PageImageReplace, PageImageWrap, PageLinkSettings} from "./EditImage";
|
import {PageImageReorder, PageImageReplace, PageImageWrap, PageLinkSettings} from "./EditImage";
|
||||||
|
@ -25,23 +25,39 @@ const routes = [
|
||||||
//Edit text
|
//Edit text
|
||||||
{
|
{
|
||||||
path: '/edit-text-fonts/',
|
path: '/edit-text-fonts/',
|
||||||
component: PageFonts,
|
component: PageTextFonts,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/edit-text-add-formatting/',
|
path: '/edit-text-add-formatting/',
|
||||||
component: PageAdditionalFormatting,
|
component: PageTextAddFormatting,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/edit-text-bullets/',
|
path: '/edit-text-bullets/',
|
||||||
component: PageBullets,
|
component: PageTextBullets,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/edit-text-numbers/',
|
path: '/edit-text-numbers/',
|
||||||
component: PageNumbers,
|
component: PageTextNumbers,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/edit-text-line-spacing/',
|
path: '/edit-text-line-spacing/',
|
||||||
component: PageLineSpacing,
|
component: PageTextLineSpacing,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/edit-text-font-color/',
|
||||||
|
component: PageTextFontColor,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/edit-text-custom-font-color/',
|
||||||
|
component: PageTextCustomFontColor,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/edit-text-background-color/',
|
||||||
|
component: PageTextBackgroundColor,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/edit-text-custom-back-color/',
|
||||||
|
component: PageTextCustomBackColor,
|
||||||
},
|
},
|
||||||
//Edit paragraph
|
//Edit paragraph
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import React, {Fragment, useState} from 'react';
|
import React, {Fragment, useState } from 'react';
|
||||||
import {observer, inject} from "mobx-react";
|
import {observer, inject} from "mobx-react";
|
||||||
import {List, ListItem, Icon, Row, Button, Page, Navbar, Segmented, BlockTitle} from 'framework7-react';
|
import {f7, List, ListItem, Icon, Row, Button, Page, Navbar, Segmented, BlockTitle} from 'framework7-react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {Device} from '../../../../../common/mobile/utils/device';
|
import {Device} from '../../../../../common/mobile/utils/device';
|
||||||
|
|
||||||
|
import { ThemeColorPalette, CustomColorPicker } from '../../../../../common/mobile/lib/component/ThemeColorPalette.jsx';
|
||||||
|
|
||||||
const PageFonts = props => {
|
const PageFonts = props => {
|
||||||
const isAndroid = Device.android;
|
const isAndroid = Device.android;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -208,18 +210,136 @@ const PageLineSpacing = props => {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PageCustomFontColor = props => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const _t = t('Edit', {returnObjects: true});
|
||||||
|
const store = props.storeTextSettings;
|
||||||
|
let textColor = store.textColor;
|
||||||
|
if (typeof textColor === 'object') {
|
||||||
|
textColor = textColor.color;
|
||||||
|
}
|
||||||
|
const autoColor = textColor === 'auto' ? window.getComputedStyle(document.getElementById('font-color-auto')).backgroundColor : null;
|
||||||
|
const onAddNewColor = (colors, color) => {
|
||||||
|
props.storePalette.changeCustomColors(colors);
|
||||||
|
props.onTextColor(color);
|
||||||
|
props.f7router.back();
|
||||||
|
};
|
||||||
|
return(
|
||||||
|
<Page>
|
||||||
|
<Navbar title={_t.textCustomColor} backLink={_t.textBack} />
|
||||||
|
<CustomColorPicker autoColor={autoColor} currentColor={textColor} onAddNewColor={onAddNewColor}/>
|
||||||
|
</Page>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const PageFontColor = props => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const _t = t('Edit', {returnObjects: true});
|
||||||
|
const textColor = props.storeTextSettings.textColor;
|
||||||
|
const customColors = props.storePalette.customColors;
|
||||||
|
const changeColor = (color, effectId) => {
|
||||||
|
if (color !== 'empty') {
|
||||||
|
if (effectId !==undefined ) {
|
||||||
|
props.onTextColor({color: color, effectId: effectId});
|
||||||
|
} else {
|
||||||
|
props.onTextColor(color);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// open custom color menu
|
||||||
|
props.f7router.navigate('/edit-text-custom-font-color/');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return(
|
||||||
|
<Page>
|
||||||
|
<Navbar title={_t.textFontColors} backLink={_t.textBack} />
|
||||||
|
<List>
|
||||||
|
<ListItem className={'item-color-auto' + (textColor === 'auto' ? ' active' : '')} title={_t.textAutomatic} onClick={() => {
|
||||||
|
props.onTextColorAuto();
|
||||||
|
}}>
|
||||||
|
<div slot="media">
|
||||||
|
<div id='font-color-auto' className={'color-auto'}></div>
|
||||||
|
</div>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
<ThemeColorPalette changeColor={changeColor} curColor={textColor} customColors={customColors}/>
|
||||||
|
<List>
|
||||||
|
<ListItem title={_t.textAddCustomColor} link={'/edit-text-custom-font-color/'} routeProps={{
|
||||||
|
onTextColor: props.onTextColor
|
||||||
|
}}></ListItem>
|
||||||
|
</List>
|
||||||
|
</Page>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const PageCustomBackColor = props => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const _t = t('Edit', {returnObjects: true});
|
||||||
|
let backgroundColor = props.storeTextSettings.backgroundColor;
|
||||||
|
if (typeof backgroundColor === 'object') {
|
||||||
|
backgroundColor = backgroundColor.color;
|
||||||
|
}
|
||||||
|
const onAddNewColor = (colors, color) => {
|
||||||
|
props.storePalette.changeCustomColors(colors);
|
||||||
|
props.onBackgroundColor(color);
|
||||||
|
props.f7router.back();
|
||||||
|
};
|
||||||
|
return(
|
||||||
|
<Page>
|
||||||
|
<Navbar title={_t.textCustomColor} backLink={_t.textBack} />
|
||||||
|
<CustomColorPicker currentColor={backgroundColor} onAddNewColor={onAddNewColor}/>
|
||||||
|
</Page>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const PageBackgroundColor = props => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const _t = t('Edit', {returnObjects: true});
|
||||||
|
const backgroundColor = props.storeTextSettings.backgroundColor;
|
||||||
|
const customColors = props.storePalette.customColors;
|
||||||
|
const changeColor = (color, effectId) => {
|
||||||
|
if (color !== 'empty') {
|
||||||
|
if (effectId !==undefined ) {
|
||||||
|
props.onBackgroundColor({color: color, effectId: effectId});
|
||||||
|
} else {
|
||||||
|
props.onBackgroundColor(color);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// open custom color menu
|
||||||
|
props.f7router.navigate('/edit-text-custom-back-color/');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return(
|
||||||
|
<Page>
|
||||||
|
<Navbar title={_t.textHighlightColor} backLink={_t.textBack} />
|
||||||
|
<ThemeColorPalette changeColor={changeColor} curColor={backgroundColor} customColors={customColors} transparent={true}/>
|
||||||
|
<List>
|
||||||
|
<ListItem title={_t.textAddCustomColor} link={'/edit-text-custom-back-color/'} routeProps={{
|
||||||
|
onBackgroundColor: props.onBackgroundColor
|
||||||
|
}}></ListItem>
|
||||||
|
</List>
|
||||||
|
</Page>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
const EditText = props => {
|
const EditText = props => {
|
||||||
const isAndroid = Device.android;
|
const isAndroid = Device.android;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const storeTextSettings = props.storeTextSettings;
|
const storeTextSettings = props.storeTextSettings;
|
||||||
const fontName = storeTextSettings.fontName || t('Edit.textFonts');
|
const fontName = storeTextSettings.fontName || t('Edit.textFonts');
|
||||||
const fontSize = storeTextSettings.fontSize;
|
const fontSize = storeTextSettings.fontSize;
|
||||||
|
const fontColor = storeTextSettings.textColor;
|
||||||
|
const backgroundColor = storeTextSettings.backgroundColor;
|
||||||
const displaySize = typeof fontSize === 'undefined' ? t('Edit.textAuto') : fontSize + ' ' + t('Edit.textPt');
|
const displaySize = typeof fontSize === 'undefined' ? t('Edit.textAuto') : fontSize + ' ' + t('Edit.textPt');
|
||||||
const isBold = storeTextSettings.isBold;
|
const isBold = storeTextSettings.isBold;
|
||||||
const isItalic = storeTextSettings.isItalic;
|
const isItalic = storeTextSettings.isItalic;
|
||||||
const isUnderline = storeTextSettings.isUnderline;
|
const isUnderline = storeTextSettings.isUnderline;
|
||||||
const isStrikethrough = storeTextSettings.isStrikethrough;
|
const isStrikethrough = storeTextSettings.isStrikethrough;
|
||||||
const paragraphAlign = storeTextSettings.paragraphAlign;
|
const paragraphAlign = storeTextSettings.paragraphAlign;
|
||||||
|
|
||||||
|
const fontColorPreview = fontColor !== 'auto' ?
|
||||||
|
<span className="color-preview" style={{ background: `#${(typeof fontColor === "object" ? fontColor.color : fontColor)}`}}></span> :
|
||||||
|
<span className="color-preview auto"></span>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<List>
|
<List>
|
||||||
|
@ -235,12 +355,22 @@ const EditText = props => {
|
||||||
<a className={'button' + (isStrikethrough ? ' active' : '')} onClick={() => {props.toggleStrikethrough(!isStrikethrough)}} style={{textDecoration: "line-through"}}>S</a>
|
<a className={'button' + (isStrikethrough ? ' active' : '')} onClick={() => {props.toggleStrikethrough(!isStrikethrough)}} style={{textDecoration: "line-through"}}>S</a>
|
||||||
</Row>
|
</Row>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem title={t("Edit.textFontColor")} link="#">
|
<ListItem title={t("Edit.textFontColor")} link="/edit-text-font-color/" routeProps={{
|
||||||
{!isAndroid && <Icon slot="media" icon="icon-text-color"></Icon>}
|
onTextColorAuto: props.onTextColorAuto,
|
||||||
<span className="color-preview"></span>
|
onTextColor: props.onTextColor
|
||||||
|
}}>
|
||||||
|
{!isAndroid ?
|
||||||
|
<Icon slot="media" icon="icon-text-color">{fontColorPreview}</Icon> :
|
||||||
|
fontColorPreview
|
||||||
|
}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem title={t("Edit.textHighlightColor")} link="#">
|
<ListItem title={t("Edit.textHighlightColor")} link="/edit-text-background-color/" routeProps={{
|
||||||
{!isAndroid && <Icon slot="media" icon="icon-text-selection"></Icon>}
|
onBackgroundColor: props.onBackgroundColor
|
||||||
|
}}>
|
||||||
|
{!isAndroid ?
|
||||||
|
<Icon slot="media" icon="icon-text-selection"><span className="color-preview" style={{ background: `#${backgroundColor}`}}></span></Icon> :
|
||||||
|
<span className="color-preview" style={{ background: `#${(typeof backgroundColor === "object" ? backgroundColor.color : backgroundColor)}`}}></span>
|
||||||
|
}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem title={t("Edit.textAdditionalFormatting")} link="/edit-text-add-formatting/" routeProps={{
|
<ListItem title={t("Edit.textAdditionalFormatting")} link="/edit-text-add-formatting/" routeProps={{
|
||||||
onAdditionalStrikethrough: props.onAdditionalStrikethrough,
|
onAdditionalStrikethrough: props.onAdditionalStrikethrough,
|
||||||
|
@ -299,15 +429,26 @@ const EditText = props => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const EditTextContainer = inject("storeTextSettings", "storeFocusObjects")(observer(EditText));
|
const EditTextContainer = inject("storeTextSettings", "storeFocusObjects")(observer(EditText));
|
||||||
const PageFontsContainer = inject("storeTextSettings", "storeFocusObjects")(observer(PageFonts));
|
const PageTextFonts = inject("storeTextSettings", "storeFocusObjects")(observer(PageFonts));
|
||||||
const PageAddFormattingContainer = inject("storeTextSettings", "storeFocusObjects")(observer(PageAdditionalFormatting));
|
const PageTextAddFormatting = inject("storeTextSettings", "storeFocusObjects")(observer(PageAdditionalFormatting));
|
||||||
const PageBulletsContainer = inject("storeTextSettings")(observer(PageBullets));
|
const PageTextBullets = inject("storeTextSettings")(observer(PageBullets));
|
||||||
const PageNumbersContainer = inject("storeTextSettings")(observer(PageNumbers));
|
const PageTextNumbers = inject("storeTextSettings")(observer(PageNumbers));
|
||||||
const PageLineSpacingContainer = inject("storeTextSettings")(observer(PageLineSpacing));
|
const PageTextLineSpacing = inject("storeTextSettings")(observer(PageLineSpacing));
|
||||||
|
const PageTextFontColor = inject("storeTextSettings", "storePalette")(observer(PageFontColor));
|
||||||
|
const PageTextCustomFontColor = inject("storeTextSettings", "storePalette")(observer(PageCustomFontColor));
|
||||||
|
const PageTextBackgroundColor = inject("storeTextSettings", "storePalette")(observer(PageBackgroundColor));
|
||||||
|
const PageTextCustomBackColor = inject("storeTextSettings", "storePalette")(observer(PageCustomBackColor));
|
||||||
|
|
||||||
export {EditTextContainer as EditText,
|
|
||||||
PageFontsContainer as PageFonts,
|
export {
|
||||||
PageAddFormattingContainer as PageAdditionalFormatting,
|
EditTextContainer as EditText,
|
||||||
PageBulletsContainer as PageBullets,
|
PageTextFonts,
|
||||||
PageNumbersContainer as PageNumbers,
|
PageTextAddFormatting,
|
||||||
PageLineSpacingContainer as PageLineSpacing};
|
PageTextBullets,
|
||||||
|
PageTextNumbers,
|
||||||
|
PageTextLineSpacing,
|
||||||
|
PageTextFontColor,
|
||||||
|
PageTextCustomFontColor,
|
||||||
|
PageTextBackgroundColor,
|
||||||
|
PageTextCustomBackColor
|
||||||
|
};
|
|
@ -1,9 +1,79 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import StatusbarView from '../view/Statusbar';
|
import StatusbarView from '../view/Statusbar';
|
||||||
|
import { inject } from 'mobx-react';
|
||||||
|
|
||||||
const Statusbar = props => {
|
const Statusbar = inject('sheets')(props => {
|
||||||
return <StatusbarView />
|
const {sheets} = props;
|
||||||
};
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("status bar did mount");
|
||||||
|
|
||||||
|
Common.Notifications.on('document:ready', onApiSheetsChanged);
|
||||||
|
Common.Notifications.on('engineCreated', api => {
|
||||||
|
api.asc_registerCallback('asc_onSheetsChanged', onApiSheetsChanged.bind(api));
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onApiSheetsChanged = api => {
|
||||||
|
console.log('on api sheets changed');
|
||||||
|
|
||||||
|
!api && (api = Common.EditorApi.get());
|
||||||
|
|
||||||
|
const sheets_count = api.asc_getWorksheetsCount();
|
||||||
|
const active_index = api.asc_getActiveWorksheetIndex();
|
||||||
|
let i = -1, items = [];
|
||||||
|
|
||||||
|
while ( ++i < sheets_count ) {
|
||||||
|
const tab = {
|
||||||
|
index : i,
|
||||||
|
active : active_index == i,
|
||||||
|
name : api.asc_getWorksheetName(i),
|
||||||
|
locked : api.asc_isWorksheetLockedOrDeleted(i),
|
||||||
|
hidden : api.asc_isWorksheetHidden(i),
|
||||||
|
color : api.asc_getWorksheetTabColor(i)
|
||||||
|
};
|
||||||
|
|
||||||
|
items.push(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
sheets.reset(items);
|
||||||
|
// this.hiddensheets.reset(hiddentems);
|
||||||
|
|
||||||
|
// this.updateTabsColors();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTabClicked = i => {
|
||||||
|
const model = sheets.at(i);
|
||||||
|
|
||||||
|
const api = Common.EditorApi.get();
|
||||||
|
api.asc_showWorksheet(model.index);
|
||||||
|
sheets.setActiveWorksheet(i);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onAddTabClicked = () => {
|
||||||
|
const api = Common.EditorApi.get();
|
||||||
|
api.asc_closeCellEditor();
|
||||||
|
|
||||||
|
const createSheetName = () => {
|
||||||
|
let items = [], wc = api.asc_getWorksheetsCount();
|
||||||
|
while (wc--) {
|
||||||
|
items.push(api.asc_getWorksheetName(wc).toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
let index = 0, name;
|
||||||
|
while(++index < 1000) {
|
||||||
|
name = /*this.strSheet*/ 'Sheet' + index;
|
||||||
|
if (items.indexOf(name.toLowerCase()) < 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
};
|
||||||
|
|
||||||
|
api.asc_addWorksheet(createSheetName());
|
||||||
|
};
|
||||||
|
|
||||||
|
return <StatusbarView onTabClicked={onTabClicked} onAddTabClicked={onAddTabClicked} />
|
||||||
|
});
|
||||||
|
|
||||||
export default Statusbar;
|
export default Statusbar;
|
|
@ -1,6 +1,9 @@
|
||||||
|
|
||||||
@themeColor: #40865c;
|
@themeColor: #40865c;
|
||||||
|
|
||||||
|
@import '../../../../common/mobile/resources/less/variables.less';
|
||||||
|
@import '../../../../../vendor/framework7-react/node_modules/framework7/less/mixins.less';
|
||||||
|
|
||||||
@import '../../../../common/mobile/resources/less/_mixins.less';
|
@import '../../../../common/mobile/resources/less/_mixins.less';
|
||||||
@import '../../../../common/mobile/resources/less/collaboration.less';
|
@import '../../../../common/mobile/resources/less/collaboration.less';
|
||||||
@import '../../../../common/mobile/resources/less/common.less';
|
@import '../../../../common/mobile/resources/less/common.less';
|
||||||
|
@ -12,6 +15,7 @@
|
||||||
@import './icons-material.less';
|
@import './icons-material.less';
|
||||||
@import './icons-common.less';
|
@import './icons-common.less';
|
||||||
@import './celleditor.less';
|
@import './celleditor.less';
|
||||||
|
@import './statusbar.less';
|
||||||
|
|
||||||
.page[data-name='home'] {
|
.page[data-name='home'] {
|
||||||
.page-content {
|
.page-content {
|
||||||
|
|
58
apps/spreadsheeteditor/mobile/src/less/statusbar.less
Normal file
58
apps/spreadsheeteditor/mobile/src/less/statusbar.less
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
@statusbar-height: 30px;
|
||||||
|
@fontColor: #000;
|
||||||
|
|
||||||
|
.statusbar {
|
||||||
|
.hairline(top, @border-regular-control);
|
||||||
|
height: @statusbar-height;
|
||||||
|
min-height: @statusbar-height;
|
||||||
|
background-color: @background-normal;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
border: 0 none;
|
||||||
|
border-radius: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: inherit;
|
||||||
|
min-width: 48px;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 10px;
|
||||||
|
text-align: center;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.hairline(right, @border-regular-control);
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusbar--box-tabs {
|
||||||
|
> ul {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
|
white-space: pre;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
> li {
|
||||||
|
a {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 0 10px 0;
|
||||||
|
line-height: @statusbar-height;
|
||||||
|
color: @text-normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.active) {
|
||||||
|
a {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i.icon {
|
||||||
|
&.icon-plus {
|
||||||
|
.encoded-svg-background('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 22 22" fill="@{fontColor}"><g><path d="M22,12H12v10h-1V12H1v-1h10V1h1v10h10V12z"/></g></svg>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
// import {storeDocumentSettings} from './documentSettings';
|
// import {storeDocumentSettings} from './documentSettings';
|
||||||
// import {storeFocusObjects} from "./focusObjects";
|
// import {storeFocusObjects} from "./focusObjects";
|
||||||
import {storeUsers} from '../../../../common/mobile/lib/store/users';
|
import {storeUsers} from '../../../../common/mobile/lib/store/users';
|
||||||
|
import {storeWorksheets} from './sheets';
|
||||||
// import {storeTextSettings} from "./textSettings";
|
// import {storeTextSettings} from "./textSettings";
|
||||||
// import {storeParagraphSettings} from "./paragraphSettings";
|
// import {storeParagraphSettings} from "./paragraphSettings";
|
||||||
// import {storeShapeSettings} from "./shapeSettings";
|
// import {storeShapeSettings} from "./shapeSettings";
|
||||||
|
@ -13,6 +14,7 @@ export const stores = {
|
||||||
// storeFocusObjects: new storeFocusObjects(),
|
// storeFocusObjects: new storeFocusObjects(),
|
||||||
// storeDocumentSettings: new storeDocumentSettings(),
|
// storeDocumentSettings: new storeDocumentSettings(),
|
||||||
users: new storeUsers(),
|
users: new storeUsers(),
|
||||||
|
sheets: new storeWorksheets()
|
||||||
// storeTextSettings: new storeTextSettings(),
|
// storeTextSettings: new storeTextSettings(),
|
||||||
// storeParagraphSettings: new storeParagraphSettings(),
|
// storeParagraphSettings: new storeParagraphSettings(),
|
||||||
// storeShapeSettings: new storeShapeSettings(),
|
// storeShapeSettings: new storeShapeSettings(),
|
||||||
|
|
52
apps/spreadsheeteditor/mobile/src/store/sheets.js
Normal file
52
apps/spreadsheeteditor/mobile/src/store/sheets.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
|
||||||
|
import {observable, action} from 'mobx';
|
||||||
|
|
||||||
|
class Worksheet {
|
||||||
|
@observable sheet = {
|
||||||
|
index : -1,
|
||||||
|
active : false,
|
||||||
|
name : '',
|
||||||
|
locked : false,
|
||||||
|
hidden : false,
|
||||||
|
color : ''
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(data = {}) {
|
||||||
|
this.sheet.merge(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class storeWorksheets {
|
||||||
|
@observable sheets;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.sheets = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
@action reset(sheets) {
|
||||||
|
this.sheets = Object.values(sheets)
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setActiveWorksheet(i) {
|
||||||
|
if ( !this.sheets[i].active ) {
|
||||||
|
this.sheets.forEach(model => {
|
||||||
|
if ( model.active )
|
||||||
|
model.active = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.sheets[i].active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
at(i) {
|
||||||
|
return this.sheets[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
hasHiddenWorksheet() {
|
||||||
|
return this.sheets.some(model => model.hidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
hiddenWorksheets() {
|
||||||
|
return this.sheets.filter(model => model.hidden);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,34 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { View, Toolbar, Link } from 'framework7-react';
|
import { View, Toolbar, Link, Icon } from 'framework7-react';
|
||||||
|
import { observer, inject } from "mobx-react";
|
||||||
|
|
||||||
const viewStyle = {
|
const viewStyle = {
|
||||||
height: 30
|
height: 30
|
||||||
};
|
};
|
||||||
|
|
||||||
const StatusbarView = props => {
|
const StatusbarView = inject('sheets')(observer(props => {
|
||||||
return <View id="idx-statusbar" style={viewStyle}>
|
const { sheets } = props;
|
||||||
<Toolbar tabbar bottom>
|
|
||||||
<Link>Sheet 1</Link>
|
const getTabClassList = model =>
|
||||||
<Link>Sheet 2</Link>
|
`tab ${model.active ? 'active':''} ${model.locked ? 'locked':''}`;
|
||||||
</Toolbar>
|
|
||||||
|
return <View id="idx-statusbar" className="statusbar" style={viewStyle}>
|
||||||
|
<div id="idx-box-add-tab">
|
||||||
|
<Link href="false" id="idx-btn-addtab" className="tab" onClick={e => props.onAddTabClicked()}>
|
||||||
|
<Icon className="icon icon-plus" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="statusbar--box-tabs">
|
||||||
|
<ul className="sheet-tabs bottom">
|
||||||
|
{sheets.sheets.map((model,i) =>
|
||||||
|
model.hidden ? null :
|
||||||
|
<li className={getTabClassList(model)} key={i}>
|
||||||
|
<a onClick={e => props.onTabClicked(i)}>{model.name}</a>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</View>;
|
</View>;
|
||||||
};
|
}));
|
||||||
|
|
||||||
export default StatusbarView;
|
export default StatusbarView;
|
||||||
|
|
Loading…
Reference in a new issue