Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
71bc197
Initial commit
May 18, 2022
b7db8da
Updated to use ICON_LIST
May 18, 2022
dfe029a
Replace Icon button removed when options equal waffle-editor
May 18, 2022
9d1c7df
v0.7.0 added
May 18, 2022
6a291de
Initial commit
May 19, 2022
0f8d424
Updated to export IconSelector type
May 19, 2022
27b88b5
Initial commit
May 19, 2022
a5aea55
Font awesome class for text icons added
May 19, 2022
72a2f9d
Support for IconButton type added
May 19, 2022
3aa44fe
GetChartSettings now returns aCode and bCode
May 19, 2022
69921c2
Position changed to fixed. Grid layout for icon-library class added
May 19, 2022
5354f9b
Styles for .icon-library-button and .icon-library-close added
May 19, 2022
8ddf1ca
Class names added to components
May 19, 2022
f4300f7
IconSelector types added to chart data menu
May 19, 2022
6ae2d95
Ability to update icons added
May 19, 2022
cd9388a
Function changeIcon added to props
May 19, 2022
9305fd3
Styles for .waffle-data added
May 19, 2022
1ce9935
UpdateChartSettings now expects aCode and bCode instead of iconCode
May 19, 2022
2364bb0
v0.7.0 updated
May 19, 2022
291b036
Styles updated
May 20, 2022
6c71057
Class names added to certain components. Icon library now closes when…
May 20, 2022
4a991fa
Initial commit
May 20, 2022
b1f8cbd
useOutsideClick hook added
May 20, 2022
1349c03
Initial commit'
May 20, 2022
05354ba
ID attribute added to .editor-content
May 20, 2022
9878509
Updated to use portals. Scroll detection also added
May 20, 2022
e733399
Updated to find current position of IconButton and pass to IconLibrary
May 20, 2022
f03720b
Styles updated to work with IconLibrary's use of portals
May 20, 2022
ef7858f
Box shadow added to .icon-library-container
May 20, 2022
5de65da
Height and overflow control added
May 21, 2022
645aa99
Date updated
May 21, 2022
14b9175
Date updated
May 21, 2022
a762540
Initial commit
May 21, 2022
d535bcb
Hook useResizeDetection added
May 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
# Change Log
## [v0.7.0] - 2022-05-20
Ability to replace individual icons for WaffleChart type added
### Added
* ICON_LIST constant defined
* IconSelector types added (IconButton, IconLibrary, IconSelector)
* Custom hooks for detecting outside click, window resizing, and scrolling
### Changed
* Icon.js updated to use ICON_LIST
* AWaffleChart.GetChartSettings now returns preset A's and preset B's iconCode as aCode and bCode respectively
* AWaffleChart.SetChartSettings updated to adhere to new export format in GetChartSettings
### Removed
* Replace Icons button removed from toolbar when WaffleEditor is selected
## [v0.6.2] - 2022-05-18
### Changed
* AInfographic code reorganized
Expand Down
5 changes: 5 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@
*:disabled {
cursor: not-allowed;
}

.font-awesome {
font-family: "Font Awesome 5 Free";
font-weight: 900;
}

</style>

Expand Down
12 changes: 12 additions & 0 deletions src/components/Hooks/DetectResize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useEffect } from 'react';

const useResizeDetection = (callback) => {
useEffect(() => {
window.addEventListener('resize', callback);
return () => {
window.removeEventListener('resize', callback);
};
});
};

export default useResizeDetection;
26 changes: 26 additions & 0 deletions src/components/Hooks/DetectScrolling.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useEffect } from "react";

const useScrollDetection = (callback) => {
useEffect(() => {
/**
* Note that when an infographic is selected, most elements actually do
* not support scrolling. So, to detect scrolling, we have to manually
* add the callback to all scrollable elements.
*
* Below is NOT an exhaustive list, it is a list of the elements needed
* at the moment.
*/
const canvasContainer = document.getElementById('canvas-container');
const editor = document.getElementById('editor-content-scrollable');

canvasContainer.addEventListener('scroll', callback);
editor.addEventListener('scroll', callback);

return () => {
canvasContainer.removeEventListener('scroll', callback);
editor.removeEventListener('scroll', callback);
}
});
};

export default useScrollDetection;
24 changes: 24 additions & 0 deletions src/components/Hooks/HandleOutsideClick.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useEffect } from "react";

/**
* Code adapted from:
* https://stackoverflow.com/questions/32553158/detect-click-outside-react-component
* @param {*} ref Return value from useRef
* @param {function} callback Callback function to be ran when outside click detected
*/
const useOutsideClick = (ref, callback) => {
useEffect(() => {
const HandleOutsideClick = (event) => {
if (ref.current && !ref.current.contains(event.target)) {
callback();
}
}

document.addEventListener("mousedown", HandleOutsideClick);
return () => {
document.removeEventListener("mousedown", HandleOutsideClick);
}
}, [ref]);
}

export default useOutsideClick;
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Editor extends React.Component
<TabContainer
currentTab={this.state.currentTab}
onClick={(state) => { this._SetCurrentTab(state); }}/>
<div className='editor-content'>
<div id='editor-content-scrollable' className='editor-content'>
<div className='editor-menu-container'>
{this._DisplayContent()}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import '../../../../../css/React/Editors/IconButton.css'

/**
*
* @param {Object} props icon: string, iconColor: string, onClick: function,
*/
const IconButton = (props) => {
return (
<button className='icon-button' onClick={props.onClick}>
{
<span
className="font-awesome icon"
style={{color: props.iconColor}}>
{props.icon}
</span>}
</button>
)
};

export { IconButton };
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useRef } from 'react';
import ReactDOM from 'react-dom';
import useOutsideClick from '../../../../Hooks/HandleOutsideClick';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faTimesCircle } from '@fortawesome/free-solid-svg-icons';
import ICON_LIST from '../../../IconList';

import '../../../../../css/React/Editors/IconLibrary.css';
import useScrollDetection from '../../../../Hooks/DetectScrolling';
import useResizeDetection from '../../../../Hooks/DetectResize';

/**
*
* @param {Object} props closeLibrary: function, changeIcon: function, top, left
*/
const IconLibrary = (props) => {
const ref = useRef(null);

useOutsideClick(ref, props.closeLibrary);
useScrollDetection(props.closeLibrary);
useResizeDetection(props.closeLibrary);

return ReactDOM.createPortal(
<div ref={ref} className='icon-library-container' style={{top: props.top, left: props.left - 150}}>
<div className='icon-library-header'>
<button className='icon-library-close' onClick={props.closeLibrary}>
<FontAwesomeIcon className='close-icon' icon={faTimesCircle} />
</button>
</div>
<div className='icon-library'>
{
ICON_LIST.map(d => {
const changeIcon = () => {
const iconCode = String.fromCharCode(
parseInt(d.icon[3], 16));
props.closeLibrary();
props.changeIcon(iconCode);
}

return (
<button className='icon-library-button'
onClick={changeIcon}>
<FontAwesomeIcon className='icon-library-icon' icon={d} />
</button>
);
})
}
</div>
</div>
, document.getElementById('root'));
};

export { IconLibrary };
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useState, useRef } from 'react';
import ReactDOM from 'react-dom';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import { IconButton } from './IconButton';
import { IconLibrary } from './IconLibrary';

/**
* @param {Object} props icon: string, iconColor: string, changeIcon: function,
*/
const IconSelector = (props) => {
const [displayIcons, setDisplayIcons] = useState(false);

const ref = useRef(null);

const OpenIconLibrary = () => {
setDisplayIcons(true);
}

const CloseIconLibrary = () => {
setDisplayIcons(false);
}

const SetContent = () => {
if (displayIcons) {
let rect = ref.current.getBoundingClientRect()
return (
<IconLibrary closeLibrary={CloseIconLibrary}
changeIcon={props.changeIcon}
top={rect.top}
left={rect.left}/>
);
} else return (
<CSSTransition>
<IconButton
icon={props.icon}
iconColor={props.iconColor}
onClick={OpenIconLibrary}/>
</CSSTransition>
);
}

return (
<div ref={ref} className='icon-selector-container'>
<TransitionGroup>
{SetContent()}
</TransitionGroup>
</div>
);
}

export { IconSelector };
3 changes: 2 additions & 1 deletion src/components/InfographicEditor/Editors/Components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ export { LabeledDropdown } from './LabeledDropdown';
export { Slider } from './Slider';
export { LabeledSlider } from './LabeledSlider';
export { NumericTextField } from './NumericTextField';
export { LabeledNumericTextField } from './LabeledNumericTextField';
export { LabeledNumericTextField } from './LabeledNumericTextField';
export { IconSelector } from './IconSelector/IconSelector';
11 changes: 2 additions & 9 deletions src/components/InfographicEditor/Editors/Insert/Icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import React from 'react';

import '../../../../css/React/Editors/Insert/Insert.css';
import '../../../../css/React/Editors/Insert/Icon.css';
import { faAmbulance, faBrain, faCapsules, faFirstAid, faHeart, faHeartbeat,
faHospital, faLungs, faLungsVirus, faMedkit, faPills, faPrescription,
faPrescriptionBottle, faStethoscope, faSyringe, faUserMd, faWheelchair,
faFemale, } from '@fortawesome/free-solid-svg-icons';
import ICON_LIST from '../../IconList';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

class Icon extends React.Component
Expand All @@ -29,11 +26,7 @@ class Icon extends React.Component
* Note that accessing the 3rd index in fa{Name}'s icon attribute will
* give the unicode, which is what the canvas uses to draw the icons
*/
let iconList = [faAmbulance, faHeart, faHeartbeat, faHospital, faMedkit,
faPrescription, faPrescriptionBottle, faStethoscope, faUserMd,
faWheelchair, faBrain, faCapsules, faFirstAid, faLungs, faLungsVirus
, faPills, faSyringe, faFemale]
return iconList.map((d, i) => {
return ICON_LIST.map((d) => {
return (
<button className='insert-fa-icon-button'
onClick={() => { this.props.toggleInsert('icon', d.icon[3])}}>
Expand Down
12 changes: 10 additions & 2 deletions src/components/InfographicEditor/Editors/WaffleEditor.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { Menu, Editor, LabeledColorPicker, LabeledTextField, FontSelector, LabeledCheckbox,
LabeledNumericTextField } from './Components/index';
LabeledNumericTextField, IconSelector } from './Components/index';
import Lodash from 'lodash';
import '../../../css/React/Editors/WaffleEditor.css';
import '../../../css/React/Editors/ChartEditor.css';
Expand Down Expand Up @@ -62,7 +62,7 @@ class WaffleEditor extends React.Component
// ally), the LabeledTextFields would not rerender when undo/redo is
// called.
let chartDataContent = [
<div className='center'>
<div className='waffle-data center'>
<LabeledNumericTextField
label='Numerator:'
index={data.numerator}
Expand All @@ -72,6 +72,10 @@ class WaffleEditor extends React.Component
onlyPositive={true}
onChange={(d, i) => { this._SetChartData(0, d); }}
/>
<IconSelector
icon={this.props.cSettings.icon.aCode}
iconColor={this.props.cSettings.icon.aColor}
changeIcon={(icon) => { this._SetChartSettings('icon', 'aCode', icon)}}/>
<LabeledTextField
label='Denominator:'
index={data.denominator}
Expand All @@ -81,6 +85,10 @@ class WaffleEditor extends React.Component
onlyPositive={true}
onChange={(d, i) => { this._SetChartData(1, d); }}
/>
<IconSelector
icon={this.props.cSettings.icon.bCode}
iconColor={this.props.cSettings.icon.bColor}
changeIcon={(icon) => { this._SetChartSettings('icon', 'bCode', icon)}}/>
</div>
]

Expand Down
23 changes: 23 additions & 0 deletions src/components/InfographicEditor/IconList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* This file defines the set of avaliable icons in Florence's UI.
*
* To add new icons, search the for the necessary icons on FontAwesome's
* website and add them to the import statement starting on line 8. NOTE that
* this only imports solid icons, other styles require additional import
* statements. After the icons are imported, add them to ICON_LIST.
*
* NOTE that the order they appear in ICON_LIST defines the order they will
* appear in Florence's UI.
*/

import { faAmbulance, faBrain, faCapsules, faFirstAid, faHeart, faHeartbeat,
faHospital, faLungs, faLungsVirus, faMedkit, faPills, faPrescription,
faPrescriptionBottle, faStethoscope, faSyringe, faUserMd, faWheelchair,
faFemale, } from '@fortawesome/free-solid-svg-icons';

const ICON_LIST = [faAmbulance, faHeart, faHeartbeat, faHospital, faMedkit,
faPrescription, faPrescriptionBottle, faStethoscope, faUserMd,
faWheelchair, faBrain, faCapsules, faFirstAid, faLungs, faLungsVirus
, faPills, faSyringe, faFemale];

export default ICON_LIST;
5 changes: 3 additions & 2 deletions src/components/InfographicEditor/Toolbar/ToolbarContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ class ToolbarContent extends React.Component
{
if (this.props.options === 'bar-editor' || this.props.options === 'pie-editor'
|| this.props.options === 'stacked-bar-editor' || this.props.options === 'line-editor'
|| this.props.options === 'donut-editor' || this.props.options === 'update-chart') {
|| this.props.options === 'donut-editor' || this.props.options === 'update-chart'
|| this.props.options === 'waffle-editor') {
return this._CreateChartIcons();
} else if (this.props.options === 'text-editor') {
return this._CreateTextIcons();
Expand All @@ -134,7 +135,7 @@ class ToolbarContent extends React.Component
return this._CreateImageIcons();
} else if (this.props.options === 'icon-editor') {
return this._CreateIconIcons();
} else if (this.props.options === 'icon-bar-editor' || this.props.options === 'waffle-editor') {
} else if (this.props.options === 'icon-bar-editor') {
return this._CreateIconBarIcons();
}
}
Expand Down
15 changes: 15 additions & 0 deletions src/css/React/Editors/IconButton.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.icon-button {
border: none;
background-color: #fff;
position: relative;
top: 15px;
}

.icon-button:hover {
cursor: pointer;
background-color: #eee;
}

.icon {
font-size: 30px;
}
Loading