Skip to content

Commit

Permalink
feat(icons): custom icons
Browse files Browse the repository at this point in the history
  • Loading branch information
Birkbjo committed Feb 19, 2024
1 parent 54fb044 commit e1a49d9
Show file tree
Hide file tree
Showing 7 changed files with 491 additions and 117 deletions.
2 changes: 1 addition & 1 deletion scss/IconPicker/IconPicker.scss
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
&__scroll-box {
// This takes into account the primary and secundary header,
// footer and space above and below the dialog
height: calc(100vh - 320px);
height: calc(100vh - 330px);
max-height: 1200px;
overflow-y: auto;
overflow-x: hidden;
Expand Down
14 changes: 13 additions & 1 deletion src/forms/form-fields/helpers/IconPickerDialog/Icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,18 @@ export default class Icon extends Component {
};
}

componentWillUnmount() {
delete this.img.onload
}

componentDidMount() {
this.img.onload = () => {
this.img.removeAttribute('data-loading');
try {
this.img.removeAttribute('data-loading');

} catch(e) {
console.log('failed', e);
}
};
}

Expand All @@ -33,6 +42,9 @@ export default class Icon extends Component {
alt={title}
title={title}
data-loading
loading="lazy"
width={60}
height={60}
className={`icon-picker__icon${classSuffix}`}
onClick={this.handleClick}
/>
Expand Down
133 changes: 133 additions & 0 deletions src/forms/form-fields/helpers/IconPickerDialog/IconList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import CircularProgress from 'd2-ui/lib/circular-progress/CircularProgress.js';
import Icon from './Icon.js';

export class IconList extends Component {
constructor(props, context) {
super(props, context);

this.d2 = context.d2;

this.state = {
loading: false,
pager: {
page: 1,
},
icons: [],
};

this.intersectionObserver = null;
this.loadingRef = null;
}

componentDidMount() {
this.intersectionObserver = new IntersectionObserver(
entries => {
if (this.state.loading) {
return;
}
const [{ isIntersecting }] = entries;

if (isIntersecting) {
console.log({ intersecting: isIntersecting });
}
},
{ threshold: 0.8 }
);

this.intersectionObserver.observe(this.loadingRef);

this.fetchIcons(1);
}

componentDidUpdate(prevProps) {
if (prevProps.textFilter !== this.props.textFilter) {
this.setState({ icons: [] }, () => this.fetchIcons(1));
}
}

componentWillUnmount() {
this.intersectionObserver.disconnect();
}

fetchIconAndAddToStartOfList = async key => {
const icon = await this.d2.Api.getApi().get(`/icons/${key}`);
this.setState(prevState => ({
icons: [icon, ...prevState.icons],
}));
};

fetchIcons = async page => {
const typeFilter = this.props.type === 'custom' ? 'custom' : 'default';
const filter = this.props.textFilter || '';
const response = await this.d2.Api.getApi().get('/icons', {
type: typeFilter,
paging: true,
page: page,
keys: filter,
});

this.setState(prevState => ({
pager: response.pager,
icons: [...prevState.icons, ...response.icons.slice(0,25)],
}));
};

render() {
const isLastPage =
this.state.pager.pageCount &&
this.state.pager.pageSize &&
this.state.pager.total &&
this.state.pager.page ===
Math.floor(this.state.pager.total / this.state.pager.pageSize);

const shouldShowLoading = this.state.loading || false;
const icons = this.props.prependedIcons
? [...this.props.prependedIcons, ...this.state.icons]
: this.state.icons;

return (
<div>
<div>
{this.state.selectedIcon && (
<Icon
icon={this.state.selectedIcon}
key={this.state.selectedIcon.key}
selectedIconKey={this.props.selectedIconKey}
handleClick={this.props.onIconSelect}
/>
)}
{icons.map(icon => (
<Icon
icon={icon}
key={icon.key}
selectedIconKey={this.props.selectedIconKey}
handleClick={this.props.onIconSelect}
/>
))}
</div>

<div
className="icon-picker__list-loader"
style={{ display: shouldShowLoading ? 'block' : 'none' }}
ref={ref => (this.loadingRef = ref)}
>
<CircularProgress />
</div>
</div>
);
}
}

IconList.propTypes = {
type: PropTypes.oneOf(['default', 'custom']).isRequired,
textFilter: PropTypes.string,
selectedIconKey: PropTypes.string,
onIconSelect: PropTypes.func.isRequired,
prependedIcons: PropTypes.array,
};

IconList.contextTypes = {
d2: PropTypes.object,
};
Loading

0 comments on commit e1a49d9

Please sign in to comment.