Browse Source

Add storybook, update user tabs

feature/settings-cleanup
GreatBearShark 2 years ago
parent
commit
e989690fcc
  1. 14
      .storybook/main.js
  2. 9
      package.json
  3. 18
      src/components/ThemeSystemProvider.tsx
  4. 14
      src/components/data-type-select.tsx
  5. 16
      src/components/listing-type-select.tsx
  6. 3
      src/components/main.tsx
  7. 40
      src/components/user.tsx
  8. 13
      src/custom.css
  9. 36
      src/stories/Button.stories.tsx
  10. 93
      src/stories/Theming.stories.tsx
  11. 56
      src/theme.tsx
  12. 6734
      yarn.lock

14
.storybook/main.js

@ -0,0 +1,14 @@
module.exports = {
stories: ['../src/**/*.stories.tsx'],
webpackFinal: async config => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('babel-loader'),
options: {
presets: [['react-app', { flow: false, typescript: true }]],
},
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
},
};

9
package.json

@ -8,7 +8,8 @@
"api-test": "jest src/api_tests/api.spec.ts",
"build": "node generate_translations.js && NODE_ENV=production vite build --base=/static/",
"lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src",
"start": "node generate_translations.js && vite --port 4444 --open"
"start": "node generate_translations.js && vite --port 4444 --open",
"storybook": "start-storybook"
},
"keywords": [],
"dependencies": {
@ -68,14 +69,20 @@
"ws": "^7.3.1"
},
"devDependencies": {
"@babel/core": "^7.11.1",
"@storybook/addon-info": "^5.3.19",
"@storybook/react": "^5.3.19",
"@types/jest": "^26.0.8",
"@types/node-fetch": "^2.5.7",
"babel-loader": "^8.1.0",
"babel-preset-react-app": "^9.1.2",
"cssnano": "^4.1.10",
"eslint": "^7.6.0",
"eslint-plugin-inferno": "^7.20.1",
"eslint-plugin-jane": "^8.0.5",
"lint-staged": "^10.2.11",
"node-fetch": "^2.6.0",
"react-docgen-typescript-loader": "^3.7.2",
"sortpack": "^2.1.6",
"source-map-loader": "^1.0.1",
"ts-jest": "^26.1.4",

18
src/components/ThemeSystemProvider.tsx

@ -5,19 +5,20 @@ import { themes, variants } from '../theme';
const ThemeSystem = createContext({});
function ThemeSystemProvider({ children }) {
const [currentTheme, setCurrentTheme] = useState('chapo');
function ThemeSystemProvider({ children, initialTheme = 'chapo' }) {
console.log({ initialTheme });
const [currentTheme, setCurrentTheme] = useState(initialTheme);
const theme = Object.keys(themes).includes(currentTheme)
? themes[currentTheme]
: themes.chapo;
useEffect(() => {
const theme = UserService?.Instance?.user?.theme;
// const theme = UserService?.Instance?.user?.theme;
if (theme) {
setCurrentTheme(theme);
}
// if (theme) {
// setCurrentTheme(theme);
// }
}, []);
useEffect(() => {
@ -42,7 +43,10 @@ function ThemeSystemProvider({ children }) {
setCurrentTheme,
}}
>
<ThemeProvider theme={{ ...theme, ...variants }}>
<ThemeProvider theme={{
...variants,
...theme,
}}>
{children}
</ThemeProvider>
</ThemeSystem.Provider>

14
src/components/data-type-select.tsx

@ -38,12 +38,7 @@ export class DataTypeSelect extends Component<
<div className="btn-group btn-group-toggle">
<Button
as="label"
css={{
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
// backgroundColor: this.state.type_ == DataType.Post ? 'inherit' : '#2b2a2a'
}}
variant={this.state.type_ == DataType.Post ? 'highlight' : 'primary'}
variant={this.state.type_ == DataType.Post ? 'primary' : 'muted'}
>
<input
type="radio"
@ -56,13 +51,8 @@ export class DataTypeSelect extends Component<
</Button>
<Button
as="label"
css={{
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
// backgroundColor: this.state.type_ == DataType.Comment ? 'inherit' : '#2b2a2a'
}}
variant={
this.state.type_ == DataType.Comment ? 'highlight' : 'primary'
this.state.type_ == DataType.Comment ? 'primary' : 'muted'
}
>
<input

16
src/components/listing-type-select.tsx

@ -39,16 +39,9 @@ export class ListingTypeSelect extends Component<
<div className="btn-group btn-group-toggle">
<Button
as="label"
className={`
${this.state.type_ == ListingType.Subscribed && 'active'}
`}
disabled={UserService.Instance.user == undefined}
css={{
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
}}
variant={
this.state.type_ == ListingType.Subscribed ? 'highlight' : 'primary'
this.state.type_ == ListingType.Subscribed ? 'primary' : 'muted'
}
>
<input
@ -63,13 +56,8 @@ export class ListingTypeSelect extends Component<
</Button>
<Button
as="label"
css={{
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
// backgroundColor: this.state.type_ == ListingType.All ? 'inherit' : '#2b2a2a'
}}
variant={
this.state.type_ == ListingType.All ? 'highlight' : 'primary'
this.state.type_ == ListingType.All ? 'primary' : 'muted'
}
>
<input

3
src/components/main.tsx

@ -327,6 +327,7 @@ class Main extends Component<any, MainState> {
src={`${BASE_PATH}welcome.gif`}
className="img-fluid"
style={{ width: '100%' }}
alt="welcome sign"
/>
{this.canAdmin && (
<ul className="list-inline mb-1 text-muted font-weight-bold">
@ -591,6 +592,7 @@ class Main extends Component<any, MainState> {
{this.state.page > 1 && (
<Button
mr={1}
variant="muted"
onClick={linkEvent(this, this.prevPage)}
>
{i18n.t('prev')}
@ -598,6 +600,7 @@ class Main extends Component<any, MainState> {
)}
{this.state.posts.length > 0 && (
<Button
variant="muted"
onClick={linkEvent(this, this.nextPage)}
>
{i18n.t('next')}

40
src/components/user.tsx

@ -296,58 +296,58 @@ class BaseUser extends Component<any, UserState> {
viewRadios() {
return (
<div className="btn-group btn-group-toggle">
<label
className={`btn btn-sm btn-secondary pointer btn-outline-light
${this.state.view == UserDetailsView.Overview && 'active'}
`}
<Button
as="label"
variant={this.state.view == UserDetailsView.Overview ? 'primary' : 'muted'}
>
<input
type="radio"
className="visually-hidden"
value={UserDetailsView.Overview}
checked={this.state.view === UserDetailsView.Overview}
onChange={linkEvent(this, this.handleViewChange)}
/>
{i18n.t('overview')}
</label>
<label
className={`btn btn-sm btn-secondary pointer btn-outline-light
${this.state.view == UserDetailsView.Comments && 'active'}
`}
</Button>
<Button
as="label"
variant={this.state.view == UserDetailsView.Comments ? 'primary' : 'muted'}
>
<input
type="radio"
className="visually-hidden"
value={UserDetailsView.Comments}
checked={this.state.view == UserDetailsView.Comments}
onChange={linkEvent(this, this.handleViewChange)}
/>
{i18n.t('comments')}
</label>
<label
className={`btn btn-sm btn-secondary pointer btn-outline-light
${this.state.view == UserDetailsView.Posts && 'active'}
`}
</Button>
<Button
as="label"
variant={this.state.view == UserDetailsView.Posts ? 'primary' : 'muted'}
>
<input
type="radio"
className="visually-hidden"
value={UserDetailsView.Posts}
checked={this.state.view == UserDetailsView.Posts}
onChange={linkEvent(this, this.handleViewChange)}
/>
{i18n.t('posts')}
</label>
<label
className={`btn btn-sm btn-secondary pointer btn-outline-light
${this.state.view == UserDetailsView.Saved && 'active'}
`}
</Button>
<Button
as="label"
variant={this.state.view == UserDetailsView.Saved ? 'primary' : 'muted'}
>
<input
className="visually-hidden"
type="radio"
value={UserDetailsView.Saved}
checked={this.state.view == UserDetailsView.Saved}
onChange={linkEvent(this, this.handleViewChange)}
/>
{i18n.t('saved')}
</label>
</Button>
</div>
);
}

13
src/custom.css

@ -718,4 +718,15 @@ a.text-body {
.user-settings-container {
flex-direction: column-reverse;
}
}
}
.btn-group>label:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.btn-group>label:not(:first-child) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}

36
src/stories/Button.stories.tsx

@ -0,0 +1,36 @@
import React, { useState } from 'react';
import { Box, Label,
Input,
Select,
Textarea,
Radio,
Flex,
Checkbox,
Slider, } from 'theme-ui';
import Button from '../components/elements/Button';
import { ThemeSystemProvider } from '../components/ThemeSystemProvider';
import { themes } from '../theme';
export default { title: 'Buttons' };
export const Basic = () => {
return (
<div>
{Object.keys(themes).map(theme => {
return (
<ThemeSystemProvider key={theme} initialTheme={theme}>
<Box bg="background" p={2}>
<Button mx={1}>Primary</Button>
<Button variant="secondary" mx={1}>Secondary</Button>
<Button variant="highlight" mx={1}>Highlight</Button>
<Button variant="muted" mx={1}>Muted</Button>
<Button disabled mx={1}>Disabled</Button>
<Button variant="danger" mx={1}>Danger</Button>
<Button variant="outline" mx={1}>Outline</Button>
</Box>
</ThemeSystemProvider>
)
})}
</div>
)
}

93
src/stories/Theming.stories.tsx

@ -0,0 +1,93 @@
import React, { useState } from 'react';
import { Box, Label,
Input,
Select,
Textarea,
Radio,
Flex,
Checkbox,
Slider, } from 'theme-ui';
import Button from '../components/elements/Button';
import { ThemeSystemProvider } from '../components/ThemeSystemProvider';
import { ThemeSelector } from '../theme';
// import { Button } from '@storybook/react/demo';
export default { title: 'Themes' };
function Form() {
return (
<Box
as='form'
onSubmit={e => e.preventDefault()}>
<Label htmlFor='username'>Username</Label>
<Input
name='username'
id='username'
mb={3}
/>
<Label htmlFor='password'>Password</Label>
<Input
type='password'
name='password'
id='password'
mb={3}
/>
<Box>
<Label mb={3}>
<Checkbox />
Remember me
</Label>
</Box>
<Label htmlFor='sound'>Sound</Label>
<Select name='sound' id='sound' mb={3}>
<option>Beep</option>
<option>Boop</option>
<option>Blip</option>
</Select>
<Label htmlFor='comment'>Comment</Label>
<Textarea
name='comment'
id='comment'
rows='6'
mb={3}
/>
<Flex mb={3}>
<Label>
<Radio name='letter' /> Alpha
</Label>
<Label>
<Radio name='letter' /> Bravo
</Label>
<Label>
<Radio name='letter' /> Charlie
</Label>
</Flex>
<Label>
Slider
</Label>
<Slider mb={3} />
<Button variant="primary">
Submit
</Button>
<Button variant='secondary'>
Cancel
</Button>
</Box>
)
}
export const Basic = () => {
const [theme, setTheme] = useState('chapo');
return (
<ThemeSystemProvider>
<Box m={4}>
<Box mb={2}>
<ThemeSelector value={theme} onChange={newTheme => setTheme(newTheme)} />
</Box>
<Form />
</Box>
</ThemeSystemProvider>
)
};

56
src/theme.tsx

@ -1,35 +1,37 @@
import React from 'react';
import * as allThemes from '@theme-ui/presets';
import { Theme, ThemeProviderProps } from 'theme-ui';
import { Select, Theme, ThemeProviderProps } from 'theme-ui';
import { darken, lighten } from '@theme-ui/color';
import { i18n } from './i18next';
import { useThemeSystem } from './components/ThemeSystemProvider';
const { dark } = allThemes;
const { dark, bulma, tailwind, ...remainingThemes } = allThemes;
export const variants = {
buttons: {
primary: {
color: 'text',
backgroundColor: 'muted',
color: 'background',
bg: 'primary',
cursor: 'pointer',
// backgroundColor: 'primary',
'&:hover': {
color: 'text',
textDecoration: 'none',
// backgroundColor: darken('primary', 0.05),
backgroundColor: darken('muted', 0.1),
},
'&:disabled': {
opacity: 0.65,
opacity: 0.5,
cursor: 'not-allowed',
backgroundColor: '#444',
},
},
muted: {
bg: 'muted',
color: 'text',
},
secondary: {
color: 'background',
bg: 'secondary',
},
highlight: {
color: 'text',
backgroundColor: lighten('muted', 0.1),
'&:hover': {
backgroundColor: 'muted',
},
@ -38,6 +40,7 @@ export const variants = {
backgroundColor: 'danger',
},
outline: {
color: 'text',
borderColor: 'muted',
borderWidth: '1px',
borderStyle: 'solid',
@ -46,7 +49,7 @@ export const variants = {
},
forms: {
select: {
borderColor: lighten('muted', 0.4),
// borderColor: lighten('muted', 0.4),
backgroundColor: 'background',
color: 'text',
},
@ -61,16 +64,32 @@ const defaultTheme: ThemeProviderProps<Theme> = {
primary: '#DA1B9A',
secondary: '#2030DF',
accent: '#F3B90C',
danger: '#E74C3C',
danger: '#dc3545',
muted: '#303030',
},
buttons: {
...variants.buttons,
primary: {
...variants.buttons.primary,
color: 'text',
bg: 'primary'
},
secondary: {
...variants.buttons.secondary,
color: 'text',
bg: 'secondary',
}
}
};
export const themes = {
chapo: defaultTheme,
...allThemes,
chapo: { ...defaultTheme },
dark,
...remainingThemes,
};
// console.log({ themes })
export function ThemeSelector({ value, onChange }) {
const { setCurrentTheme } = useThemeSystem();
// console.log({ context });
@ -81,10 +100,11 @@ export function ThemeSelector({ value, onChange }) {
}
return (
<select
<Select
value={value}
onChange={handleThemeChange}
className="ml-2 custom-select custom-select-sm w-auto"
// ml={2}
// className="ml-2 custom-select custom-select-sm w-auto"
>
<option disabled>{i18n.t('theme')}</option>
{Object.keys(themes).map(theme => (
@ -92,7 +112,7 @@ export function ThemeSelector({ value, onChange }) {
{theme}
</option>
))}
</select>
</Select>
);
}

6734
yarn.lock
File diff suppressed because it is too large
View File

Loading…
Cancel
Save