Skip to content

Commit

Permalink
[desk-tool] Add basic user-based annotation colors
Browse files Browse the repository at this point in the history
  • Loading branch information
mariuslundgard authored and rexxars committed Oct 6, 2020
1 parent d56a6e2 commit 144b1e4
Show file tree
Hide file tree
Showing 14 changed files with 228 additions and 29 deletions.
15 changes: 9 additions & 6 deletions packages/@sanity/base/src/components/SanityRoot.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react'
import config from 'config:sanity'
import RootComponent from 'part:@sanity/base/root'
import SnackbarProvider from 'part:@sanity/components/snackbar/provider'
import {userColorManager, UserColorManagerProvider} from '../user-color'
import ErrorHandler from './ErrorHandler'
import VersionChecker from './VersionChecker'
import MissingProjectConfig from './MissingProjectConfig'
Expand All @@ -17,12 +18,14 @@ function SanityRoot() {

return (
<div className={styles.root}>
<SnackbarProvider>
<DevServerStatus />
<ErrorHandler />
<RootComponent />
<VersionChecker />
</SnackbarProvider>
<UserColorManagerProvider manager={userColorManager}>
<SnackbarProvider>
<DevServerStatus />
<ErrorHandler />
<RootComponent />
<VersionChecker />
</SnackbarProvider>
</UserColorManagerProvider>
</div>
)
}
Expand Down
2 changes: 2 additions & 0 deletions packages/@sanity/base/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import DefaultRootComponent from './components/DefaultRootComponent'

export {DefaultRootComponent}

export * from './user-color'
4 changes: 4 additions & 0 deletions packages/@sanity/base/src/user-color/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './manager'
export * from './provider'
export * from './singleton'
export * from './types'
32 changes: 32 additions & 0 deletions packages/@sanity/base/src/user-color/manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {UserColorHue, UserColorManager} from './types'

const colors: UserColorHue[] = [
'blue',
'cyan',
// 'green',
'yellow',
'orange',
// 'red',
'magenta',
'purple'
]

export function createUserColorManager(): UserColorManager {
let state: {users: string[]} = {
users: []
}

return {get}

function get(userId: string) {
if (!state.users.includes(userId)) {
state = {
users: state.users.concat([userId])
}
}

const idx = state.users.indexOf(userId)

return colors[idx % colors.length]
}
}
25 changes: 25 additions & 0 deletions packages/@sanity/base/src/user-color/provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, {createContext, useContext} from 'react'
import {UserColorManager} from './types'

interface ProviderProps {
children: React.ReactNode
manager: UserColorManager
}

const UserColorManagerContext = createContext<UserColorManager | null>(null)

export function useUserColorManager(): UserColorManager {
const manager = useContext(UserColorManagerContext)

if (!manager) {
throw new Error(`missing user color manager in context`)
}

return manager
}

export function UserColorManagerProvider({children, manager}: ProviderProps) {
return (
<UserColorManagerContext.Provider value={manager}>{children}</UserColorManagerContext.Provider>
)
}
3 changes: 3 additions & 0 deletions packages/@sanity/base/src/user-color/singleton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import {createUserColorManager} from './manager'

export const userColorManager = createUserColorManager()
13 changes: 13 additions & 0 deletions packages/@sanity/base/src/user-color/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export type UserColorHue =
| 'blue'
| 'cyan'
// | 'green'
| 'yellow'
| 'orange'
// | 'red'
| 'magenta'
| 'purple'

export interface UserColorManager {
get: (userId: string) => UserColorHue
}
1 change: 1 addition & 0 deletions packages/@sanity/desk-tool/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"leven": "^2.1.0",
"lodash": "^4.17.15",
"mendoza": "^0.1.0",
"polished": "^3.6.5",
"promise-latest": "^1.0.4",
"react-click-outside": "^3.0.0",
"react-json-inspector": "^7.1.1",
Expand Down
16 changes: 16 additions & 0 deletions packages/@sanity/desk-tool/src/@types/parts.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
declare module 'part:*'
declare module 'all:part:*'

declare module '@sanity/base' {
export type UserColorHue =
| 'blue'
| 'cyan'
// | 'green'
| 'yellow'
| 'orange'
// | 'red'
| 'magenta'
| 'purple'
export interface UserColorManager {
get: (userId: string) => UserColorHue
}
export const useUserColorManager: () => UserColorManager
}

declare module 'part:@sanity/base/router' {
export * from '@sanity/state-router'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
.root {
background: rgba(0, 0, 0, 0.05);
padding: 0.75em;
border-radius: 4px;
display: flex;

@nest & > span {
display: inline-block;
padding: 0.75em 0.125em;
}

@nest & del {
display: inline-block;
padding: 0.75em;
border-radius: 4px;
}

@nest & ins {
display: inline-block;
padding: 0.75em;
border-radius: 4px;
text-decoration: none;
}
}
28 changes: 16 additions & 12 deletions packages/@sanity/desk-tool/src/components/diffs/NumberFieldDiff.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
import * as React from 'react'
import {NumberDiff, StringDiffSegment} from '@sanity/diff'
import {useUserColorManager} from '@sanity/base'
import {NumberDiff} from '@sanity/diff'
import React from 'react'
import {Annotation} from '../../panes/documentPane/history/types'
import {getAnnotationColor} from './helpers'
import {DiffComponent} from './types'
import {StringSegment} from './StringFieldDiff'

import styles from './NumberFieldDiff.css'

export const NumberFieldDiff: DiffComponent<NumberDiff<Annotation>> = ({diff}) => {
const userColorManager = useUserColorManager()
const {fromValue, toValue, annotation} = diff
const segments: StringDiffSegment[] = []
const color = getAnnotationColor(userColorManager, annotation)

if (typeof fromValue === 'number') {
segments.push({type: 'removed', text: fromValue.toString(), annotation})
}
if (typeof toValue === 'number') {
segments.push({type: 'added', text: fromValue.toString(), annotation})
const inlineStyle = {
background: color.bg,
color: color.fg
}

return (
<div className={styles.root}>
{segments.map((segment, index) => (
<StringSegment key={index} segment={segment} />
))}
{fromValue !== undefined && (
<>
<del style={inlineStyle}>{fromValue}</del>
<span>&rarr;</span>
</>
)}
<ins style={inlineStyle}>{toValue}</ins>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@import 'part:@sanity/base/theme/variables-style';

.root {
background: rgba(0, 0, 0, 0.05);
background: #f1f3f6;
padding: 0.75em;
border-radius: 4px;
}
Expand All @@ -12,14 +12,12 @@

.add {
composes: segment;
background-color: var(--state-success-color--faded);
color: var(--state-success-color--inverted);
text-decoration: none;
mix-blend-mode: multiply;
}

.remove {
composes: segment;
text-decoration: line-through;
background-color: var(--state-danger-color--faded);
color: var(--state-danger-color--inverted);
mix-blend-mode: multiply;
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
/* eslint-disable react/no-multi-comp, react/prop-types */

import * as React from 'react'
import {useUserColorManager} from '@sanity/base'
import {StringDiffSegment, StringDiff} from '@sanity/diff'
import React from 'react'
import {Annotation} from '../../panes/documentPane/history/types'
import {getAnnotationColor} from './helpers'
import {DiffComponent} from './types'

import styles from './StringFieldDiff.css'
Expand All @@ -12,12 +14,26 @@ export function StringSegment({
}: {
segment: StringDiffSegment<Annotation>
}): React.ReactElement {
const userColorManager = useUserColorManager()

if (segment.type === 'added') {
return <ins className={styles.add}>{segment.text}</ins>
const color = getAnnotationColor(userColorManager, segment.annotation)

return (
<ins className={styles.add} style={{background: color.bg, color: color.fg}}>
{segment.text}
</ins>
)
}

if (segment.type === 'removed') {
return <del className={styles.remove}>{segment.text}</del>
const color = getAnnotationColor(userColorManager, segment.annotation)

return (
<del className={styles.remove} style={{background: color.bg, color: color.fg}}>
{segment.text}
</del>
)
}

return <>{segment.text}</>
Expand Down
66 changes: 66 additions & 0 deletions packages/@sanity/desk-tool/src/components/diffs/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {UserColorManager} from '@sanity/base'
import {parseToRgb} from 'polished'
import {Annotation} from '../../panes/documentPane/history/types'

interface RGB {
red: number
green: number
blue: number
}

interface UserColors {
blue: {bg: string; fg: string}
cyan: {bg: string; fg: string}
// green: {bg: string; fg: string}
yellow: {bg: string; fg: string}
orange: {bg: string; fg: string}
// red: {bg: string; fg: string}
magenta: {bg: string; fg: string}
purple: {bg: string; fg: string}
}

// @todo: get these values from a global theme object
const color: UserColors = {
blue: {bg: '#E8F1FE', fg: '#1B50A5'},
cyan: {bg: '#E2F4FD', fg: '#15628C'},
yellow: {bg: '#FEF7DA', fg: '#756623'},
orange: {bg: '#FEF0E6', fg: '#914E23'},
magenta: {bg: '#FCEBF5', fg: '#902A6C'},
purple: {bg: '#F8E9FE', fg: '#7B1EA5'}
}

function multiply(rgb1: RGB, rgb2: RGB) {
return {
red: Math.floor((rgb1.red * rgb2.red) / 255),
green: Math.floor((rgb1.green * rgb2.green) / 255),
blue: Math.floor((rgb1.blue * rgb2.blue) / 255)
}
}

export function getAnnotationColor(colorManager: UserColorManager, annotation: Annotation) {
if (!annotation) {
throw new Error('missing annotation')
}

const colors = Array.from(annotation.authors).map((userId: any) => {
const hueKey = colorManager.get(userId)
const hue = color[hueKey]

return {
bg: parseToRgb(hue.bg),
fg: parseToRgb(hue.fg)
}
})

const result = colors.reduce((acc, x) => {
return {
bg: multiply(acc.bg, x.bg),
fg: multiply(acc.fg, x.fg)
}
})

return {
bg: `rgb(${result.bg.red}, ${result.bg.green}, ${result.bg.blue})`,
fg: `rgb(${result.fg.red}, ${result.fg.green}, ${result.fg.blue})`
}
}

0 comments on commit 144b1e4

Please sign in to comment.