Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
36d6ce94
Commit
36d6ce94
authored
Apr 20, 2020
by
Lyza Danger Gardner
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add `ThreadCard` component
This component renders top-level threads as “cards” in sidebar
parent
c07d796e
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
193 additions
and
0 deletions
+193
-0
thread-card-test.js
src/sidebar/components/test/thread-card-test.js
+104
-0
thread-card.js
src/sidebar/components/thread-card.js
+62
-0
thread-card.scss
src/styles/sidebar/components/thread-card.scss
+26
-0
sidebar.scss
src/styles/sidebar/sidebar.scss
+1
-0
No files found.
src/sidebar/components/test/thread-card-test.js
0 → 100644
View file @
36d6ce94
import
{
mount
}
from
'enzyme'
;
import
{
createElement
}
from
'preact'
;
import
ThreadCard
from
'../thread-card'
;
import
{
$imports
}
from
'../thread-card'
;
import
{
checkAccessibility
}
from
'../../../test-util/accessibility'
;
import
mockImportedComponents
from
'../../../test-util/mock-imported-components'
;
describe
(
'ThreadCard'
,
()
=>
{
let
fakeDebounce
;
let
fakeFrameSync
;
let
fakeStore
;
let
fakeThread
;
function
createComponent
(
props
)
{
return
mount
(
<
ThreadCard
frameSync
=
{
fakeFrameSync
}
settings
=
{{}}
thread
=
{
fakeThread
}
{...
props
}
/
>
);
}
beforeEach
(()
=>
{
fakeDebounce
=
sinon
.
stub
().
returnsArg
(
0
);
fakeFrameSync
=
{
focusAnnotations
:
sinon
.
stub
(),
scrollToAnnotation
:
sinon
.
stub
(),
};
fakeStore
=
{
isAnnotationFocused
:
sinon
.
stub
().
returns
(
false
),
};
fakeThread
=
{
id
:
't1'
,
annotation
:
{
$tag
:
'myTag'
},
};
$imports
.
$mock
(
mockImportedComponents
());
$imports
.
$mock
({
'lodash.debounce'
:
fakeDebounce
,
'../store/use-store'
:
callback
=>
callback
(
fakeStore
),
});
});
afterEach
(()
=>
{
$imports
.
$restore
();
});
it
(
'renders a `Thread` for the passed `thread`'
,
()
=>
{
const
wrapper
=
createComponent
();
assert
(
wrapper
.
find
(
'Thread'
).
props
().
thread
===
fakeThread
);
});
it
(
'applies a focused CSS class if the annotation thread is focused'
,
()
=>
{
fakeStore
.
isAnnotationFocused
.
returns
(
true
);
const
wrapper
=
createComponent
();
assert
(
wrapper
.
find
(
'.thread-card'
).
hasClass
(
'is-focused'
));
});
it
(
'applies a CSS class if settings indicate a `clean` theme'
,
()
=>
{
const
wrapper
=
createComponent
({
settings
:
{
theme
:
'clean'
}
});
assert
(
wrapper
.
find
(
'.thread-card'
).
hasClass
(
'thread-card--theme-clean'
));
});
describe
(
'mouse and click events'
,
()
=>
{
it
(
'scrolls to the annotation when the `ThreadCard` is clicked'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.thread-card'
).
simulate
(
'click'
);
assert
.
calledWith
(
fakeFrameSync
.
scrollToAnnotation
,
'myTag'
);
});
it
(
'focuses the annotation thread when mouse enters'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.thread-card'
).
simulate
(
'mouseenter'
);
assert
.
calledWith
(
fakeFrameSync
.
focusAnnotations
,
sinon
.
match
([
'myTag'
]));
});
it
(
'unfocuses the annotation thread when mouse exits'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.thread-card'
).
simulate
(
'mouseleave'
);
assert
.
calledWith
(
fakeFrameSync
.
focusAnnotations
,
sinon
.
match
([]));
});
});
it
(
'should pass a11y checks'
,
checkAccessibility
({
content
:
()
=>
createComponent
(),
})
);
});
src/sidebar/components/thread-card.js
0 → 100644
View file @
36d6ce94
import
classnames
from
'classnames'
;
import
{
createElement
}
from
'preact'
;
import
{
useCallback
}
from
'preact/hooks'
;
import
debounce
from
'lodash.debounce'
;
import
propTypes
from
'prop-types'
;
import
useStore
from
'../store/use-store'
;
import
{
withServices
}
from
'../util/service-context'
;
import
Thread
from
'./thread'
;
/**
* A "top-level" `Thread`, rendered as a "card" in the sidebar. A `Thread`
* renders its own child `Thread`s within itself.
*/
function
ThreadCard
({
frameSync
,
settings
=
{},
thread
})
{
const
threadTag
=
thread
.
annotation
&&
thread
.
annotation
.
$tag
;
const
isFocused
=
useStore
(
store
=>
store
.
isAnnotationFocused
(
threadTag
));
const
focusThreadAnnotation
=
useCallback
(
debounce
(
tag
=>
{
const
focusTags
=
tag
?
[
tag
]
:
[];
frameSync
.
focusAnnotations
(
focusTags
);
},
10
),
[
frameSync
]
);
const
scrollToAnnotation
=
useCallback
(
tag
=>
{
frameSync
.
scrollToAnnotation
(
tag
);
},
[
frameSync
]
);
return
(
/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
<
div
onClick
=
{()
=>
scrollToAnnotation
(
threadTag
)}
onMouseEnter
=
{()
=>
focusThreadAnnotation
(
threadTag
)}
onMouseLeave
=
{()
=>
focusThreadAnnotation
(
null
)}
key
=
{
thread
.
id
}
className
=
{
classnames
(
'thread-card'
,
{
'is-focused'
:
isFocused
,
'thread-card--theme-clean'
:
settings
.
theme
===
'clean'
,
})}
>
<
Thread
thread
=
{
thread
}
showDocumentInfo
=
{
false
}
/
>
<
/div
>
);
}
ThreadCard
.
propTypes
=
{
thread
:
propTypes
.
object
.
isRequired
,
/** injected */
frameSync
:
propTypes
.
object
.
isRequired
,
settings
:
propTypes
.
object
,
};
ThreadCard
.
injectedProps
=
[
'frameSync'
,
'settings'
];
export
default
withServices
(
ThreadCard
);
src/styles/sidebar/components/thread-card.scss
0 → 100644
View file @
36d6ce94
@use
"../../variables"
as
var
;
.thread-card
{
margin-bottom
:
1em
;
padding
:
1em
;
border-radius
:
2px
;
box-shadow
:
0px
1px
1px
0px
rgba
(
0
,
0
,
0
,
0
.1
);
cursor
:
pointer
;
background-color
:
var
.
$white
;
&
.is-focused
{
box-shadow
:
0px
2px
3px
0px
rgba
(
0
,
0
,
0
,
0
.15
);
}
&
--theme-clean
{
// Give a little more space so that the border appears centered
// between cards
padding-bottom
:
1
.5em
;
border-bottom
:
1px
solid
var
.
$grey-2
;
box-shadow
:
none
;
&
:hover
{
box-shadow
:
none
;
}
}
}
src/styles/sidebar/sidebar.scss
View file @
36d6ce94
...
@@ -62,6 +62,7 @@
...
@@ -62,6 +62,7 @@
@use
'./components/tag-editor'
;
@use
'./components/tag-editor'
;
@use
'./components/tag-list'
;
@use
'./components/tag-list'
;
@use
'./components/thread'
;
@use
'./components/thread'
;
@use
'./components/thread-card'
;
@use
'./components/thread-list'
;
@use
'./components/thread-list'
;
@use
'./components/toast-messages'
;
@use
'./components/toast-messages'
;
@use
'./components/tooltip'
;
@use
'./components/tooltip'
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment