Skip to content

Commit 88bd480

Browse files
committed
feat: setup theme
1 parent ff40dee commit 88bd480

File tree

15 files changed

+166
-121
lines changed

15 files changed

+166
-121
lines changed

.storybook/theme.js

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,41 @@ export { useTheme, ThemeProvider };
66

77
export const themes = ['dark', 'light'];
88

9-
export const zones = {};
9+
export const zones = {
10+
'json-schema-viewer': ({ base }) => base === 'dark'
11+
? {
12+
canvas: {
13+
bg: '#111',
14+
fg: '#fff',
15+
error: 'red',
16+
muted: 'rgba(255, 255, 255, 0.4)'
17+
},
18+
19+
divider: {
20+
bg: '#bababa',
21+
},
22+
23+
row: {
24+
hoverBg: '#999',
25+
hoverFg: '#222',
26+
evenBg: '#333',
27+
}
28+
} : {
29+
canvas: {
30+
bg: '#fff',
31+
fg: '#111',
32+
error: 'red',
33+
muted: 'rgba(0, 0, 0, 0.4)'
34+
},
35+
36+
divider: {
37+
bg: '#dae1e7',
38+
},
39+
40+
row: {
41+
hoverBg: '#888',
42+
hoverFg: '#111',
43+
evenBg: '#e4e4e4',
44+
},
45+
},
46+
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"react-dom": ">=16.8.0"
4141
},
4242
"dependencies": {
43+
"@fortawesome/free-solid-svg-icons": "^5.6.3",
4344
"@stoplight/json": "1.3.x",
4445
"lodash": "4.17.x"
4546
},

src/JsonSchemaViewer.tsx

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
/* @jsx jsx */
22

33
import { jsx } from '@emotion/core';
4-
import { Box, IBox } from '@stoplight/ui-kit';
4+
import { Omit } from '@stoplight/types';
55
import { Component } from 'react';
66
import { ErrorMessage } from './common/ErrorMessage';
77
import { MutedText } from './common/MutedText';
88
import { ISchemaView, SchemaView } from './Schema';
9+
import { ThemeZone } from './theme';
910
import { isSchemaViewerEmpty } from './util/isSchemaViewerEmpty';
1011

11-
export interface IJsonSchemaViewer extends ISchemaView, IBox {}
12+
export interface IJsonSchemaViewer extends Omit<ISchemaView, 'emptyText'> {
13+
emptyText?: string;
14+
}
1215

1316
export interface IJsonSchemaViewerState {
1417
error: null | string;
@@ -21,12 +24,13 @@ export class JsonSchemaViewer extends Component<IJsonSchemaViewer, IJsonSchemaVi
2124

2225
// there is no error hook yet, see https://reactjs.org/docs/hooks-faq.html#how-do-lifecycle-methods-correspond-to-hooks
2326
public static getDerivedStateFromError(error: Error): { error: IJsonSchemaViewerState['error'] } {
24-
return { error: error.message };
27+
return { error: `Error rendering schema. ${error.message}` };
2528
}
2629

2730
public render() {
2831
const {
2932
props: {
33+
emptyText = 'No schema defined',
3034
name,
3135
schema,
3236
dereferencedSchema,
@@ -42,38 +46,38 @@ export class JsonSchemaViewer extends Component<IJsonSchemaViewer, IJsonSchemaVi
4246
} = this;
4347

4448
if (error) {
45-
// todo: handle these:
46-
/*
47-
<Box as="p" p={3} className="u-error">
48-
There is an error in your {name} schema definition.
49-
</Box>
50-
*/
51-
52-
/*<Row className="u-error">{`Error rendering schema. ${e}`}</Row>]*/
53-
return <ErrorMessage>{error}</ErrorMessage>;
49+
return (
50+
<ThemeZone name="json-schema-viewer">
51+
<ErrorMessage>{error}</ErrorMessage>
52+
</ThemeZone>
53+
);
5454
}
5555

5656
// an empty array or object is still a valid response, schema is ONLY really empty when a combiner type has no information
5757
if (isSchemaViewerEmpty(schema)) {
58-
return <MutedText>No schema defined</MutedText>;
58+
return (
59+
<ThemeZone name="json-schema-viewer">
60+
<MutedText>{emptyText}</MutedText>
61+
</ThemeZone>
62+
);
5963
}
6064

6165
return (
62-
<Box {...props}>
63-
{(
64-
<SchemaView
65-
defaultExpandedDepth={defaultExpandedDepth}
66-
dereferencedSchema={dereferencedSchema}
67-
expanded={expanded}
68-
hideInheritedFrom={hideInheritedFrom}
69-
hideRoot={hideRoot}
70-
limitPropertyCount={limitPropertyCount}
71-
name={name}
72-
schema={schema}
73-
schemas={schemas}
74-
/>
75-
) || <MutedText>No schema defined</MutedText>}
76-
</Box>
66+
<ThemeZone name="json-schema-viewer">
67+
<SchemaView
68+
emptyText={emptyText}
69+
defaultExpandedDepth={defaultExpandedDepth}
70+
dereferencedSchema={dereferencedSchema}
71+
expanded={expanded}
72+
hideInheritedFrom={hideInheritedFrom}
73+
hideRoot={hideRoot}
74+
limitPropertyCount={limitPropertyCount}
75+
name={name}
76+
schema={schema}
77+
schemas={schemas}
78+
{...props}
79+
/>
80+
</ThemeZone>
7781
);
7882
}
7983
}

src/Schema.tsx

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
/* @jsx jsx */
22

33
import { jsx } from '@emotion/core';
4+
import { Dictionary, ISchema } from '@stoplight/types';
5+
import { Box, Button, IBox } from '@stoplight/ui-kit';
46
import dropRight = require('lodash/dropRight');
57
import isEmpty = require('lodash/isEmpty');
6-
import { Fragment, FunctionComponent, MouseEventHandler, ReactNodeArray, useCallback, useState } from 'react';
7-
8-
import { Dictionary, ISchema } from '@stoplight/types';
9-
import { Button } from '@stoplight/ui-kit';
8+
import { FunctionComponent, MouseEventHandler, ReactNodeArray, useCallback, useState } from 'react';
9+
import { MutedText } from './common/MutedText';
1010
import { dereferenceSchema } from './dereferenceSchema';
1111
import { renderSchema } from './renderers/renderSchema';
12+
import { useTheme } from './theme';
1213
import { buildAllOfSchema } from './util/buildAllOfSchema';
1314

14-
export interface ISchemaView {
15+
export interface ISchemaViewProps {
1516
name?: string;
1617
dereferencedSchema?: ISchema;
1718
defaultExpandedDepth?: number;
@@ -21,20 +22,26 @@ export interface ISchemaView {
2122
hideRoot?: boolean;
2223
expanded?: boolean;
2324
hideInheritedFrom?: boolean;
25+
emptyText: string;
2426
}
2527

28+
export interface ISchemaView extends ISchemaViewProps, IBox {}
29+
2630
export const SchemaView: FunctionComponent<ISchemaView> = props => {
2731
const {
2832
defaultExpandedDepth = 1,
2933
dereferencedSchema,
34+
emptyText,
3035
expanded = false,
3136
hideInheritedFrom = false,
3237
hideRoot,
3338
limitPropertyCount = 0,
3439
schema,
3540
schemas = {},
41+
...rest
3642
} = props;
3743

44+
const theme = useTheme();
3845
const [showExtra, setShowExtra] = useState<boolean>(false);
3946
const [expandedRows, setExpandedRows] = useState<Dictionary<boolean>>({ all: expanded });
4047

@@ -56,15 +63,15 @@ export const SchemaView: FunctionComponent<ISchemaView> = props => {
5663
!Object.keys(actualSchema).length ||
5764
(actualSchema.properties && !Object.keys(actualSchema.properties).length)
5865
) {
59-
return null;
66+
return <MutedText>{emptyText}</MutedText>;
6067
}
6168

6269
if (actualSchema.allOf) {
63-
const props = actualSchema.allOf;
70+
const schemaProps = actualSchema.allOf;
6471

65-
if (actualSchema.type) props.push({ type: actualSchema.type });
72+
if (actualSchema.type) schemaProps.push({ type: actualSchema.type });
6673

67-
actualSchema = buildAllOfSchema(props);
74+
actualSchema = buildAllOfSchema(schemaProps);
6875
}
6976

7077
let rowElems: ReactNodeArray = [];
@@ -90,17 +97,17 @@ export const SchemaView: FunctionComponent<ISchemaView> = props => {
9097
}
9198

9299
if (rowElems.length === 0) {
93-
return null;
100+
return <MutedText>{emptyText}</MutedText>;
94101
}
95102

96103
return (
97-
<Fragment>
104+
<Box backgroundColor={theme.canvas.bg} color={theme.canvas.fg} {...rest}>
98105
{rowElems}
99106
{showExtra || propOverflowCount > 0 ? (
100107
<Button onClick={toggleShowExtra}>
101108
{showExtra ? 'collapse' : `...show ${propOverflowCount} more properties`}
102109
</Button>
103110
) : null}
104-
</Fragment>
111+
</Box>
105112
);
106113
};

src/__stories__/JsonSchemaViewer.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22

3-
import { boolean, number, object, text } from '@storybook/addon-knobs';
3+
import { boolean, number, object, text, withKnobs } from '@storybook/addon-knobs';
44
import { storiesOf } from '@storybook/react';
55

66
import { JsonSchemaViewer } from '../JsonSchemaViewer';
@@ -22,13 +22,16 @@ const schema = {
2222
},
2323
};
2424

25-
storiesOf('JsonSchemaViewer', module).add('with text', () => (
26-
<JsonSchemaViewer
27-
name={text('name', 'name')}
28-
schemas={object('schemas', {})}
29-
schema={object('schema', schema)}
30-
limitPropertyCount={number('limitPropertyCount', 20)}
31-
hideRoot={boolean('hideRoot', false)}
32-
expanded={boolean('expanded', true)}
33-
/>
34-
));
25+
storiesOf('JsonSchemaViewer', module)
26+
.addDecorator(withKnobs)
27+
.add('with text', () => (
28+
<JsonSchemaViewer
29+
css={{ fontFamily: 'monospace' }}
30+
name={text('name', 'name')}
31+
schemas={object('schemas', {})}
32+
schema={object('schema', schema)}
33+
limitPropertyCount={number('limitPropertyCount', 20)}
34+
hideRoot={boolean('hideRoot', false)}
35+
expanded={boolean('expanded', true)}
36+
/>
37+
));

src/common/ErrorMessage.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { jsx } from '@emotion/core';
44
import { Box, IBox } from '@stoplight/ui-kit';
55
import { FunctionComponent } from 'react';
6+
import { useTheme } from '../theme';
67

78
export const ErrorMessage: FunctionComponent<IErrorMessage> = props => {
89
const { children, ...rest } = props;
@@ -20,9 +21,8 @@ export interface IErrorMessageProps {}
2021
export interface IErrorMessage extends IErrorMessageProps, IBox {}
2122

2223
export const errorMessageStyles = () => {
23-
// const theme = useTheme();
24+
const theme = useTheme();
2425
return {
25-
// canvas.error
26-
color: 'red',
26+
color: theme.canvas.error,
2727
};
2828
};

src/common/MutedText.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { jsx } from '@emotion/core';
44
import { Box, IBox } from '@stoplight/ui-kit';
55
import { FunctionComponent } from 'react';
6+
import { useTheme } from '../theme';
67

78
export const MutedText: FunctionComponent<IMutedText> = props => {
89
const { children, ...rest } = props;
@@ -20,9 +21,8 @@ export interface IMutedTextProps {}
2021
export interface IMutedText extends IMutedTextProps, IBox {}
2122

2223
export const mutedTextStyles = () => {
23-
// const theme = useTheme();
24+
const theme = useTheme();
2425
return {
25-
// canvas.muted
26-
color: 'rgba(19, 15, 33, 0.6)',
26+
color: theme.canvas.muted,
2727
};
2828
};

src/common/Row.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import { css, jsx } from '@emotion/core';
44
import { Box, IBox } from '@stoplight/ui-kit';
55
import { FunctionComponent } from 'react';
6+
import { DEFAULT_PADDING, GUTTER_WIDTH } from '../consts';
7+
import { useTheme } from '../theme';
68

79
export const Row: FunctionComponent<IRow> = props => {
810
const { children, level, ...rest } = props;
@@ -21,22 +23,24 @@ export interface IRowProps {
2123

2224
export interface IRow extends IRowProps, IBox {}
2325

24-
const $gutterWidth = 15;
25-
2626
export const rowStyles = ({ level }: IRowProps) => {
27+
const theme = useTheme();
28+
2729
return [
2830
{
29-
...(level !== undefined && { paddingLeft: 20 + $gutterWidth * level }),
31+
...(level !== undefined && { paddingLeft: DEFAULT_PADDING + GUTTER_WIDTH * level }),
3032
},
3133
css`
3234
user-select none;
3335
34-
&:nth-child(even) {
35-
background-color grey;
36+
&:nth-of-type(even) {
37+
background-color ${theme.row.evenBg};
38+
color ${theme.row.evenFg || theme.canvas.fg};
3639
}
3740
3841
&:hover {
39-
background-color #f3f3f3;
42+
background-color ${theme.row.hoverBg};
43+
color ${theme.row.hoverFg || theme.canvas.fg};
4044
}
4145
4246
i {

src/common/RowType.tsx

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/consts.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const GUTTER_WIDTH = 15;
2+
export const DEFAULT_PADDING = 20;

0 commit comments

Comments
 (0)