mirror of
https://github.com/nickzuber/meteorite.git
synced 2024-11-29 09:31:15 +03:00
New charts, small ui changes, few bug fixes
This commit is contained in:
parent
cb03dc5c34
commit
be96c50272
@ -15,13 +15,13 @@ It's actually pretty simple - we use GitHub's notifications API to get your noti
|
||||
|
||||
Using this information, we're able to give a score of importantce to each thread based on the history of reasons we saw coming in. For example, a pull request that is assigned to you, has your review requested, and has 30 comments on it, will be scored much higher than an issue you opened up and received a single comment of someone saying "nice" on it.
|
||||
|
||||
We're also able to hook into web notifications to alert you when you get a GitHub notification if you'd want - something like this is totally opt-in.
|
||||
We're also able to hook into desktop notifications to alert you when you get a GitHub notification if you'd want - something like this is totally opt-in.
|
||||
|
||||
Some key features include:
|
||||
|
||||
- Scores your notifications based on their importance, so we can surface the most critical updates at the top of your queue.
|
||||
- Provides you with quick context for why you're receiving each notification.
|
||||
- Allows you to opt in for web notifications whenever you recieve important update to help notify you right away.
|
||||
- Allows you to opt in for desktop notifications whenever you recieve important update to help notify you right away.
|
||||
- Protects you from useless spammy notifications that you don't care about.
|
||||
- Let's you focus in on specific types of notifications that matter to you, like when your review is requested for a pull request or you were assigned an issue.
|
||||
- Unlocks dope statistics that help you understand how you interact with notifications on a daily basis.
|
||||
|
BIN
src/images/iconCircle.png
Normal file
BIN
src/images/iconCircle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
src/images/logoSquare.png
Normal file
BIN
src/images/logoSquare.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Binary file not shown.
Before Width: | Height: | Size: 406 KiB After Width: | Height: | Size: 408 KiB |
@ -713,7 +713,7 @@ export default function Scene ({loggedIn, onLogout, ...props}) {
|
||||
</ItemText>
|
||||
<ItemText>
|
||||
<Icon.NotificationsOn style={{filter: 'invert(1)'}} />
|
||||
<p>Allows you to opt in for web notifications whenever you recieve important update to help notify you right away.</p>
|
||||
<p>Allows you to opt in for desktop notifications whenever you recieve important update to help notify you right away.</p>
|
||||
</ItemText>
|
||||
</Item>
|
||||
<Item className="item-text">
|
||||
|
@ -485,53 +485,164 @@ const SmallLink = styled('a')({
|
||||
}
|
||||
});
|
||||
|
||||
const BarGraph = styled('div')({
|
||||
const BarGraphDiv = styled('div')({
|
||||
position: 'relative',
|
||||
height: 100,
|
||||
':after': {
|
||||
content: `"Triaged notifications compared to last week"`,
|
||||
content: `"Notifications Read"`,
|
||||
position: 'absolute',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
textAlign: 'center',
|
||||
fontSize: 10,
|
||||
width: '100%',
|
||||
bottom: -30,
|
||||
textAlign: 'left',
|
||||
fontSize: 16,
|
||||
top: -67,
|
||||
left: -23,
|
||||
fontWeight: 500
|
||||
}
|
||||
});
|
||||
|
||||
const FauxGridLine = styled('div')({
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
height: 1,
|
||||
background: '#f3f3f3',
|
||||
}, ({offsetY, tick, showDecimals}) => ({
|
||||
bottom: offsetY,
|
||||
':after': tick !== false ? {
|
||||
content: showDecimals
|
||||
? `"${tick.toFixed(2).replace('.00', '')}"`
|
||||
: `"${Math.round(tick)}"`,
|
||||
position: 'absolute',
|
||||
top: '-6px',
|
||||
left: '-30px',
|
||||
width: '20px',
|
||||
textAlign: 'right',
|
||||
} : {}
|
||||
}));
|
||||
|
||||
const Legend = styled('div')({
|
||||
position: 'absolute',
|
||||
textAlign: 'left',
|
||||
top: -35,
|
||||
left: -23,
|
||||
});
|
||||
|
||||
const LegendItem = styled('div')({
|
||||
position: 'relative',
|
||||
display: 'inline-block',
|
||||
fontSize: 12,
|
||||
marginRight: 15,
|
||||
}, ({color}) => ({
|
||||
':before': {
|
||||
content: '" "',
|
||||
background: color,
|
||||
display: 'inline-block',
|
||||
height: 12,
|
||||
width: 12,
|
||||
borderRadius: 2,
|
||||
marginRight: 5,
|
||||
verticalAlign: 'middle'
|
||||
}
|
||||
}));
|
||||
|
||||
function BarGraph ({children, numLines, max, ...props}) {
|
||||
const height = 100;
|
||||
const gapSize = height / (numLines - 1);
|
||||
const yAxisTickOffset = gapSize / 100 * max;
|
||||
// Only show decimals if we have to, e.g. the steps are under 1.
|
||||
const showDecimals = yAxisTickOffset * numLines < 2;
|
||||
return (
|
||||
<BarGraphDiv>
|
||||
<Legend>
|
||||
<LegendItem color="#f2f9ff">Last week</LegendItem>
|
||||
<LegendItem color="#17aaf3">This week</LegendItem>
|
||||
</Legend>
|
||||
{new Array(numLines).fill(0).map((_, i) => (
|
||||
<FauxGridLine
|
||||
key={i}
|
||||
offsetY={i * gapSize}
|
||||
showDecimals={showDecimals}
|
||||
tick={yAxisTickOffset > 0 || i === 0 ? (
|
||||
i % 2 === 0 ? i * yAxisTickOffset : false
|
||||
) : (
|
||||
false
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
{children}
|
||||
</BarGraphDiv>
|
||||
);
|
||||
}
|
||||
|
||||
const Separator = styled('div')({
|
||||
position: 'relative',
|
||||
background: '#f3f3f3',
|
||||
width: '100%',
|
||||
height: 1,
|
||||
margin: '30px 0'
|
||||
});
|
||||
|
||||
const BarContainer = styled('div')({
|
||||
position: 'absolute',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around',
|
||||
justifyContent: 'space-evenly',
|
||||
width: '100%',
|
||||
height: 100,
|
||||
alignItems: 'flex-end',
|
||||
}, ({opacity}) => ({
|
||||
}, ({opacity, hide}) => ({
|
||||
'div': {
|
||||
opacity: opacity === undefined ? 1 : opacity
|
||||
background: opacity ? '#f2f9ff' : undefined,
|
||||
opacity: hide ? 0 : 1
|
||||
}
|
||||
}));
|
||||
|
||||
const stripe_size = 3;
|
||||
const Bar = styled('div')({
|
||||
position: 'relative',
|
||||
width: 20,
|
||||
width: 30,
|
||||
minHeight: 5,
|
||||
background: '#00d19a',
|
||||
borderRadius: 4,
|
||||
}, ({height, active, color = '#00d19a', visible = true}) => ({
|
||||
}, ({height, active, label, visible = true, bottomTick}) => ({
|
||||
height,
|
||||
background: !visible
|
||||
? 'none'
|
||||
: active
|
||||
? `repeating-linear-gradient(45deg, ${color}, ${color} ${stripe_size}px, ${color}55 ${stripe_size}px, ${color}55 ${stripe_size * 2}px)`
|
||||
: color,
|
||||
: active && false
|
||||
? `repeating-linear-gradient(45deg, #28abf0, #28abf0 ${stripe_size}px, #28abf055 ${stripe_size}px, #28abf055 ${stripe_size * 2}px)`
|
||||
: '#28abf0',
|
||||
':after': label ? {
|
||||
content: `"${label}"`,
|
||||
position: 'absolute',
|
||||
left: '-20px',
|
||||
width: '70px',
|
||||
textAlign: 'center',
|
||||
bottom: '-25px',
|
||||
color: '#3f464c',
|
||||
} : {},
|
||||
':before': bottomTick ? {
|
||||
content: '" "',
|
||||
position: 'absolute',
|
||||
background: '#f3f3f3',
|
||||
width: '1px',
|
||||
height: '8px',
|
||||
bottom: '-8px',
|
||||
left: '14px',
|
||||
} : {},
|
||||
}));
|
||||
|
||||
const PageCount = styled('div')({
|
||||
fontSize: 12,
|
||||
margin: '12px auto',
|
||||
width: '100%',
|
||||
textAlign: 'center',
|
||||
color: 'rgb(32, 33, 36)'
|
||||
});
|
||||
|
||||
const NotificationIconWrapper = styled('div')({
|
||||
background: '#22303f',
|
||||
borderRadius: 4,
|
||||
transform: 'scale(.65)'
|
||||
});
|
||||
|
||||
const EnhancedBar = withTooltip(Bar);
|
||||
const EnhancedTab = withTooltip(Tab);
|
||||
const EnhancedNavTab = withTooltip(NavTab);
|
||||
@ -541,16 +652,22 @@ const EnhancedIconHot = withTooltip(Icon.Hot);
|
||||
const EnhancedIconTimer = withTooltip(Icon.Timer);
|
||||
const EnhancedIconConvo = withTooltip(Icon.Convo);
|
||||
|
||||
function getPRIssueIcon (type, reasons) {
|
||||
const grow = 1.0;
|
||||
// @TODO if GitHub ever fixes their API, we can use `reasons` to know when
|
||||
// a PR/Issue merges/closes/etc.
|
||||
function getPRIssueIcon (type, _reasons) {
|
||||
const scale = 1.0;
|
||||
switch (type) {
|
||||
case 'PullRequest':
|
||||
return (
|
||||
<Icon.PrMerged shrink={grow} />
|
||||
<NotificationIconWrapper style={{background: '#00d299'}}>
|
||||
<Icon.PrMerged shrink={scale} style={{filter: 'invert(1)'}} />
|
||||
</NotificationIconWrapper>
|
||||
);
|
||||
case 'Issue':
|
||||
return (
|
||||
<Icon.IssueOpen shrink={grow} />
|
||||
<NotificationIconWrapper style={{background: '#00a8f6'}}>
|
||||
<Icon.IssueOpen shrink={scale} style={{filter: 'invert(1)'}} />
|
||||
</NotificationIconWrapper>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
@ -600,18 +717,19 @@ export default function Scene ({
|
||||
? Icon.NotificationsOn
|
||||
: Icon.NotificationsOff;
|
||||
|
||||
// console.log('notifications', notifications)
|
||||
// console.log('isFirstTimeUser', isFirstTimeUser)
|
||||
// console.log('notificationsPermission', notificationsPermission)
|
||||
|
||||
if (isFirstTimeUser && notifications.length > 10) {
|
||||
// probably prompt to mark all as read to start out since they prob don't use notifs
|
||||
}
|
||||
|
||||
stagedStatistics = stagedStatistics.map(n => parseInt(n, 10));
|
||||
|
||||
const highestStagedCount = stagedStatistics.reduce((n, m) => Math.max(n, m), 0);
|
||||
const lastWeekStats = stagedStatistics.slice(0, 7);
|
||||
const thisWeekStats = stagedStatistics.slice(7);
|
||||
let lastWeekStats = stagedStatistics.slice(0, 7);
|
||||
let thisWeekStats = stagedStatistics.slice(7);
|
||||
|
||||
// Trim off the weekends.
|
||||
lastWeekStats = lastWeekStats.slice(1, -1);
|
||||
thisWeekStats = thisWeekStats.slice(1, -1);
|
||||
|
||||
return (
|
||||
<div style={{marginTop: 60}}>
|
||||
@ -756,21 +874,23 @@ export default function Scene ({
|
||||
)}
|
||||
commented
|
||||
</EnhancedSidebarLink>
|
||||
<Separator style={{marginBottom: 90}} />
|
||||
<div style={{
|
||||
padding: 14,
|
||||
borderRadius: 4,
|
||||
height: 100,
|
||||
fontSize: 11,
|
||||
margin: '24px 8px 20px'
|
||||
margin: '62px 8px 20px',
|
||||
marginLeft: 30,
|
||||
}}>
|
||||
<BarGraph>
|
||||
<BarGraph numLines={6} max={highestStagedCount * 1.15}>
|
||||
{/* Last week's statistics */}
|
||||
<BarContainer opacity={0.15}>
|
||||
<BarContainer opacity={true}>
|
||||
{lastWeekStats.map((dayStats, i) => (
|
||||
<Bar
|
||||
key={i}
|
||||
color={getColorFromFilter(activeFilter)}
|
||||
height={(dayStats / highestStagedCount) * 100}
|
||||
// color={getColorFromFilter(activeFilter)}
|
||||
height={(dayStats / (highestStagedCount * 1.15)) * 100}
|
||||
/>
|
||||
))}
|
||||
</BarContainer>
|
||||
@ -779,35 +899,39 @@ export default function Scene ({
|
||||
{thisWeekStats.map((dayStats, i) => (
|
||||
<Bar
|
||||
key={i}
|
||||
color={getColorFromFilter(activeFilter)}
|
||||
active={currentTime.day() === i}
|
||||
label="Sunday"
|
||||
height={(dayStats / highestStagedCount) * 100}
|
||||
visible={currentTime.day() >= i}
|
||||
label={i % 2 === 0 ? getWeekday(i + 1) : null}
|
||||
bottomTick={true}
|
||||
// color={getColorFromFilter(activeFilter)}
|
||||
active={currentTime.day() === i + 1}
|
||||
height={(dayStats / (highestStagedCount * 1.15)) * 100}
|
||||
visible={currentTime.day() >= i + 1}
|
||||
/>
|
||||
))}
|
||||
</BarContainer>
|
||||
{/* Wrapper for tooltips */}
|
||||
<BarContainer opacity={0}>
|
||||
{/* <BarContainer hide={true}>
|
||||
{thisWeekStats.map((dayStats, i) => (
|
||||
<EnhancedBar
|
||||
key={i}
|
||||
style={{width: 33}}
|
||||
tooltip={getWeekday(i)}
|
||||
style={{width: 45}}
|
||||
tooltip={dayStats || '0'}
|
||||
tooltipOffsetY={
|
||||
(Math.max((dayStats / highestStagedCount) * 100, 5) * -1) + 85
|
||||
}
|
||||
tooltipOffsetX={5}
|
||||
tooltipOffsetX={17}
|
||||
tooltipSpeed={0}
|
||||
height={100}
|
||||
/>
|
||||
))}
|
||||
</BarContainer>
|
||||
</BarContainer> */}
|
||||
</BarGraph>
|
||||
</div>
|
||||
<Separator style={{marginTop: 60}} />
|
||||
<div style={{
|
||||
padding: 14,
|
||||
paddingTop: 8,
|
||||
margin: 34,
|
||||
marginTop: 0,
|
||||
position: 'relative',
|
||||
display: 'block',
|
||||
}}>
|
||||
@ -853,8 +977,8 @@ export default function Scene ({
|
||||
<EnhancedTab
|
||||
tooltip={!loading ? (
|
||||
notificationsPermission === 'granted'
|
||||
? "Turn off web notifications"
|
||||
: "Turn on web notifications"
|
||||
? "Turn off desktop notifications"
|
||||
: "Turn on desktop notifications"
|
||||
) : null}
|
||||
disabled={loading}>
|
||||
<NotificationsIcon
|
||||
@ -1044,7 +1168,7 @@ export default function Scene ({
|
||||
</TableItem>
|
||||
<TableItem width={100}>
|
||||
<InlineBlockContainer>
|
||||
{n.badges.map(badge => {
|
||||
{activeStatus === Status.QUEUED && n.badges.map(badge => {
|
||||
switch (badge) {
|
||||
case Badges.HOT:
|
||||
// lots of `reasons` within short time frame
|
||||
@ -1143,6 +1267,7 @@ export default function Scene ({
|
||||
)}
|
||||
</Notifications>
|
||||
</NotificationsContainer>
|
||||
{!loading && <PageCount>Page {page} out of {lastPage}</PageCount>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user