Commit a9b4b2fb by zhanghaozhe

storybook

parent 05ab0595
import './style.scss'
\ No newline at end of file
.shadow {
display: inline-block;
background: rgba(255, 255, 255, 1);
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
.purchase {
width: 61px;
height: 18px;
background: rgba(0, 153, 255, 1);
border-radius: 9px;
color: #fff;
font-size: 12px;
border: 0;
outline: 0;
-webkit-appearance: none;
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
"@testing-library/user-event": "^7.2.1", "@testing-library/user-event": "^7.2.1",
"@types/jest": "^24.9.1", "@types/jest": "^24.9.1",
"@types/node": "^12.12.53", "@types/node": "^12.12.53",
"@types/qs": "^6.9.4",
"@types/react": "^16.9.43", "@types/react": "^16.9.43",
"@types/react-dom": "^16.9.8", "@types/react-dom": "^16.9.8",
"@types/react-redux": "^7.1.9", "@types/react-redux": "^7.1.9",
...@@ -63,9 +64,9 @@ ...@@ -63,9 +64,9 @@
"json-stringify-safe": "^5.0.1", "json-stringify-safe": "^5.0.1",
"less": "^3.9.0", "less": "^3.9.0",
"less-loader": "^4.1.0", "less-loader": "^4.1.0",
"lodash": "^4.17.15", "lodash": "^4.17.19",
"mini-css-extract-plugin": "0.9.0", "mini-css-extract-plugin": "0.9.0",
"node-sass": "^4.13.0", "node-sass": "^4.14.1",
"optimize-css-assets-webpack-plugin": "5.0.3", "optimize-css-assets-webpack-plugin": "5.0.3",
"pnp-webpack-plugin": "1.6.4", "pnp-webpack-plugin": "1.6.4",
"postcss-flexbugs-fixes": "4.1.0", "postcss-flexbugs-fixes": "4.1.0",
...@@ -74,7 +75,7 @@ ...@@ -74,7 +75,7 @@
"postcss-preset-env": "6.7.0", "postcss-preset-env": "6.7.0",
"postcss-safe-parser": "4.0.1", "postcss-safe-parser": "4.0.1",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"qrcode": "^1.3.3", "qrcode": "^1.4.4",
"qs": "^6.7.0", "qs": "^6.7.0",
"react": "^16.13.1", "react": "^16.13.1",
"react-ace": "^8.0.0", "react-ace": "^8.0.0",
...@@ -86,7 +87,7 @@ ...@@ -86,7 +87,7 @@
"react-lazy-load": "^3.0.13", "react-lazy-load": "^3.0.13",
"react-mobile-swiper": "^1.1.4", "react-mobile-swiper": "^1.1.4",
"react-redux": "^7.0.2", "react-redux": "^7.0.2",
"react-router-dom": "^5.0.1", "react-router-dom": "^5.2.0",
"react-spinners": "^0.5.4", "react-spinners": "^0.5.4",
"react-sticky": "^6.0.3", "react-sticky": "^6.0.3",
"redux": "^4.0.1", "redux": "^4.0.1",
...@@ -96,7 +97,6 @@ ...@@ -96,7 +97,6 @@
"resolve": "1.15.0", "resolve": "1.15.0",
"resolve-url-loader": "3.1.1", "resolve-url-loader": "3.1.1",
"sass-loader": "8.0.2", "sass-loader": "8.0.2",
"sass-resources-loader": "^2.0.0",
"semver": "6.3.0", "semver": "6.3.0",
"socket.io": "^2.2.0", "socket.io": "^2.2.0",
"store2": "^2.11.2", "store2": "^2.11.2",
...@@ -109,14 +109,16 @@ ...@@ -109,14 +109,16 @@
"video.js": "^7.6.5", "video.js": "^7.6.5",
"web-launch-app": "^2.1.9", "web-launch-app": "^2.1.9",
"webpack": "4.42.0", "webpack": "4.42.0",
"webpack-dev-server": "3.10.3", "webpack-dev-server": "^3.11.0",
"webpack-manifest-plugin": "2.2.0", "webpack-manifest-plugin": "2.2.0",
"workbox-webpack-plugin": "4.3.1" "workbox-webpack-plugin": "4.3.1"
}, },
"scripts": { "scripts": {
"start": "node scripts/start.js", "start": "node scripts/start.js",
"build": "node scripts/build.js", "build": "node scripts/build.js",
"test": "node scripts/test.js" "test": "node scripts/test.js",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
}, },
"eslintConfig": { "eslintConfig": {
"extends": "react-app" "extends": "react-app"
...@@ -194,13 +196,20 @@ ...@@ -194,13 +196,20 @@
}, },
"devDependencies": { "devDependencies": {
"@babel/runtime": "^7.7.2", "@babel/runtime": "^7.7.2",
"@storybook/addon-actions": "^5.3.19",
"@storybook/addon-knobs": "^5.3.19",
"@storybook/addon-links": "^5.3.19",
"@storybook/addons": "^5.3.19",
"@storybook/preset-typescript": "^3.0.0",
"@storybook/react": "^5.3.19",
"babel-plugin-import": "^1.11.0", "babel-plugin-import": "^1.11.0",
"browserslist": "^4.6.6", "browserslist": "^4.6.6",
"caniuse-lite": "^1.0.30000989", "caniuse-lite": "^1.0.30000989",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"fork-ts-checker-webpack-plugin": "^5.0.14",
"mockjs": "^1.0.1-beta3", "mockjs": "^1.0.1-beta3",
"postcss-px-to-viewport": "^1.1.0", "postcss-px-to-viewport": "^1.1.0",
"sass-resources-loader": "^2.0.0" "ts-loader": "^8.0.2"
}, },
"theme": "./src/assets/theme/config.js" "theme": "./src/assets/theme/config.js"
} }
@mixin fontFamily($font){
font-family: $font, "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;;
}
\ No newline at end of file
@import "../index";
.course-card-h {
position: relative;
display: flex;
width: 351px;
height: 108px;
.show {
position: relative;
flex: 0 0 auto;
width: 150px;
height: 108px;
margin-right: 15px;
img {
width: 100%;
height: 100%;
border-radius: 3px;
}
}
.info {
position: relative;
width: 181px;
height: 100%;
.title {
width: 100%;
margin-bottom: 10px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 16px;
color: #333;
}
.subtitle {
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
-webkit-line-clamp: 2;
font-size: 14px;
color: #666;
}
.status {
position: absolute;
left: 0;
bottom: 5px;
width: 100%;
}
}
}
\ No newline at end of file
import React, {ReactNode, ReactElement} from 'react';
import {handleNavigation, Navigation} from "../index";
import {RequireAtLeastOne} from 'src/utils/types'
import {History} from "history";
import './index.scss'
export interface CoursePropsBasic {
image: string
title: string
courseId: number
status: ReactNode
navigate?: (courseId: number) => void
history?: History
subtitle?: string
tag?: ReactElement
marketing?: string
}
export type CourseProps = RequireAtLeastOne<CoursePropsBasic, 'history' | 'navigate'>
const CourseCardH: React.FC<CourseProps> = ({image, title, subtitle, status, navigate, courseId, tag, history, marketing}) => {
return (
<div className={'course-card course-card-h'} onClick={(e) => {
if (navigate) {
handleNavigation({e, courseId, navigate})
} else {
handleNavigation({e, courseId, history} as Navigation)
}
}}>
<div className="show">
<img src={image} alt={title}/>
{marketing && <div className="marketing">{marketing}</div>}
{tag}
</div>
<div className="info">
<div className="title">{title}</div>
{subtitle && <div className="subtitle">{subtitle}</div>}
<div className="status">
{status}
</div>
</div>
</div>
);
}
CourseCardH.displayName = 'CourseCardH'
export default CourseCardH;
\ No newline at end of file
@import "src/assets/css/utils";
@import "../index";
.course-card-v {
width: 165px;
.show {
position: relative;
width: 100%;
height: 119px;
margin-bottom: 6px;
img {
width: 100%;
height: 100%;
border-radius: 4px;
}
}
.title {
margin-bottom: 30px;
font-size: 15px;
color: #525C65;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
-webkit-line-clamp: 2;
@include fontFamily('PingFangSC-Regular');
}
}
\ No newline at end of file
import React from 'react'
import {CourseProps} from '../course-card-h'
import {handleNavigation, Navigation} from "../index";
import './index.scss'
const CourseCardV: React.FC<CourseProps> = ({title, image, courseId, status, tag, navigate, history, marketing}) => {
return <div className={'course-card-v'} onClick={(e) => {
navigate ? handleNavigation({e, courseId, navigate})
: handleNavigation({e, courseId, history} as Navigation)
}}>
<div className="show">
<img src={image} alt={title}/>
{marketing && <div className="marketing">{marketing}</div>}
{tag}
</div>
<div className="title">{title}</div>
<div className="status">{status}</div>
</div>
}
export default CourseCardV
\ No newline at end of file
import React from "react";
import {withKnobs, number, text} from "@storybook/addon-knobs";
import {action} from "@storybook/addon-actions";
import CourseCardH from "./course-card-h";
import CourseCardV from "./course-card-v";
export const courseData = {
courseId: 140,
title: '三月面试求职班',
subtitle: '搞定算法 直通BAT',
image: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/20a86c1353.jpg',
marketing: '拼团减100元'
}
export default {
title: 'course-card',
component: CourseCardH,
decorators: [withKnobs, (story: () => React.ReactElement) => <div className={'shadow'}>{story()}</div>],
excludeStories: /.*Data$/
}
let {title, courseId, image, subtitle, marketing} = courseData
let navigate = action(`navigate to /detail?id=${courseId}`)
const status = <button className={'purchase'}>立即购买</button>
export const Default = () => {
title = text('title', title)
subtitle = text('subtitle', subtitle)
image = text('image', image)
courseId = number('courseId', courseId)
marketing = text('marketing', marketing)
return <CourseCardH title={title} status={status} courseId={courseId} subtitle={subtitle} image={image}
navigate={navigate} marketing={marketing}></CourseCardH>
}
export const V = () => {
title = text('title', title)
image = text('image', image)
courseId = number('courseId', courseId)
return <CourseCardV image={image} courseId={courseId} status={status} title={title}
navigate={navigate} marketing={marketing}></CourseCardV>
}
\ No newline at end of file
.marketing {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 24px;
color: #fff;
font-size: 13px;
background: rgba(224, 46, 36, .6);
text-align: center;
line-height: 24px;
}
\ No newline at end of file
import React from "react";
import { History } from "history";
import { RequireAtLeastOne } from 'src/utils/types'
import CourseCardV from "./course-card-v";
import CourseCardH from "./course-card-h";
interface BaseNavigation {
e: React.MouseEvent
courseId: number
navigate?: (courseId: number) => void
history?: History
}
export type Navigation = RequireAtLeastOne<BaseNavigation, 'history' | 'navigate'>
export const handleNavigation: (navigationArgs: Navigation) => void = ({ e, courseId, navigate, history }) => {
const _n = navigate || function (courseId: number) {
history!.push(`/detail?id=${courseId}`)
}
let nodeName = (e.target as HTMLElement).nodeName.toLowerCase()
if (nodeName === 'a' || nodeName === 'button') {
return
}
_n(courseId)
}
export const H = CourseCardH
export const V = CourseCardV
export default CourseCardH
\ No newline at end of file
$red: #FF2121;
$gray: #999;
.prices {
display: flex;
align-items: center;
.current {
margin-right: 14px;
font-size: 15px;
color: $red;
}
.origin {
font-size: 11px;
text-decoration: line-through;
color: $gray;
}
.sign {
font-size: 11px;
}
}
\ No newline at end of file
import React from "react";
import './index.scss'
interface Props {
current: number | string
origin: number | string
}
const Prices: React.FC<Props> = ({current, origin}) => {
return <div className="prices">
<span className="current"><span className={'sign'}>¥</span>{current}</span>
<span className='origin'>¥{origin}</span>
</div>
}
export default Prices
\ No newline at end of file
import React from 'react'
import Prices from './index'
import {withKnobs, number} from '@storybook/addon-knobs'
export default {
title: 'prices',
component: Prices,
decorators: [withKnobs, (story: () => React.ReactNode) => <div className={'shadow'} style={{width: '100px', padding: '10px'}}>{story()}</div>]
}
export const Default = () => {
const current = number('current', 100)
const origin = number('origin', 1000)
return <Prices current={current} origin={origin}></Prices>
}
\ No newline at end of file
import React, { Component } from 'react'; import React, { Component } from 'react';
import './index.scss'; import './index.scss';
import { HeaderBar, VList } from '../../common' import { HeaderBar, VList } from '../../common'
import { http, dateCountDown } from "src/utils"; import { http } from "src/utils";
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { Toast } from 'antd-mobile' import { Toast } from 'antd-mobile'
import { connect } from "react-redux" import { connect } from "react-redux"
......
import React, {Component} from 'react';
import {V} from 'src/common/course-card'
import {withRouter, RouteComponentProps} from 'react-router-dom'
class TSTest extends Component<RouteComponentProps> {
componentDidMount() {
}
render() {
return (
<div className={'ts-test'}>
TS
<V title={'a'} status={2} courseId={2}
history={this.props.history}
image={'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/20a86c1353.jpg'}></V>
</div>
);
}
}
export default withRouter(TSTest);
\ No newline at end of file
...@@ -351,4 +351,9 @@ export default [ ...@@ -351,4 +351,9 @@ export default [
path: '/anniversary_2020', path: '/anniversary_2020',
component: loadable(() => import('src/components/activity/2020-717')), component: loadable(() => import('src/components/activity/2020-717')),
}, },
{
path: '/ts-test',
component: loadable(() => import(/* webpackChunkName: 'ts-test' */'src/components/ts-test'))
}
] ]
import jsCookie from "js-cookie";
import {
differenceInDays,
differenceInHours,
differenceInMinutes,
differenceInSeconds,
} from 'date-fns'
export const getParam = (key, str) => { export const getParam = (key, str) => {
const _s = str ? str : location.href; const _s = str ? str : location.href;
const re = new RegExp(`(?:\\?|#|&)(${key})=([^=&#\\?]+)`, 'ig'); const re = new RegExp(`(?:\\?|#|&)(${key})=([^=&#\\?]+)`, 'ig');
...@@ -106,23 +97,6 @@ const browser = (function () { ...@@ -106,23 +97,6 @@ const browser = (function () {
} }
})() })()
const isLogin = (function () {
return jsCookie.get('uid') && jsCookie.get('token')
})()
const dateCountDown = (later, earlier) => {
const d = differenceInDays(later, earlier)
const h = differenceInHours(later, earlier) % 24
const m = differenceInMinutes(later, earlier) % 60
const s = differenceInSeconds(later, earlier) % 60
return {
d,
h,
m,
s,
}
}
const isValidUrl = (str) => { const isValidUrl = (str) => {
return /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/.test(str) return /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/.test(str)
} }
...@@ -130,12 +104,10 @@ const isValidUrl = (str) => { ...@@ -130,12 +104,10 @@ const isValidUrl = (str) => {
export { export {
default as http, default as http,
} } from './http.ts'
from './http'
export { export {
default as wxShare, default as wxShare,
} } from './wechat/share'
from './wechat/share'
export { export {
html, html,
initCaptcha, initCaptcha,
...@@ -143,8 +115,6 @@ export { ...@@ -143,8 +115,6 @@ export {
validateTel, validateTel,
validateEmail, validateEmail,
browser, browser,
isLogin,
dateCountDown,
isValidUrl, isValidUrl,
loadScript, loadScript,
getTimestamp, getTimestamp,
......
export type RequireAtLeastOne<T, Keys extends keyof T = keyof T> =
Pick<T, Exclude<keyof T, Keys>>
& {
[K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>
}[Keys]
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment