Commit 156ce129 authored by Lyza Danger Gardner's avatar Lyza Danger Gardner Committed by Lyza Gardner

Convert AnnotationQuote to Tailwind

parent 9d40fff9
...@@ -2,7 +2,7 @@ import { Actions } from '@hypothesis/frontend-shared'; ...@@ -2,7 +2,7 @@ import { Actions } from '@hypothesis/frontend-shared';
import classnames from 'classnames'; import classnames from 'classnames';
import { useStoreProxy } from '../../store/use-store'; import { useStoreProxy } from '../../store/use-store';
import { isSaved, quote } from '../../helpers/annotation-metadata'; import { isOrphan, isSaved, quote } from '../../helpers/annotation-metadata';
import { withServices } from '../../service-context'; import { withServices } from '../../service-context';
import AnnotationActionBar from './AnnotationActionBar'; import AnnotationActionBar from './AnnotationActionBar';
...@@ -83,7 +83,11 @@ function Annotation({ ...@@ -83,7 +83,11 @@ function Annotation({
/> />
{hasQuote && ( {hasQuote && (
<AnnotationQuote annotation={annotation} isFocused={isFocused} /> <AnnotationQuote
quote={quote(annotation)}
isFocused={isFocused}
isOrphan={isOrphan(annotation)}
/>
)} )}
{!isCollapsedReply && !isEditing && ( {!isCollapsedReply && !isEditing && (
......
import classnames from 'classnames'; import classnames from 'classnames';
import { isOrphan, quote } from '../../helpers/annotation-metadata';
import { withServices } from '../../service-context'; import { withServices } from '../../service-context';
import { applyTheme } from '../../helpers/theme'; import { applyTheme } from '../../helpers/theme';
...@@ -12,18 +11,14 @@ import Excerpt from '../Excerpt'; ...@@ -12,18 +11,14 @@ import Excerpt from '../Excerpt';
*/ */
/** /**
* @typedef AnnotationQuoteProps * Style content as quoted text
* @prop {Annotation} annotation
* @prop {boolean} [isFocused] - Is this annotation currently focused?
* @prop {SidebarSettings} [settings] - Used for theming.
*/
/**
* Display the selected text from the document associated with an annotation.
* *
* @parm {AnnotationQuoteProps} props * @param {object} props
* @param {import('preact').ComponentChildren} props.children
* @param {string} [props.classes] - Additional CSS classes
* @param {object} [props.style] - Inline style object
*/ */
function AnnotationQuote({ annotation, isFocused, settings = {} }) { function QuotedText({ children, classes, style }) {
// The language for the quote may be different than the client's UI (set by // The language for the quote may be different than the client's UI (set by
// `<html lang="...">`). // `<html lang="...">`).
// //
...@@ -35,29 +30,47 @@ function AnnotationQuote({ annotation, isFocused, settings = {} }) { ...@@ -35,29 +30,47 @@ function AnnotationQuote({ annotation, isFocused, settings = {} }) {
const documentLanguage = ''; const documentLanguage = '';
return ( return (
<div
className={classnames({
'is-orphan': isOrphan(annotation),
})}
>
<Excerpt
collapsedHeight={35}
inlineControls={true}
overflowThreshold={20}
>
<blockquote <blockquote
className={classnames('p-quoted-text', { className={classnames(
'is-focused': isFocused, 'border-l-[3px] border-grey-3 hover:border-l-blue-quote',
'p-redacted-content': isOrphan(annotation), 'italic text-color-text-light px-[1em]',
})} classes
)}
dir="auto" dir="auto"
lang={documentLanguage} lang={documentLanguage}
style={applyTheme(['selectionFontFamily'], settings)} style={style}
> >
{quote(annotation)} {children}
</blockquote> </blockquote>
);
}
/**
* @typedef AnnotationQuoteProps
* @prop {string} quote
* @prop {boolean} [isFocused] - Is this annotation currently focused?
* @prop {boolean} [isOrphan]
* @prop {SidebarSettings} [settings] - Used for theming.
*/
/**
* Display the selected text from the document associated with an annotation.
*
* @parm {AnnotationQuoteProps} props
*/
function AnnotationQuote({ quote, isFocused, isOrphan, settings = {} }) {
return (
<Excerpt collapsedHeight={35} inlineControls={true} overflowThreshold={20}>
<QuotedText
classes={classnames({
'border-l-blue-quote': isFocused,
'line-through grayscale contrast-50': isOrphan,
})}
style={applyTheme(['selectionFontFamily'], settings)}
>
{quote}
</QuotedText>
</Excerpt> </Excerpt>
</div>
); );
} }
......
...@@ -6,15 +6,14 @@ import { mockImportedComponents } from '../../../../test-util/mock-imported-comp ...@@ -6,15 +6,14 @@ import { mockImportedComponents } from '../../../../test-util/mock-imported-comp
import AnnotationQuote, { $imports } from '../AnnotationQuote'; import AnnotationQuote, { $imports } from '../AnnotationQuote';
describe('AnnotationQuote', () => { describe('AnnotationQuote', () => {
let fakeAnnotation; let fakeApplyTheme;
let fakeIsOrphan;
let fakeQuote;
function createQuote(props) { function createQuote(props) {
return mount( return mount(
<AnnotationQuote <AnnotationQuote
annotation={fakeAnnotation} quote={'test quote'}
isFocused={false} isFocused={false}
isOrphan={false}
settings={{}} settings={{}}
{...props} {...props}
/> />
...@@ -22,18 +21,12 @@ describe('AnnotationQuote', () => { ...@@ -22,18 +21,12 @@ describe('AnnotationQuote', () => {
} }
beforeEach(() => { beforeEach(() => {
fakeAnnotation = { fakeApplyTheme = sinon.stub().returns({});
target: [],
};
fakeQuote = sinon.stub().returns('test quote');
fakeIsOrphan = sinon.stub();
$imports.$mock(mockImportedComponents()); $imports.$mock(mockImportedComponents());
$imports.$mock({ $imports.$mock({
'../../helpers/annotation-metadata': { '../../helpers/theme': {
quote: fakeQuote, applyTheme: fakeApplyTheme,
isOrphan: fakeIsOrphan,
}, },
}); });
}); });
...@@ -48,6 +41,18 @@ describe('AnnotationQuote', () => { ...@@ -48,6 +41,18 @@ describe('AnnotationQuote', () => {
assert.equal(quote.text(), 'test quote'); assert.equal(quote.text(), 'test quote');
}); });
it('applies selectionFontFamily styling from settings', () => {
fakeApplyTheme
.withArgs(sinon.match.array.deepEquals(['selectionFontFamily']))
.returns({ fontFamily: 'monospace' });
const wrapper = createQuote();
const quote = wrapper.find('blockquote');
assert.equal(quote.getDOMNode().style.fontFamily, 'monospace');
});
it( it(
'should pass a11y checks', 'should pass a11y checks',
checkAccessibility({ checkAccessibility({
......
...@@ -19,22 +19,6 @@ ...@@ -19,22 +19,6 @@
} }
} }
// Represent quoted text, as in an excerpt, with a hover or focused state.
.p-quoted-text {
border-left: 3px solid var.$color-border;
color: var.$color-text--light;
font-style: italic;
padding: 0 var.$layout-space;
// Prevent long URLs etc. in quote causing overflow
overflow-wrap: break-word;
&.is-focused,
&:hover {
border-left: var.$color-quote 3px solid;
}
}
// A pattern for displaying redacted (moderated) text content // A pattern for displaying redacted (moderated) text content
.p-redacted-content { .p-redacted-content {
text-decoration: line-through; text-decoration: line-through;
......
...@@ -39,6 +39,9 @@ export default { ...@@ -39,6 +39,9 @@ export default {
'color-text': { 'color-text': {
inverted: '#f2f2f2', inverted: '#f2f2f2',
}, },
blue: {
quote: '#58cef4',
},
}, },
fontFamily: { fontFamily: {
mono: ['"Open Sans Mono"', 'Menlo', '"DejaVu Sans Mono"', 'monospace'], mono: ['"Open Sans Mono"', 'Menlo', '"DejaVu Sans Mono"', 'monospace'],
......
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