dark-mode: adjusting sigils and tile colors

This commit is contained in:
Hunter Miller 2021-09-13 15:14:57 -05:00
parent 2a15658d2e
commit c96b1ec700
5 changed files with 12282 additions and 5626 deletions

17829
pkg/grid/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,8 @@ import classNames from 'classnames';
import React, { useMemo } from 'react';
import { sigil, reactRenderer } from '@tlon/sigil-js';
import { deSig, Contact } from '@urbit/api';
import { darken, lighten, parseToHsla } from 'color2k';
import { usePreferencesStore } from '../nav/preferences/usePreferencesStore';
export type AvatarSizes = 'xs' | 'small' | 'default';
@ -45,10 +47,27 @@ const emptyContact: Contact = {
'last-updated': 0
};
function themeAdjustColor(color: string, theme: 'light' | 'dark'): string {
const hsla = parseToHsla(color);
const lightness = hsla[2];
if (lightness <= 0.1 && theme === 'dark') {
return lighten(color, 0.1 - lightness);
}
if (lightness >= 0.9 && theme === 'light') {
return darken(color, lightness - 0.9);
}
return color;
}
export const Avatar = ({ size, className, ...ship }: AvatarProps) => {
const currentTheme = usePreferencesStore((s) => s.currentTheme);
const { shipName, color, avatar } = { ...emptyContact, ...ship };
const { classes, size: sigilSize } = sizeMap[size];
const foregroundColor = foregroundFromBackground(color);
const adjustedColor = themeAdjustColor(color, currentTheme);
const foregroundColor = foregroundFromBackground(adjustedColor);
const sigilElement = useMemo(() => {
if (shipName.match(/[_^]/)) {
return null;
@ -59,9 +78,9 @@ export const Avatar = ({ size, className, ...ship }: AvatarProps) => {
renderer: reactRenderer,
size: sigilSize,
icon: true,
colors: [color, foregroundColor]
colors: [adjustedColor, foregroundColor]
});
}, [shipName, color, foregroundColor]);
}, [shipName, adjustedColor, foregroundColor]);
if (avatar) {
return <img className={classNames('', classes)} src={avatar} alt="" />;
@ -77,7 +96,7 @@ export const Avatar = ({ size, className, ...ship }: AvatarProps) => {
size === 'default' && 'p-3',
className
)}
style={{ backgroundColor: color }}
style={{ backgroundColor: adjustedColor }}
>
{sigilElement}
</div>

View File

@ -192,7 +192,8 @@ export const mockContacts: Contacts = {
},
'~nalbel_litzod': {
...contact,
nickname: 'Queen'
nickname: 'Queen',
color: '#0a1b0a'
},
'~litmus^ritten': {
...contact
@ -206,7 +207,8 @@ export const mockContacts: Contacts = {
},
'~nalrys': {
...contact,
status: 'hosting coming soon'
status: 'hosting coming soon',
color: '#130c06'
}
};

View File

@ -1,6 +1,5 @@
import classNames from 'classnames';
import React, { FunctionComponent } from 'react';
import { darken, hsla, lighten, parseToHsla, readableColorIsBlack } from 'color2k';
import { chadIsRunning } from '@urbit/api/docket';
import { TileMenu } from './TileMenu';
import { Spinner } from '../components/Spinner';
@ -14,28 +13,13 @@ type TileProps = {
desk: string;
};
function getMenuColor(color: string, lightText: boolean, active: boolean): string {
const hslaColor = parseToHsla(color);
const satAdjustedColor = hsla(
hslaColor[0],
active ? Math.max(0.2, hslaColor[1]) : 0,
hslaColor[2],
1
);
return lightText ? lighten(satAdjustedColor, 0.1) : darken(satAdjustedColor, 0.1);
}
export const Tile: FunctionComponent<TileProps> = ({ charge, desk }) => {
const addRecentApp = useRecentsStore((state) => state.addRecentApp);
const { title, image, color, chad, href } = charge;
const { theme, tileColor } = useTileColor(color);
const { lightText, tileColor, menuColor, suspendColor, suspendMenuColor } = useTileColor(color);
const loading = 'install' in chad;
const active = chadIsRunning(chad);
const lightText = !readableColorIsBlack(color);
const menuColor = getMenuColor(tileColor, theme === 'dark' ? !lightText : lightText, active);
const suspendColor = 'rgb(220,220,220)';
const suspended = 'suspend' in chad;
const active = chadIsRunning(chad);
const link = getAppHref(href);
const backgroundColor = active ? tileColor || 'purple' : suspendColor;
@ -61,7 +45,7 @@ export const Tile: FunctionComponent<TileProps> = ({ charge, desk }) => {
<TileMenu
desk={desk}
active={active}
menuColor={menuColor}
menuColor={active ? menuColor : suspendMenuColor}
lightText={lightText}
className="absolute z-10 top-2.5 right-2.5 sm:top-4 sm:right-4 opacity-0 hover-none:opacity-100 focus:opacity-100 group-hover:opacity-100"
/>

View File

@ -1,4 +1,4 @@
import { hsla, parseToHsla } from 'color2k';
import { darken, hsla, lighten, parseToHsla, readableColorIsBlack } from 'color2k';
import { usePreferencesStore } from '../nav/preferences/usePreferencesStore';
function getDarkColor(color: string): string {
@ -6,11 +6,31 @@ function getDarkColor(color: string): string {
return hsla(hslaColor[0], hslaColor[1], 1 - hslaColor[2], 1);
}
function bgAdjustedColor(color: string, darkBg: boolean): string {
return darkBg ? lighten(color, 0.1) : darken(color, 0.1);
}
function getMenuColor(color: string, darkBg: boolean): string {
const hslaColor = parseToHsla(color);
const satAdjustedColor = hsla(hslaColor[0], Math.max(0.2, hslaColor[1]), hslaColor[2], 1);
return bgAdjustedColor(satAdjustedColor, darkBg);
}
export const useTileColor = (color: string) => {
const theme = usePreferencesStore((s) => s.currentTheme);
const darkTheme = theme === 'dark';
const tileColor = darkTheme ? getDarkColor(color) : color;
const darkBg = !readableColorIsBlack(tileColor);
const lightText = darkBg !== darkTheme; // if not same, light text
const suspendColor = darkTheme ? 'rgb(26,26,26)' : 'rgb(220,220,220)';
return {
theme,
tileColor: theme === 'dark' ? getDarkColor(color) : color
tileColor: theme === 'dark' ? getDarkColor(color) : color,
menuColor: getMenuColor(tileColor, darkBg),
suspendColor,
suspendMenuColor: bgAdjustedColor(suspendColor, darkBg),
lightText
};
};