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
ad20c5f2
Commit
ad20c5f2
authored
Feb 09, 2022
by
Lyza Danger Gardner
Committed by
Lyza Gardner
Feb 11, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrate annotator `Buckets` to modern styles, components, tailwind
parent
3a5aa936
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
269 additions
and
301 deletions
+269
-301
Buckets.js
src/annotator/components/Buckets.js
+99
-97
Buckets-test.js
src/annotator/components/test/Buckets-test.js
+63
-23
Buckets.scss
src/styles/annotator/components/Buckets.scss
+96
-41
buttons.scss
src/styles/mixins/buttons.scss
+0
-140
tailwind.config.mjs
tailwind.config.mjs
+11
-0
No files found.
src/annotator/components/Buckets.js
View file @
ad20c5f2
import
{
LabeledButton
}
from
'@hypothesis/frontend-shared'
;
import
classnames
from
'classnames'
;
/**
* @typedef {import('../util/buckets').Bucket} Bucket
* @typedef {import("preact").ComponentChildren} Children
*/
/**
*
A left-pointing indicator button that, when hovered or clicked, highlights
*
or selects associated annotations
.
*
Render a set of buckets in a vertical channel positioned along the edge of
*
the sidebar
.
*
* @param {object} props
* @param {Bucket} props.bucket
* @param {(tags: string[]) => void} props.onFocusAnnotations
* @param {(tags: string[], toggle: boolean) => void} props.onSelectAnnotations
* @prop {Children} props.children
*/
function
BucketButton
({
bucket
,
onFocusAnnotations
,
onSelectAnnotations
})
{
const
buttonTitle
=
`Select nearby annotations (
${
bucket
.
tags
.
size
}
)`
;
function
selectAnnotations
(
event
)
{
onSelectAnnotations
([...
bucket
.
tags
],
event
.
metaKey
||
event
.
ctrlKey
);
}
/** @param {boolean} hasFocus */
function
setFocus
(
hasFocus
)
{
if
(
hasFocus
)
{
onFocusAnnotations
([...
bucket
.
tags
]);
}
else
{
onFocusAnnotations
([]);
}
}
function
BucketList
({
children
})
{
return
(
<
button
className
=
"Buckets__button Buckets__button--left"
onClick
=
{
event
=>
selectAnnotations
(
event
)}
onBlur
=
{()
=>
setFocus
(
false
)}
onFocus
=
{()
=>
setFocus
(
true
)}
onMouseEnter
=
{()
=>
setFocus
(
true
)}
onMouseOut
=
{()
=>
setFocus
(
false
)}
title
=
{
buttonTitle
}
aria
-
label
=
{
buttonTitle
}
<
ul
className
=
{
classnames
(
// 2020-11-20: Making bucket bar one pixel wider (23px vs 22px) is an
// interim and pragmatic solution for an apparent glitch on
// Safari and Chrome. Adding one pixel resolves this issue:
// https://github.com/hypothesis/client/pull/2750
'absolute w-[23px] left-[-22px] h-full'
,
// The background is set to low opacity when the sidebar is collapsed.
'bg-grey-2 annotator-collapsed:bg-black/[.08]'
,
// Disable pointer events along the sidebar itself; re-enable them in
// bucket indicator buttons
'pointer-events-none'
)}
>
{
bucket
.
tags
.
size
}
<
/
button
>
{
children
}
<
/
ul
>
);
}
/**
* An up- or down-pointing button that will scroll to the next closest bucket
* of annotations in the given direction.
* Render a vertically-positioned bucket-list item.
*
* @param {object} props
* @param {Bucket} props.bucket
* @param {'down'|'up'} props.direction
* @param {(tags: string[]) => void} props.onFocusAnnotations
* @param {(tags: string[], direction: 'down'|'up') => void} props.onScrollToClosestOffScreenAnchor
* @prop {Children} props.children
* @prop {number} props.topPosition - The vertical top position, in pixels,
* for this bucket item relative to the top of the containing BucketList
*/
function
NavigationBucketButton
({
bucket
,
direction
,
onFocusAnnotations
,
onScrollToClosestOffScreenAnchor
,
})
{
const
buttonTitle
=
`Go
${
direction
}
to next annotations (
${
bucket
.
tags
.
size
}
)`
;
/** @param {boolean} hasFocus */
function
setFocus
(
hasFocus
)
{
if
(
hasFocus
)
{
onFocusAnnotations
([...
bucket
.
tags
]);
}
else
{
onFocusAnnotations
([]);
}
}
function
BucketItem
({
children
,
topPosition
})
{
return
(
<
button
className
=
{
classnames
(
'Buckets__button'
,
`Buckets__button--
${
direction
}
`
)}
onClick
=
{()
=>
onScrollToClosestOffScreenAnchor
([...
bucket
.
tags
],
direction
)
}
onBlur
=
{()
=>
setFocus
(
false
)}
onFocus
=
{()
=>
setFocus
(
true
)}
onMouseEnter
=
{()
=>
setFocus
(
true
)}
onMouseOut
=
{()
=>
setFocus
(
false
)}
title
=
{
buttonTitle
}
aria
-
label
=
{
buttonTitle
}
<
li
className
=
{
classnames
(
'absolute right-0'
,
// Re-enable pointer events, which are disabled on the containing list
'pointer-events-auto'
)}
style
=
{{
top
:
topPosition
}}
>
{
bucket
.
tags
.
size
}
<
/
button
>
{
children
}
<
/
li
>
);
}
...
...
@@ -114,40 +81,75 @@ export default function Buckets({
const
showDownNavigation
=
below
.
tags
.
size
>
0
;
return
(
<
ul
className
=
"Buckets__list"
>
<
BucketList
>
{
showUpNavigation
&&
(
<
li
className
=
"Buckets__bucket"
style
=
{{
top
:
above
.
position
}}
>
<
NavigationBucketButton
bucket
=
{
above
}
direction
=
"up"
onFocusAnnotations
=
{
onFocusAnnotations
}
onScrollToClosestOffScreenAnchor
=
{
onScrollToClosestOffScreenAnchor
}
/
>
<
/li
>
<
BucketItem
topPosition
=
{
above
.
position
}
>
<
LabeledButton
className
=
{
classnames
(
'BucketButton UpBucketButton'
,
// Center the button vertically at `above.position` by pulling
// its top margin up by about half the button's height.
// This puts it nearer the toolbar's other buttons above the
// bucket list.
'right-0 mt-[-11px]'
)}
data
-
testid
=
"up-navigation-button"
onClick
=
{()
=>
onScrollToClosestOffScreenAnchor
([...
above
.
tags
],
'up'
)
}
onBlur
=
{()
=>
onFocusAnnotations
([])}
onFocus
=
{()
=>
onFocusAnnotations
([...
above
.
tags
])}
onMouseEnter
=
{()
=>
onFocusAnnotations
([...
above
.
tags
])}
onMouseOut
=
{()
=>
onFocusAnnotations
([])}
title
=
{
`Go up to next annotations (
${
above
.
tags
.
size
}
)`
}
>
{
above
.
tags
.
size
}
<
/LabeledButton
>
<
/BucketItem
>
)}
{
buckets
.
map
((
bucket
,
index
)
=>
(
<
li
className
=
"Buckets__bucket"
style
=
{{
top
:
bucket
.
position
}}
key
=
{
index
}
<
BucketItem
topPosition
=
{
bucket
.
position
}
key
=
{
index
}
>
<
LabeledButton
className
=
{
classnames
(
'BucketButton LeftBucketButton'
,
// Center the bucket indicator button vertically on `bucket.position`
// by pulling it by half the height of the button
'right-0 mt-[-8px]'
)}
onClick
=
{
event
=>
onSelectAnnotations
(
[...
bucket
.
tags
],
event
.
metaKey
||
event
.
ctrlKey
)
}
onBlur
=
{()
=>
onFocusAnnotations
([])}
onFocus
=
{()
=>
onFocusAnnotations
([...
bucket
.
tags
])}
onMouseEnter
=
{()
=>
onFocusAnnotations
([...
bucket
.
tags
])}
onMouseOut
=
{()
=>
onFocusAnnotations
([])}
title
=
{
`Select nearby annotations (
${
bucket
.
tags
.
size
}
)`
}
>
<
BucketButton
bucket
=
{
bucket
}
onFocusAnnotations
=
{
onFocusAnnotations
}
onSelectAnnotations
=
{
onSelectAnnotations
}
/
>
<
/li
>
{
bucket
.
tags
.
size
}
<
/LabeledButton
>
<
/BucketItem
>
))}
{
showDownNavigation
&&
(
<
li
className
=
"Buckets__bucket"
style
=
{{
top
:
below
.
position
}}
>
<
NavigationBucketButton
bucket
=
{
below
}
direction
=
"down"
onFocusAnnotations
=
{
onFocusAnnotations
}
onScrollToClosestOffScreenAnchor
=
{
onScrollToClosestOffScreenAnchor
}
/
>
<
/li
>
<
BucketItem
topPosition
=
{
below
.
position
}
>
<
LabeledButton
className
=
"BucketButton DownBucketButton right-0"
data
-
testid
=
"down-navigation-button"
onClick
=
{()
=>
onScrollToClosestOffScreenAnchor
([...
below
.
tags
],
'down'
)
}
onBlur
=
{()
=>
onFocusAnnotations
([])}
onFocus
=
{()
=>
onFocusAnnotations
([...
below
.
tags
])}
onMouseEnter
=
{()
=>
onFocusAnnotations
([...
below
.
tags
])}
onMouseOut
=
{()
=>
onFocusAnnotations
([])}
title
=
{
`Go up to next annotations (
${
below
.
tags
.
size
}
)`
}
>
{
below
.
tags
.
size
}
<
/LabeledButton
>
<
/BucketItem
>
)}
<
/
ul
>
<
/
BucketList
>
);
}
src/annotator/components/test/Buckets-test.js
View file @
ad20c5f2
...
...
@@ -45,37 +45,76 @@ describe('Buckets', () => {
);
describe
(
'up and down navigation'
,
()
=>
{
it
(
'focuses associated anchors when mouse enters the element'
,
()
=>
{
const
upButtonSelector
=
'[data-testid="up-navigation-button"] button'
;
const
downButtonSelector
=
'[data-testid="down-navigation-button"] button'
;
it
(
'focuses associated anchors above the screen when mouse enters the element'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--up'
).
first
(
).
simulate
(
'mouseenter'
);
wrapper
.
find
(
upButtonSelector
).
simulate
(
'mouseenter'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
'a1'
,
'a2'
]);
});
it
(
'removes focus on associated anchors when mouse leaves the element'
,
()
=>
{
it
(
'focuses associated anchors below the screen when mouse enters the element'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
downButtonSelector
).
simulate
(
'mouseenter'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
'b1'
,
'b2'
]);
});
it
(
'removes focus on associated anchors above screen when mouse leaves the element'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--up'
).
first
(
).
simulate
(
'mouseout'
);
wrapper
.
find
(
upButtonSelector
).
simulate
(
'mouseout'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
});
it
(
'
focuses associated anchors when the element is focused
'
,
()
=>
{
it
(
'
removes focus on associated anchors below screen when mouse leaves the element
'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--up'
).
first
().
simulate
(
'focus'
);
wrapper
.
find
(
downButtonSelector
).
simulate
(
'mouseout'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
});
it
(
'focuses associated anchors above screen when the element is focused'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
upButtonSelector
).
simulate
(
'focus'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
'a1'
,
'a2'
]);
});
it
(
'removes focus on associated anchors when element is blurred'
,
()
=>
{
it
(
'focuses associated anchors below screen when the element is focused'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
downButtonSelector
).
simulate
(
'focus'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
'b1'
,
'b2'
]);
});
it
(
'removes focus on associated anchors above screen when element is blurred'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
upButtonSelector
).
simulate
(
'blur'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
});
it
(
'removes focus on associated anchors below screen when element is blurred'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--up'
).
first
(
).
simulate
(
'blur'
);
wrapper
.
find
(
downButtonSelector
).
simulate
(
'blur'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
...
...
@@ -83,9 +122,9 @@ describe('Buckets', () => {
it
(
'renders an up navigation button if there are above-screen anchors'
,
()
=>
{
const
wrapper
=
createComponent
();
const
upButton
=
wrapper
.
find
(
'.Buckets__button--up'
);
const
upButton
=
wrapper
.
find
(
upButtonSelector
);
// The list item element wrapping the button
const
bucketItem
=
wrapper
.
find
(
'
.Buckets__bucket
'
).
first
();
const
bucketItem
=
wrapper
.
find
(
'
BucketItem
'
).
first
();
assert
.
isTrue
(
upButton
.
exists
());
assert
.
equal
(
...
...
@@ -97,15 +136,15 @@ describe('Buckets', () => {
it
(
'does not render an up navigation button if there are no above-screen anchors'
,
()
=>
{
fakeAbove
=
{
tags
:
new
Set
(),
position
:
150
};
const
wrapper
=
createComponent
();
assert
.
isFalse
(
wrapper
.
find
(
'.Buckets__button--up'
).
exists
());
assert
.
isFalse
(
wrapper
.
find
(
upButtonSelector
).
exists
());
});
it
(
'renders a down navigation button if there are below-screen anchors'
,
()
=>
{
const
wrapper
=
createComponent
();
const
downButton
=
wrapper
.
find
(
'.Buckets__button--down'
);
const
downButton
=
wrapper
.
find
(
downButtonSelector
);
// The list item element wrapping the button
const
bucketItem
=
wrapper
.
find
(
'
.Buckets__bucket
'
).
last
();
const
bucketItem
=
wrapper
.
find
(
'
BucketItem
'
).
last
();
assert
.
isTrue
(
downButton
.
exists
());
assert
.
equal
(
...
...
@@ -117,12 +156,12 @@ describe('Buckets', () => {
it
(
'does not render a down navigation button if there are no below-screen anchors'
,
()
=>
{
fakeBelow
=
{
tags
:
new
Set
(),
position
:
550
};
const
wrapper
=
createComponent
();
assert
.
isFalse
(
wrapper
.
find
(
'.Buckets__button--down'
).
exists
());
assert
.
isFalse
(
wrapper
.
find
(
downButtonSelector
).
exists
());
});
it
(
'scrolls to anchors above when up navigation button is pressed'
,
()
=>
{
const
wrapper
=
createComponent
();
const
upButton
=
wrapper
.
find
(
'.Buckets__button--up'
);
const
upButton
=
wrapper
.
find
(
upButtonSelector
);
upButton
.
simulate
(
'click'
);
...
...
@@ -135,7 +174,7 @@ describe('Buckets', () => {
it
(
'scrolls to anchors below when down navigation button is pressed'
,
()
=>
{
const
wrapper
=
createComponent
();
const
downButton
=
wrapper
.
find
(
'.Buckets__button--down'
);
const
downButton
=
wrapper
.
find
(
downButtonSelector
);
downButton
.
simulate
(
'click'
);
...
...
@@ -148,16 +187,17 @@ describe('Buckets', () => {
});
describe
(
'on-screen buckets'
,
()
=>
{
const
bucketButtonSelector
=
'button[title^="Select nearby annotations"]'
;
it
(
'renders a bucket button for each bucket'
,
()
=>
{
const
wrapper
=
createComponent
();
assert
.
equal
(
wrapper
.
find
(
'.Buckets__button--left'
).
length
,
2
);
assert
.
equal
(
wrapper
.
find
(
bucketButtonSelector
).
length
,
2
);
});
it
(
'focuses on associated annotations when mouse enters the element'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--left'
).
first
().
simulate
(
'mouseenter'
);
wrapper
.
find
(
bucketButtonSelector
).
first
().
simulate
(
'mouseenter'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
't1'
,
't2'
]);
...
...
@@ -166,7 +206,7 @@ describe('Buckets', () => {
it
(
'removes focus on associated anchors when mouse leaves the element'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--left'
).
first
().
simulate
(
'mouseout'
);
wrapper
.
find
(
bucketButtonSelector
).
first
().
simulate
(
'mouseout'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
...
...
@@ -175,7 +215,7 @@ describe('Buckets', () => {
it
(
'focuses associated anchors when the element is focused'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--left'
).
first
().
simulate
(
'focus'
);
wrapper
.
find
(
bucketButtonSelector
).
first
().
simulate
(
'focus'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[
't1'
,
't2'
]);
...
...
@@ -184,7 +224,7 @@ describe('Buckets', () => {
it
(
'removes focus on associated annotations when element is blurred'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--left'
).
first
().
simulate
(
'blur'
);
wrapper
.
find
(
bucketButtonSelector
).
first
().
simulate
(
'blur'
);
assert
.
calledOnce
(
fakeOnFocusAnnotations
);
assert
.
calledWith
(
fakeOnFocusAnnotations
,
[]);
...
...
@@ -194,7 +234,7 @@ describe('Buckets', () => {
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--left'
)
.
find
(
bucketButtonSelector
)
.
first
()
.
simulate
(
'click'
,
{
metaKey
:
false
,
ctrlKey
:
false
});
...
...
@@ -208,7 +248,7 @@ describe('Buckets', () => {
const
wrapper
=
createComponent
();
wrapper
.
find
(
'.Buckets__button--left'
)
.
find
(
bucketButtonSelector
)
.
first
()
.
simulate
(
'click'
,
{
metaKey
:
true
,
ctrlKey
:
false
});
...
...
src/styles/annotator/components/Buckets.scss
View file @
ad20c5f2
@use
'../mixins/buttons'
;
@use
'../variables'
as
var
;
$bucket-bar-width
:
22px
;
.Buckets__list
{
background
:
var
.
$grey-2
;
// When sidebar is unfolded, remove the background transparency
pointer-events
:
none
;
position
:
absolute
;
height
:
100%
;
// 2020-11-20: interim and pragmatic solution for an apparent glitch on Safari and Chrome.
// Adding one pixel resolve this issue: https://github.com/hypothesis/client/pull/2750
width
:
$bucket-bar-width
+
1
;
left
:
-
(
$bucket-bar-width
);
}
/**
* These classes style buttons to appear as lozenges with an integrated arrow
* pointing left, up or down (right doesn't exist yet but could easily be added).
* *
* The arrow-points are created by the combination of borders and positioning.
* See https://css-tricks.com/snippets/css/css-triangle/ for a few examples
*
*/
// When the sidebar is collapsed, make the background semi-transparent so the
// text is visible throughout (useful for pages with tight margins)
.annotator-collapsed
.Buckets__list
{
background
:
rgba
(
0
,
0
,
0
,
0
.08
);
}
@layer
components
{
// Base styling for a button with a numerical badge that points either up,
// down or left. On its own, it will be lozenge-shaped. Compose with one
// of the directional classes below to style a button fully, e.g.
// `classname="BucketButton LeftBucketButton`
.BucketButton
{
// A lozenge-shaped element with very small text
@apply
w-
[
26px
]
h-
[
16px
]
absolute
border
bg-white
shadow
rounded
;
@apply
font-sans
text-center
text-tiny
font-bold
text-color-text-light
leading-none
;
.Buckets__bucket
{
position
:
absolute
;
right
:
0
;
}
// Establish :before and :after content for later manipulation into
// different pointer shapes and directions
&
:
:
before
,
&::
after
{
@apply
content-
[
""
]
absolute
border-transparent
;
}
}
.Buckets__button
{
// Need pointer events again. Necessary because of `pointer-events` rule
// in `.Buckets__list`
pointer-events
:
all
;
}
// Style a `BucketButton` to point left
.LeftBucketButton
{
@apply
rounded-r
rounded-l-sm
;
.Buckets__button--left
{
// Center the indicator vertically (the element is 16px tall)
margin-top
:
-8px
;
@include
buttons
.
indicator--left
;
}
// Position to the left of the button and centered vertically
&
:
:
before
,
&::
after
{
@apply
right-full
top-1
/
2
;
}
.Buckets__button--up
{
@include
buttons
.
indicator--up
;
// Vertically center the element (which is 22px high)
margin-top
:
-11px
;
}
// Create a grey wedge to the left of the button
// This will appear as the border around the pointy side
&
:
:
before
{
@apply
mt-
[
-8px
]
border-8
;
@apply
border-r-
[
5px
]
border-r-grey-3
;
}
// Create a white wedge to the left of the button, 1px smaller than
// grey wedge. This will composite on top of the grey wedge and serve as
// the white fill of the pointy side
&
:
:
after
{
@apply
mt-
[
-7px
]
border-
[
7px
]
;
@apply
border-r-
[
4px
]
border-r-white
;
}
}
// Style a `BucketButton` to point up
.UpBucketButton
{
// Z-index assures that left-pointing buttons will scroll behind this
@apply
z-1
rounded-t-sm
rounded-b
;
// Position above the button and horizontally centered
&
:
:
before
,
&::
after
{
@apply
top-auto
left-1
/
2
bottom-full
;
}
// Create a grey wedge at the top of the button
// This will appear as the border around the pointy side
&
:
:
before
{
@apply
ml-
[
-13px
]
border-
[
13px
]
;
@apply
border-b-
[
6px
]
border-b-grey-3
;
}
// Create a white wedge 1px smaller than the grey wedge, as "fill"
&
:
:
after
{
@apply
ml-
[
-12px
]
border-
[
12px
]
;
@apply
border-b-
[
5px
]
border-b-white
;
}
}
// Style a `BucketButton` to point down
.DownBucketButton
{
// Z-index assures that left-pointing buttons will scroll behind this
@apply
z-1
rounded-t
rounded-b-sm
;
// Position below the button and horizontally centered
&
:
:
before
,
&::
after
{
@apply
top-full
left-1
/
2
;
}
// Create a grey wedge at the bottom of the button
// This will appear as the border around the pointy side
&
:
:
before
{
@apply
ml-
[
-13px
]
border-
[
13px
]
;
@apply
border-t-
[
6px
]
border-t-grey-3
;
}
.Buckets__button--down
{
@include
buttons
.
indicator--down
;
// Create a white wedge 1px smaller than the grey wedge, as "fill"
&
:
:
after
{
@apply
ml-
[
-12px
]
border-
[
12px
]
;
@apply
border-t-
[
5px
]
border-t-white
;
}
}
}
src/styles/mixins/buttons.scss
View file @
ad20c5f2
...
...
@@ -17,7 +17,6 @@
*
* And pass 'my-component-button' as the `className` prop to `Button`.
*/
@use
'sass:math'
;
@use
'@hypothesis/frontend-shared/styles/mixins/focus'
;
...
...
@@ -139,142 +138,3 @@
color
:
var
.
$grey-semi
;
}
}
/**
* Mixins that style buttons to appear as lozenges with an integrated arrow
* pointing left, up or down (right doesn't exist yet but could easily be added).
* These indicators are used, e.g., in the bucket bar.
*
* These button or button-like elements consist of styles applied to the
* element itself, which create a rounded-rectangle lozenge with small-sized
* label text, as well as composited ::before and ::after pseudo-elements to
* create an arrow-pointer effect.
*
* The arrow-points are created by the combination of borders and positioning.
* See https://css-tricks.com/snippets/css/css-triangle/ for a few examples
*
*/
$indicator-width
:
26px
;
$indicator-height
:
16px
;
// How far the arrow-pointer "sticks out" from the main body of the lozenge
$indicator-horizontal-offset
:
5px
;
$indicator-vertical-offset
:
6px
;
@mixin
indicator-base
{
@include
reset-native-btn-styles
;
@include
utils
.
border
;
position
:
absolute
;
right
:
0
;
background-color
:
var
.
$color-background
;
width
:
$indicator-width
;
height
:
$indicator-height
;
// Font/text
text-align
:
center
;
color
:
var
.
$color-text--light
;
font-weight
:
bold
;
font-family
:
var
.
$sans-font-family
;
font-size
:
var
.
$annotator-bucket-bar-font-size
;
line-height
:
1
;
&
:
:
before
,
&::
after
{
content
:
''
;
position
:
absolute
;
// NB: use of 'inset' here fixes jagged diagonals in FF
// https://github.com/zurb/foundation/issues/2230
border
:
inset
transparent
;
}
}
@mixin
indicator-vertical-base
{
@include
indicator-base
;
@include
utils
.
shadow
;
z-index
:
1
;
&
:
:
before
,
&::
after
{
left
:
50%
;
}
}
@mixin
indicator--left
{
@include
indicator-base
;
border-radius
:
2px
4px
4px
2px
;
&
:
:
before
,
&::
after
{
right
:
100%
;
top
:
50%
;
}
// This creates a left-pointing "wedge" in grey
// offset to the left of the element
&
:
:
before
{
border-width
:
math
.
div
(
$indicator-height
,
2
);
border-right
:
$indicator-horizontal-offset
solid
var
.
$grey-3
;
margin-top
:
-1
*
math
.
div
(
$indicator-height
,
2
);
}
// This creates a left-pointing "wedge" in white, on top
// of the grey wedge and one pixel narrower so that the
// grey wedge appears as a border around it
&
:
:
after
{
border-width
:
math
.
div
(
$indicator-height
,
2
)
-
1
;
border-right
:
(
$indicator-horizontal-offset
-
1
)
solid
var
.
$color-background
;
margin-top
:
-1
*
(
math
.
div
(
$indicator-height
,
2
)
-
1
);
}
}
@mixin
indicator--up
{
@include
indicator-vertical-base
;
border-radius
:
2px
2px
4px
4px
;
&
:
:
before
,
&::
after
{
top
:
auto
;
bottom
:
100%
;
}
// Grey (border) arrow pointing up
&
:
:
before
{
border-width
:
math
.
div
(
$indicator-width
,
2
);
border-bottom
:
$indicator-vertical-offset
solid
var
.
$grey-3
;
margin-left
:
-1
*
math
.
div
(
$indicator-width
,
2
);
}
// White (fill) arrow pointing up
&
:
:
after
{
border-width
:
math
.
div
(
$indicator-width
,
2
)
-
1
;
border-bottom
:
(
$indicator-vertical-offset
-
1
)
solid
var
.
$color-background
;
margin-left
:
-1
*
(
math
.
div
(
$indicator-width
,
2
)
-
1
);
}
}
@mixin
indicator--down
{
@include
indicator-vertical-base
;
margin-top
:
0
;
border-radius
:
4px
4px
2px
2px
;
&
:
:
before
,
&::
after
{
top
:
100%
;
}
// Grey (border) arrow, pointing down
&
:
:
before
{
border-width
:
math
.
div
(
$indicator-width
,
2
);
border-top
:
$indicator-vertical-offset
solid
var
.
$grey-3
;
margin-left
:
-1
*
math
.
div
(
$indicator-width
,
2
);
}
// White (fill) arrow, pointing down
&
:
:
after
{
border-width
:
math
.
div
(
$indicator-width
,
2
)
-
1
;
border-top
:
(
$indicator-vertical-offset
-
1
)
solid
var
.
$color-background
;
margin-left
:
-1
*
(
math
.
div
(
$indicator-width
,
2
)
-
1
);
}
}
tailwind.config.mjs
View file @
ad20c5f2
import
tailwindConfig
from
'@hypothesis/frontend-shared/lib/tailwind.preset.js'
;
import
plugin
from
'tailwindcss/plugin.js'
;
export
default
{
presets
:
[
tailwindConfig
],
...
...
@@ -81,8 +82,18 @@ export default {
},
},
zIndex
:
{
1
:
'1'
,
2
:
'2'
,
},
},
},
plugins
:
[
plugin
(({
addVariant
})
=>
{
// Add a custom variant such that the `annotator-collapsed:` modifier
// is available. The `Sidebar` logic adds the `.annotator-collapsed`
// class to the sidebar frame when it's collapsed. This modifier allows
// sub-components to select for that state.
addVariant
(
'annotator-collapsed'
,
'.annotator-collapsed &'
);
}),
],
};
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