mirror of
https://github.com/Redocly/redoc.git
synced 2024-11-25 18:13:44 +03:00
feat: more advanced theme engine
This commit is contained in:
parent
ea3c731464
commit
1df690a964
|
@ -99,6 +99,7 @@
|
||||||
"mobx-react": "^4.3.3",
|
"mobx-react": "^4.3.3",
|
||||||
"openapi-sampler": "1.0.0-beta.9",
|
"openapi-sampler": "1.0.0-beta.9",
|
||||||
"perfect-scrollbar": "^1.3.0",
|
"perfect-scrollbar": "^1.3.0",
|
||||||
|
"polished": "^1.9.2",
|
||||||
"prismjs": "^1.8.1",
|
"prismjs": "^1.8.1",
|
||||||
"prop-types": "^15.6.0",
|
"prop-types": "^15.6.0",
|
||||||
"react-dropdown": "^1.3.0",
|
"react-dropdown": "^1.3.0",
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import styled from '../styled-components';
|
import styled from '../styled-components';
|
||||||
import { transparentizeHex } from '../utils/styled';
|
import { transparentize } from 'polished';
|
||||||
import { deprecatedCss } from './mixins';
|
import { deprecatedCss } from './mixins';
|
||||||
|
|
||||||
export const PropertiesTableCaption = styled.caption`
|
export const PropertiesTableCaption = styled.caption`
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: ${props => transparentizeHex(props.theme.colors.text, 0.4)};
|
color: ${props => transparentize(0.4, props.theme.colors.text)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const PropertyCell = styled.td`
|
export const PropertyCell = styled.td`
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { transparentizeHex } from '../utils/styled';
|
|
||||||
import { PropertyNameCell } from './fields-layout';
|
import { PropertyNameCell } from './fields-layout';
|
||||||
|
import { transparentize } from 'polished';
|
||||||
|
|
||||||
export const ClickablePropertyNameCell = PropertyNameCell.extend`
|
export const ClickablePropertyNameCell = PropertyNameCell.extend`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -13,14 +13,14 @@ export const FieldLabel = styled.span`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const TypePrefix = styled(FieldLabel)`
|
export const TypePrefix = styled(FieldLabel)`
|
||||||
color: ${props => transparentizeHex(props.theme.colors.text, 0.4)};
|
color: ${props => transparentize(0.4, props.theme.colors.text)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const TypeName = styled(FieldLabel)`
|
export const TypeName = styled(FieldLabel)`
|
||||||
color: ${props => transparentizeHex(props.theme.colors.text, 0.8)};
|
color: ${props => transparentize(0.8, props.theme.colors.text)};
|
||||||
`;
|
`;
|
||||||
export const TypeTitle = styled(FieldLabel)`
|
export const TypeTitle = styled(FieldLabel)`
|
||||||
color: ${props => transparentizeHex(props.theme.colors.text, 0.5)};
|
color: ${props => transparentize(0.5, props.theme.colors.text)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const TypeFormat = TypeName;
|
export const TypeFormat = TypeName;
|
||||||
|
@ -55,13 +55,13 @@ export const PatternLabel = styled(FieldLabel)`
|
||||||
|
|
||||||
export const ExampleValue = styled.span`
|
export const ExampleValue = styled.span`
|
||||||
font-family: ${props => props.theme.code.fontFamily};
|
font-family: ${props => props.theme.code.fontFamily};
|
||||||
background-color: ${props => transparentizeHex(props.theme.colors.text, 0.02)};
|
background-color: ${props => transparentize(0.02, props.theme.colors.text)};
|
||||||
border: 1px solid ${props => transparentizeHex(props.theme.colors.text, 0.15)};
|
border: 1px solid ${props => transparentize(0.15, props.theme.colors.text)};
|
||||||
margin: 0 3px;
|
margin: 0 3px;
|
||||||
padding: 0.4em 0.2em 0.2em;
|
padding: 0.4em 0.2em 0.2em;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
color: ${props => transparentizeHex(props.theme.colors.text, 0.9)};
|
color: ${props => transparentize(0.9, props.theme.colors.text)};
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
min-width: 20px;
|
min-width: 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -70,8 +70,8 @@ export const ExampleValue = styled.span`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ConstraintItem = styled(FieldLabel)`
|
export const ConstraintItem = styled(FieldLabel)`
|
||||||
background-color: ${props => transparentizeHex(props.theme.colors.main, 0.15)};
|
background-color: ${props => transparentize(0.15, props.theme.colors.main)};
|
||||||
color: ${props => transparentizeHex(props.theme.colors.main, 0.6)};
|
color: ${props => transparentize(0.6, props.theme.colors.main)};
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
|
|
@ -4,14 +4,3 @@ export const deprecatedCss = css`
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
color: #bdccd3;
|
color: #bdccd3;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const hoverColor = color => {
|
|
||||||
if (!color) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return css`
|
|
||||||
&:hover {
|
|
||||||
color: ${color};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import styled, { media } from '../styled-components';
|
import styled, { media } from '../styled-components';
|
||||||
|
|
||||||
export const MiddlePanel = styled.div`
|
export const MiddlePanel = styled.div`
|
||||||
width: ${props => 100 - props.theme.rightPanel.width}%;
|
width: calc(100% - ${props => props.theme.rightPanel.width});
|
||||||
padding: ${props => props.theme.spacingUnit * 2}px;
|
padding: ${props => props.theme.spacingUnit * 2}px;
|
||||||
|
|
||||||
${media.lessThan('medium')`
|
${media.lessThan('medium')`
|
||||||
|
@ -10,9 +10,9 @@ export const MiddlePanel = styled.div`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const RightPanel = styled.div`
|
export const RightPanel = styled.div`
|
||||||
width: ${props => props.theme.rightPanel.width}%;
|
width: ${props => props.theme.rightPanel.width};
|
||||||
color: #fafbfc;
|
color: #fafbfc;
|
||||||
bckground-color: ${props => props.theme.rightPanel.backgroundColor};
|
background-color: ${props => props.theme.rightPanel.backgroundColor};
|
||||||
padding: ${props => props.theme.spacingUnit * 2}px;
|
padding: ${props => props.theme.spacingUnit * 2}px;
|
||||||
|
|
||||||
${media.lessThan('medium')`
|
${media.lessThan('medium')`
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { hoverColor } from '../../common-elements/mixins';
|
|
||||||
import styled, { media } from '../../styled-components';
|
import styled, { media } from '../../styled-components';
|
||||||
export { ClassAttributes } from 'react';
|
export { ClassAttributes } from 'react';
|
||||||
|
|
||||||
|
@ -29,8 +28,15 @@ export const RedocWrap = styled.div`
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: ${props => props.theme.links.color || props.theme.colors.main};
|
color: ${props => props.theme.links.color};
|
||||||
${props => hoverColor(props.theme.links.hover)};
|
|
||||||
|
&:visited {
|
||||||
|
color: ${props => props.theme.links.visited};
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: ${props => props.theme.links.hover};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import styled from '../../styled-components';
|
import styled from '../../styled-components';
|
||||||
|
|
||||||
import { UnderlinedHeader } from '../../common-elements';
|
import { UnderlinedHeader } from '../../common-elements';
|
||||||
import { transparentizeHex } from '../../utils';
|
import { transparentize } from 'polished';
|
||||||
import { ResponseTitle } from './ResponseTitle';
|
import { ResponseTitle } from './ResponseTitle';
|
||||||
|
|
||||||
export const StyledResponseTitle = styled(ResponseTitle)`
|
export const StyledResponseTitle = styled(ResponseTitle)`
|
||||||
|
@ -13,7 +13,7 @@ export const StyledResponseTitle = styled(ResponseTitle)`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
color: ${props => props.theme.colors[props.type]};
|
color: ${props => props.theme.colors[props.type]};
|
||||||
background-color: ${props => transparentizeHex(props.theme.colors[props.type], 0.08)};
|
background-color: ${props => transparentize(0.08, props.theme.colors[props.type])};
|
||||||
|
|
||||||
${props =>
|
${props =>
|
||||||
(props.empty &&
|
(props.empty &&
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import styled from '../../styled-components';
|
import styled from '../../styled-components';
|
||||||
import { transparentizeHex } from '../../utils/styled';
|
import { transparentize } from 'polished';
|
||||||
|
|
||||||
import { UnderlinedHeader } from '../../common-elements/headers';
|
import { UnderlinedHeader } from '../../common-elements/headers';
|
||||||
import { SecurityRequirementModel } from '../../services/models/SecurityRequirement';
|
import { SecurityRequirementModel } from '../../services/models/SecurityRequirement';
|
||||||
|
@ -8,7 +8,7 @@ import { SecurityRequirementModel } from '../../services/models/SecurityRequirem
|
||||||
const ScopeName = styled.code`
|
const ScopeName = styled.code`
|
||||||
font-size: ${props => props.theme.code.fontSize};
|
font-size: ${props => props.theme.code.fontSize};
|
||||||
font-family: ${props => props.theme.code.fontFamily};
|
font-family: ${props => props.theme.code.fontFamily};
|
||||||
border: 1px solid ${props => transparentizeHex(props.theme.colors.text, 0.15)};
|
border: 1px solid ${props => transparentize(0.15, props.theme.colors.text)};
|
||||||
margin: 0 3px;
|
margin: 0 3px;
|
||||||
padding: 0.2em;
|
padding: 0.2em;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import defaultTheme, { ThemeInterface } from '../theme';
|
import defaultTheme, { ResolvedThemeInterface, ThemeInterface, resolveTheme } from '../theme';
|
||||||
import { querySelector } from '../utils/dom';
|
import { querySelector } from '../utils/dom';
|
||||||
import { isNumeric, mergeObjects } from '../utils/helpers';
|
import { isNumeric, mergeObjects } from '../utils/helpers';
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ export class RedocNormalizedOptions {
|
||||||
return () => 0;
|
return () => 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
theme: ThemeInterface;
|
theme: ResolvedThemeInterface;
|
||||||
scrollYOffset: () => number;
|
scrollYOffset: () => number;
|
||||||
hideHostname: boolean;
|
hideHostname: boolean;
|
||||||
expandResponses: { [code: string]: boolean } | 'all';
|
expandResponses: { [code: string]: boolean } | 'all';
|
||||||
|
@ -93,7 +93,7 @@ export class RedocNormalizedOptions {
|
||||||
hideDownloadButton: boolean;
|
hideDownloadButton: boolean;
|
||||||
|
|
||||||
constructor(raw: RedocRawOptions) {
|
constructor(raw: RedocRawOptions) {
|
||||||
this.theme = mergeObjects({} as any, defaultTheme, raw.theme || {});
|
this.theme = resolveTheme(mergeObjects({} as any, defaultTheme, raw.theme || {}));
|
||||||
this.scrollYOffset = RedocNormalizedOptions.normalizeScrollYOffset(raw.scrollYOffset);
|
this.scrollYOffset = RedocNormalizedOptions.normalizeScrollYOffset(raw.scrollYOffset);
|
||||||
this.hideHostname = RedocNormalizedOptions.normalizeHideHostname(raw.hideHostname);
|
this.hideHostname = RedocNormalizedOptions.normalizeHideHostname(raw.hideHostname);
|
||||||
this.expandResponses = RedocNormalizedOptions.normalizeExpandResponses(raw.expandResponses);
|
this.expandResponses = RedocNormalizedOptions.normalizeExpandResponses(raw.expandResponses);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import * as styledComponents from 'styled-components';
|
import * as styledComponents from 'styled-components';
|
||||||
|
|
||||||
import { ThemeInterface } from './theme';
|
import { ResolvedThemeInterface } from './theme';
|
||||||
|
|
||||||
export type StyledFunction<T> = styledComponents.ThemedStyledFunction<T, ThemeInterface>;
|
export type StyledFunction<T> = styledComponents.ThemedStyledFunction<T, ResolvedThemeInterface>;
|
||||||
|
|
||||||
function withProps<T, U extends HTMLElement = HTMLElement>(
|
function withProps<T, U extends HTMLElement = HTMLElement>(
|
||||||
styledFunction: StyledFunction<React.HTMLProps<U>>,
|
styledFunction: StyledFunction<React.HTMLProps<U>>,
|
||||||
|
@ -19,7 +19,7 @@ const {
|
||||||
withTheme,
|
withTheme,
|
||||||
} = (styledComponents as styledComponents.ThemedStyledComponentsModule<
|
} = (styledComponents as styledComponents.ThemedStyledComponentsModule<
|
||||||
any
|
any
|
||||||
>) as styledComponents.ThemedStyledComponentsModule<ThemeInterface>;
|
>) as styledComponents.ThemedStyledComponentsModule<ResolvedThemeInterface>;
|
||||||
|
|
||||||
export const media = {
|
export const media = {
|
||||||
lessThan(breakpoint) {
|
lessThan(breakpoint) {
|
||||||
|
@ -40,9 +40,9 @@ export const media = {
|
||||||
|
|
||||||
between(firstBreakpoint, secondBreakpoint) {
|
between(firstBreakpoint, secondBreakpoint) {
|
||||||
return (...args) => css`
|
return (...args) => css`
|
||||||
@media (min-width: ${props => props.theme.breakpoints[firstBreakpoint]}) and (max-width: ${props => props.theme.breakpoints[
|
@media (min-width: ${props =>
|
||||||
secondBreakpoint
|
props.theme.breakpoints[firstBreakpoint]}) and (max-width: ${props =>
|
||||||
]}) {
|
props.theme.breakpoints[secondBreakpoint]}) {
|
||||||
${(css as any)(...args)};
|
${(css as any)(...args)};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
121
src/theme.ts
121
src/theme.ts
|
@ -1,4 +1,6 @@
|
||||||
const theme = {
|
import { lighten } from 'polished';
|
||||||
|
|
||||||
|
const theme: ThemeInterface = {
|
||||||
spacingUnit: 20,
|
spacingUnit: 20,
|
||||||
breakpoints: {
|
breakpoints: {
|
||||||
small: '50rem',
|
small: '50rem',
|
||||||
|
@ -8,9 +10,9 @@ const theme = {
|
||||||
colors: {
|
colors: {
|
||||||
main: '#32329f',
|
main: '#32329f',
|
||||||
success: '#00aa13',
|
success: '#00aa13',
|
||||||
redirect: 'orange',
|
redirect: '#ffa500',
|
||||||
error: '#e53935',
|
error: '#e53935',
|
||||||
info: 'skyblue',
|
info: '#87ceeb',
|
||||||
text: '#263238',
|
text: '#263238',
|
||||||
warning: '#f1c400',
|
warning: '#f1c400',
|
||||||
http: {
|
http: {
|
||||||
|
@ -44,9 +46,9 @@ const theme = {
|
||||||
fontFamily: 'Courier, monospace',
|
fontFamily: 'Courier, monospace',
|
||||||
},
|
},
|
||||||
links: {
|
links: {
|
||||||
color: undefined, // by default main color
|
color: ({ colors }) => colors.main,
|
||||||
visited: undefined, // by default main color
|
visited: ({ colors }) => colors.main,
|
||||||
hover: undefined, // by default main color
|
hover: ({ colors }) => lighten(0.2, colors.main),
|
||||||
},
|
},
|
||||||
menu: {
|
menu: {
|
||||||
width: '260px',
|
width: '260px',
|
||||||
|
@ -58,10 +60,113 @@ const theme = {
|
||||||
},
|
},
|
||||||
rightPanel: {
|
rightPanel: {
|
||||||
backgroundColor: '#263238',
|
backgroundColor: '#263238',
|
||||||
width: 40,
|
width: '40%',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default theme;
|
export default theme;
|
||||||
|
|
||||||
export type ThemeInterface = typeof theme;
|
export function resolveTheme(theme: ThemeInterface): ResolvedThemeInterface {
|
||||||
|
const resolvedValues = {};
|
||||||
|
let counter = 0;
|
||||||
|
const setProxy = (obj, path: string) => {
|
||||||
|
Object.keys(obj).forEach(k => {
|
||||||
|
const currentPath = (path ? path + '.' : '') + k;
|
||||||
|
const val = obj[k];
|
||||||
|
if (typeof val === 'function') {
|
||||||
|
Object.defineProperty(obj, k, {
|
||||||
|
get() {
|
||||||
|
if (!resolvedValues[currentPath]) {
|
||||||
|
counter++;
|
||||||
|
if (counter > 1000) {
|
||||||
|
throw new Error(
|
||||||
|
`Theme probably contains cirucal dependency at ${currentPath}: ${val.toString()}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvedValues[currentPath] = val(theme);
|
||||||
|
}
|
||||||
|
return resolvedValues[currentPath];
|
||||||
|
},
|
||||||
|
enumerable: true,
|
||||||
|
});
|
||||||
|
} else if (typeof val === 'object') {
|
||||||
|
setProxy(val, currentPath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
setProxy(theme, '');
|
||||||
|
return JSON.parse(JSON.stringify(theme));
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResolvedThemeInterface {
|
||||||
|
spacingUnit: number;
|
||||||
|
breakpoints: {
|
||||||
|
small: string;
|
||||||
|
medium: string;
|
||||||
|
large: string;
|
||||||
|
};
|
||||||
|
colors: {
|
||||||
|
main: string;
|
||||||
|
success: string;
|
||||||
|
redirect: string;
|
||||||
|
error: string;
|
||||||
|
info: string;
|
||||||
|
text: string;
|
||||||
|
warning: string;
|
||||||
|
http: {
|
||||||
|
get: string;
|
||||||
|
post: string;
|
||||||
|
put: string;
|
||||||
|
options: string;
|
||||||
|
patch: string;
|
||||||
|
delete: string;
|
||||||
|
basic: string;
|
||||||
|
link: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
schemaView: {
|
||||||
|
linesColor: string;
|
||||||
|
defaultDetailsWidth: string;
|
||||||
|
};
|
||||||
|
baseFont: {
|
||||||
|
size: string;
|
||||||
|
lineHeight: string;
|
||||||
|
weight: string;
|
||||||
|
family: string;
|
||||||
|
smoothing: string;
|
||||||
|
optimizeSpeed: boolean;
|
||||||
|
};
|
||||||
|
headingsFont: {
|
||||||
|
family: string;
|
||||||
|
};
|
||||||
|
code: {
|
||||||
|
fontSize: string;
|
||||||
|
fontFamily: string;
|
||||||
|
};
|
||||||
|
links: {
|
||||||
|
color: string;
|
||||||
|
visited: string;
|
||||||
|
hover: string;
|
||||||
|
};
|
||||||
|
menu: {
|
||||||
|
width: string;
|
||||||
|
backgroundColor: string;
|
||||||
|
};
|
||||||
|
logo: {
|
||||||
|
maxHeight: string;
|
||||||
|
width: string;
|
||||||
|
};
|
||||||
|
rightPanel: {
|
||||||
|
backgroundColor: string;
|
||||||
|
width: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type primitive = string | number | boolean | undefined | null;
|
||||||
|
export type AdvancedThemeDeep<T> = T extends primitive
|
||||||
|
? T | ((theme: ResolvedThemeInterface) => T)
|
||||||
|
: AdvancedThemeObject<T>;
|
||||||
|
export type AdvancedThemeObject<T> = { [P in keyof T]: AdvancedThemeDeep<T[P]> };
|
||||||
|
export type ThemeInterface = AdvancedThemeObject<ResolvedThemeInterface>;
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
import * as react from 'React';
|
|
||||||
import { transparentizeHex } from '../styled';
|
|
||||||
|
|
||||||
describe('transparentizeHex', () => {
|
|
||||||
test('simple transparentize', () => {
|
|
||||||
const res = transparentizeHex('#000000', 0.5);
|
|
||||||
expect(res).toBe('rgba(0, 0, 0, 0.5)');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('transparentize hex shorthand', () => {
|
|
||||||
const res = transparentizeHex('#123', 0.5);
|
|
||||||
expect(res).toBe('rgba(17, 34, 51, 0.5)');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('do not transparentize (withot last param)', () => {
|
|
||||||
const res = transparentizeHex('#010203');
|
|
||||||
expect(res).toBe('rgb(1, 2, 3)');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,5 +1,4 @@
|
||||||
export * from './JsonPointer';
|
export * from './JsonPointer';
|
||||||
export * from './styled';
|
|
||||||
|
|
||||||
export * from './openapi';
|
export * from './openapi';
|
||||||
export * from './helpers';
|
export * from './helpers';
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
export function hexToRgb(hex: string): { r: number; g: number; b: number } {
|
|
||||||
hex = hex.replace('#', '');
|
|
||||||
const r = parseInt(hex.length === 3 ? hex.slice(0, 1).repeat(2) : hex.slice(0, 2), 16);
|
|
||||||
const g = parseInt(hex.length === 3 ? hex.slice(1, 2).repeat(2) : hex.slice(2, 4), 16);
|
|
||||||
const b = parseInt(hex.length === 3 ? hex.slice(2, 3).repeat(2) : hex.slice(4, 6), 16);
|
|
||||||
return { r, g, b };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function transparentizeHex(hex: string, alpha?: number): string {
|
|
||||||
const { r, g, b } = hexToRgb(hex);
|
|
||||||
if (alpha !== undefined) {
|
|
||||||
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
||||||
} else {
|
|
||||||
return `rgb(${r}, ${g}, ${b})`;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5972,6 +5972,10 @@ pn@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"
|
resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"
|
||||||
|
|
||||||
|
polished@^1.9.2:
|
||||||
|
version "1.9.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/polished/-/polished-1.9.2.tgz#d705cac66f3a3ed1bd38aad863e2c1e269baf6b6"
|
||||||
|
|
||||||
portfinder@^1.0.9:
|
portfinder@^1.0.9:
|
||||||
version "1.0.13"
|
version "1.0.13"
|
||||||
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9"
|
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user