Commit 4b5751ea authored by Lyza Danger Gardner's avatar Lyza Danger Gardner

Refactor `AnnotationActionButton` to use SVG icons

Update annotation action icons to updated variants, adjust
CSS for improved layout and interaction; increase tap-target
size for mobile users.
parent 8e61efcf
......@@ -4,22 +4,31 @@ const classnames = require('classnames');
const propTypes = require('prop-types');
const { createElement } = require('preact');
function AnnotationActionButton({ icon, isDisabled, label, onClick }) {
const SvgIcon = require('./svg-icon');
function AnnotationActionButton({
className = '',
icon,
isDisabled,
label,
onClick,
}) {
return (
<button
className="btn btn-clean annotation-action-btn"
className={classnames('annotation-action-button', className)}
onClick={onClick}
disabled={isDisabled}
aria-label={label}
h-tooltip
title={label}
>
<i className={classnames(icon, 'btn-icon')} />
<SvgIcon name={icon} className="annotation-action-button__icon" />
</button>
);
}
AnnotationActionButton.propTypes = {
/** A CSS classname corresponding to an `h` icon */
className: propTypes.string,
/** The name of the SVGIcon to render */
icon: propTypes.string.isRequired,
isDisabled: propTypes.bool.isRequired,
label: propTypes.string.isRequired,
......
......@@ -80,7 +80,7 @@ function AnnotationShareControl({
return (
<div className="annotation-share-control" ref={shareRef}>
<AnnotationActionButton
icon="h-icon-annotation-share"
icon="share"
isDisabled={false}
label="Share"
onClick={toggleSharePanel}
......
'use strict';
const { createElement } = require('preact');
const { mount } = require('enzyme');
const AnnotationActionButton = require('../annotation-action-button');
const mockImportedComponents = require('./mock-imported-components');
describe('AnnotationActionButton', () => {
let fakeOnClick;
function createComponent(props = {}) {
return mount(
<AnnotationActionButton
icon="fakeIcon"
isDisabled={false}
label="My Action"
onClick={fakeOnClick}
{...props}
/>
);
}
beforeEach(() => {
fakeOnClick = sinon.stub();
AnnotationActionButton.$imports.$mock(mockImportedComponents());
});
afterEach(() => {
AnnotationActionButton.$imports.$restore();
});
it('applies any provided className to the button', () => {
const wrapper = createComponent({ className: 'my-class' });
assert.isTrue(wrapper.hasClass('my-class'));
});
});
......@@ -53,14 +53,15 @@
<!-- / Tags -->
<footer class="annotation-footer">
<div class="annotation-form-actions" ng-if="vm.editing()">
<annotation-publish-control
group="vm.group()"
is-disabled="!vm.hasContent()"
is-shared="vm.isShared()"
on-cancel="vm.revert()"
on-save="vm.save()"
on-set-privacy="vm.setPrivacy(level)"></annotation-publish-control>
<annotation-publish-control
group="vm.group()"
is-disabled="!vm.hasContent()"
is-shared="vm.isShared()"
on-cancel="vm.revert()"
on-save="vm.save()"
on-set-privacy="vm.setPrivacy(level)"></annotation-publish-control>
</div>
<div class="annotation-section annotation-license"
......@@ -88,21 +89,21 @@
<div class="annotation-actions" ng-if="!vm.isSaving && !vm.editing() && vm.id()">
<div ng-show="vm.isSaving">Saving…</div>
<annotation-action-button
icon="'h-icon-annotation-edit'"
icon="'edit'"
is-disabled="vm.isDeleted()"
label="'Edit'"
ng-show="vm.authorize('update') && !vm.isSaving"
on-click="vm.edit()"
></annotation-action-button>
<annotation-action-button
icon="'h-icon-annotation-delete'"
icon="'trash'"
is-disabled="vm.isDeleted()"
label="'Delete'"
ng-show="vm.authorize('delete')"
on-click="vm.delete()"
></annotation-action-button>
<annotation-action-button
icon="'h-icon-annotation-reply'"
icon="'reply'"
is-disabled="vm.isDeleted()"
label="'Reply'"
on-click="vm.reply()"
......@@ -112,14 +113,15 @@
</span>
<span ng-if="vm.canFlag()">
<annotation-action-button
icon="'h-icon-annotation-flag'"
icon="'flag'"
is-disabled="vm.isDeleted()"
label="'Report this annotation to the moderators'"
ng-if="!vm.isFlagged()"
on-click="vm.flag()"
></annotation-action-button>
<annotation-action-button
icon="'h-icon-annotation-flag annotation--flagged'"
class-name="'annotation-action-button--active'"
icon="'flag--active'"
is-disabled="vm.isDeleted()"
label="'Annotation has been reported to the moderators'"
ng-if="vm.isFlagged()"
......
......@@ -10,15 +10,33 @@
border-style: none;
}
/**
* Basic color, sizing, padding and hover for any button
*/
@mixin button-base {
@include reset-native-btn-styles;
padding: 0.5em;
color: var.$grey-5;
&__icon {
width: 16px;
height: 16px;
}
&:hover {
transition: 0.2s ease-out;
color: var.$grey-6;
}
}
/**
* A <button> composed of an SVG icon (left) and text (right) with some
* hover transition effects
*/
@mixin action-button($icon-margin: 0 5px) {
@include reset-native-btn-styles;
@include button-base;
display: flex;
align-items: center;
padding: 0.5em;
border-radius: 2px;
border: none;
background-color: var.$grey-1;
......@@ -31,9 +49,7 @@
}
&:hover {
transition: 0.2s ease-out;
background-color: var.$grey-2;
color: var.$grey-6;
}
}
......
@use "../../mixins/buttons";
@use "../../variables" as var;
.annotation-action-button {
@include buttons.button-base;
&--active {
color: var.$brand;
&:hover {
color: var.$brand;
}
}
}
@media (pointer: coarse) {
.annotation-action-button {
min-width: var.$touch-target-size;
min-height: var.$touch-target-size;
}
}
......@@ -10,8 +10,8 @@
.annotation-share-panel {
@include panel.panel--compact;
position: absolute;
right: -5px;
bottom: 30px;
right: 5px;
bottom: 32px;
width: 275px;
box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.15);
cursor: default;
......
......@@ -25,6 +25,7 @@
// Components
// ----------
@use './components/action-button';
@use './components/annotation-action-button';
@use './components/annotation';
@use './components/annotation-document-info';
@use './components/annotation-header';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment