@vixoniccom/menu-daily 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/assets/framed.ai +3330 -4
- package/assets/modern.ai +421 -0
- package/build.zip +0 -0
- package/configuration.json +207 -0
- package/icon.png +0 -0
- package/package.json +31 -0
- package/src/dataLoader.ts +168 -0
- package/src/global.d.ts +59 -0
- package/src/index.html +33 -0
- package/src/logger.ts +11 -0
- package/src/main.ts +47 -0
- package/src/scenes/App.tsx +103 -0
- package/src/scenes/components/FontLoader.tsx +52 -0
- package/src/scenes/components/FormattedText.tsx +56 -0
- package/src/scenes/components/Grid/Grid.tsx +161 -0
- package/src/scenes/components/Grid/GridItem.tsx +79 -0
- package/src/scenes/components/Grid/animation.ts +105 -0
- package/src/scenes/components/Grid/index.ts +2 -0
- package/src/scenes/components/MealContainer/components/OptionItem.tsx +25 -0
- package/src/scenes/components/MealContainer/components/Title/index.tsx +82 -0
- package/src/scenes/components/MealContainer/components/Title/styles/Framed.tsx +52 -0
- package/src/scenes/components/MealContainer/components/Title/styles/Modern.tsx +47 -0
- package/src/scenes/components/MealContainer/components/Title/styles/index.tsx +13 -0
- package/src/scenes/components/MealContainer/components/index.ts +2 -0
- package/src/scenes/components/MealContainer/index.tsx +59 -0
- package/src/static/menu-daily-example.xlsx +0 -0
- package/src/test/downloads/1234.ttf +0 -0
- package/src/test/downloads/background.jpg +0 -0
- package/src/test/downloads/futura-font.ttf +0 -0
- package/src/test/parameters.json +37 -0
- package/tsconfig.json +36 -0
- package/tslint.json +5 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
fonts: string[]
|
|
5
|
+
downloadPath: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
class FontLoader extends React.Component<Props> {
|
|
9
|
+
render () {
|
|
10
|
+
let fonts = this.props.fonts.map((font) => {
|
|
11
|
+
try {
|
|
12
|
+
return `
|
|
13
|
+
@font-face {
|
|
14
|
+
font-family: "${parseFontName(font)}";
|
|
15
|
+
src: url("${parseFontUrl(this.props.downloadPath, font)}");
|
|
16
|
+
}
|
|
17
|
+
`
|
|
18
|
+
} catch (err) {
|
|
19
|
+
return ''
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
return <style>{fonts}</style>
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function fontParser (parameters: VixonicParameters): string[] {
|
|
27
|
+
let initArr: string[] = []
|
|
28
|
+
return Object.keys(parameters).reduce(
|
|
29
|
+
(fonts, param) => {
|
|
30
|
+
switch (param) {
|
|
31
|
+
case 'itemTitleTextFormat':
|
|
32
|
+
case 'itemOptionsTextFormat':
|
|
33
|
+
if (parameters[param] && parameters[param]!.font && parameters[param]!.font!.filename) {
|
|
34
|
+
fonts.push((parameters[param]!.font!.filename || ''))
|
|
35
|
+
return fonts
|
|
36
|
+
} else return fonts
|
|
37
|
+
default:
|
|
38
|
+
return fonts
|
|
39
|
+
}
|
|
40
|
+
}, initArr
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const parseFontName = (filename: string): string => {
|
|
45
|
+
return filename.replace('.','-')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const parseFontUrl = (path: string, filename: string): string => {
|
|
49
|
+
return path + '/' + filename
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default FontLoader
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { parseFontName } from './FontLoader'
|
|
3
|
+
|
|
4
|
+
const alignments = {
|
|
5
|
+
center: 'center',
|
|
6
|
+
left: 'flex-start',
|
|
7
|
+
right: 'flex-end'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
text: string
|
|
12
|
+
downloadsPath: string
|
|
13
|
+
unit: 'px' | '%' | 'em' | 'vh'
|
|
14
|
+
defaults: {
|
|
15
|
+
fontSize: number,
|
|
16
|
+
fontColor: string
|
|
17
|
+
alignment: 'left' | 'center' | 'right'
|
|
18
|
+
}
|
|
19
|
+
format: VixonicTextFormat
|
|
20
|
+
multiline?: boolean
|
|
21
|
+
lineHeight?: number
|
|
22
|
+
style?: React.CSSProperties
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class FormattedText extends React.Component<Props> {
|
|
26
|
+
render () {
|
|
27
|
+
let { format, defaults } = this.props
|
|
28
|
+
let { alignment, font, fontColor, fontSize } = format
|
|
29
|
+
let containerStyle = Object.assign({
|
|
30
|
+
display: 'inline-flex',
|
|
31
|
+
justifyContent: this.getHorizontalAlignment(alignment && alignment.horizontal || defaults.alignment)
|
|
32
|
+
}, this.props.style)
|
|
33
|
+
return <div style={containerStyle}>
|
|
34
|
+
<span style={{
|
|
35
|
+
color: fontColor || defaults.fontColor,
|
|
36
|
+
width: '100%',
|
|
37
|
+
fontFamily: font && font.filename && `"${parseFontName(font.filename)}"` || undefined,
|
|
38
|
+
fontSize: `${fontSize || defaults.fontSize}${this.props.unit}`,
|
|
39
|
+
textAlign: alignment && alignment.horizontal || defaults.alignment,
|
|
40
|
+
lineHeight: this.props.lineHeight,
|
|
41
|
+
overflow: 'hidden',
|
|
42
|
+
textOverflow: 'ellipsis',
|
|
43
|
+
whiteSpace: this.props.multiline ? 'normal' : 'nowrap'
|
|
44
|
+
}}>{this.props.text}</span>
|
|
45
|
+
</div>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getHorizontalAlignment (alignment: any) {
|
|
49
|
+
if (alignment) {
|
|
50
|
+
return alignments.hasOwnProperty(alignment) ? (alignments as any)[alignment] : 'flex-start'
|
|
51
|
+
}
|
|
52
|
+
return 'flex-start'
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default FormattedText
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import Animation from './animation'
|
|
3
|
+
import Item from './GridItem'
|
|
4
|
+
|
|
5
|
+
type GridProps = {
|
|
6
|
+
animate: boolean,
|
|
7
|
+
animation: {
|
|
8
|
+
mode: 'fade' | 'slideLeft' | 'slideRight',
|
|
9
|
+
duration: number,
|
|
10
|
+
speed?: number,
|
|
11
|
+
stagger?: number,
|
|
12
|
+
reverse?: boolean
|
|
13
|
+
},
|
|
14
|
+
layout: {
|
|
15
|
+
rows: number,
|
|
16
|
+
rowsGap?: number,
|
|
17
|
+
columns: number,
|
|
18
|
+
columnsGap?: number,
|
|
19
|
+
alignment: {
|
|
20
|
+
h: 'start' | 'center' | 'end',
|
|
21
|
+
v: 'start' | 'center' | 'end'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
style?: React.CSSProperties
|
|
25
|
+
fontSize?: string
|
|
26
|
+
id: string
|
|
27
|
+
items: React.ReactNode[]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type GridState = {
|
|
31
|
+
show: boolean,
|
|
32
|
+
stage: 'idle' | 'preparing' | 'prepared' | 'animating',
|
|
33
|
+
items: React.ReactNode[]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
class Grid extends React.Component<GridProps, GridState> {
|
|
37
|
+
lastIndex: number
|
|
38
|
+
animation: any
|
|
39
|
+
animating: boolean = false
|
|
40
|
+
unmounting: boolean = false
|
|
41
|
+
|
|
42
|
+
container: HTMLDivElement | null = null
|
|
43
|
+
|
|
44
|
+
columns: number = 1
|
|
45
|
+
columnsGap: number = 1
|
|
46
|
+
rows: number = 1
|
|
47
|
+
rowsGap: number = 1
|
|
48
|
+
itemsCount: number = 1
|
|
49
|
+
|
|
50
|
+
state: GridState = {
|
|
51
|
+
show: false,
|
|
52
|
+
stage: 'idle',
|
|
53
|
+
items: []
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
constructor () {
|
|
57
|
+
super ()
|
|
58
|
+
this.lastIndex = 0
|
|
59
|
+
this.animation = new Animation()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
componentDidMount () {
|
|
63
|
+
this.configure(this.props)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
componentWillReceiveProps (nextProps: GridProps) {
|
|
67
|
+
this.configure(nextProps)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
componentWillUnmount () {
|
|
71
|
+
this.unmounting = true
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
configure (props: GridProps) {
|
|
75
|
+
this.animation.configure(props.animation)
|
|
76
|
+
this.columns = props.layout.columns || 1
|
|
77
|
+
this.columnsGap = props.layout.columnsGap || 0
|
|
78
|
+
this.rows = props.layout.rows || 1
|
|
79
|
+
this.rowsGap = props.layout.rowsGap || 0
|
|
80
|
+
this.itemsCount = this.rows * this.columns
|
|
81
|
+
if (props.animate && !this.animating && this.state.stage === 'idle') {
|
|
82
|
+
this.animating = true
|
|
83
|
+
this.createItems(props)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Filter items by index and create the proper item within its container.
|
|
88
|
+
createItems (props: GridProps) {
|
|
89
|
+
if (!props.items) return
|
|
90
|
+
let count = 0
|
|
91
|
+
this.lastIndex = this.lastIndex < props.items.length ? this.lastIndex : 0
|
|
92
|
+
let newItems = props.items.filter((_item, index) => {
|
|
93
|
+
return index >= this.lastIndex
|
|
94
|
+
}).map((item, index, arr) => {
|
|
95
|
+
if (count >= this.itemsCount) return null
|
|
96
|
+
this.lastIndex++
|
|
97
|
+
count++
|
|
98
|
+
return <Item
|
|
99
|
+
key={`${Math.random()}${Math.random()}`} containerData={{
|
|
100
|
+
ic_index: index,
|
|
101
|
+
ic_rowIndex: Math.floor(index / this.columns),
|
|
102
|
+
ic_columnIndex: Math.floor(index % this.columns),
|
|
103
|
+
ic_firstChild: index === 0,
|
|
104
|
+
ic_lastChild: index === (arr.length - 1)
|
|
105
|
+
}} style={this.animation.getInitialStyle()}
|
|
106
|
+
// Item alignment. By default is center - center.
|
|
107
|
+
alignment={props.layout.alignment}
|
|
108
|
+
// Setup item width based on columns count.
|
|
109
|
+
width={(100 - (this.columnsGap * (this.columns - 1))) / this.columns}
|
|
110
|
+
// Setup item height based on rows count. If 0 set up on auto.
|
|
111
|
+
height={(100 - (this.rowsGap * (this.rows - 1))) / this.rows}
|
|
112
|
+
// Setup horizontal gap
|
|
113
|
+
horizontalGap={this.columnsGap}
|
|
114
|
+
// Setup vertical gap
|
|
115
|
+
verticalGap={this.rowsGap}
|
|
116
|
+
// Optional fontSize
|
|
117
|
+
fontSize={this.props.fontSize}>
|
|
118
|
+
{item}
|
|
119
|
+
</Item>
|
|
120
|
+
})
|
|
121
|
+
if (newItems.length > 0) {
|
|
122
|
+
this.setState({
|
|
123
|
+
show: true,
|
|
124
|
+
stage: 'prepared',
|
|
125
|
+
items: newItems
|
|
126
|
+
})
|
|
127
|
+
} else {
|
|
128
|
+
this.setState({
|
|
129
|
+
show: false,
|
|
130
|
+
stage: 'idle'
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
render () {
|
|
136
|
+
return <div ref={(container) => { this.container = container }} style={{
|
|
137
|
+
opacity: this.state.show ? 1 : 0,
|
|
138
|
+
position: 'relative',
|
|
139
|
+
display: 'flex',
|
|
140
|
+
flexWrap: 'wrap',
|
|
141
|
+
alignContent: 'flex-start',
|
|
142
|
+
...this.props.style
|
|
143
|
+
}}>
|
|
144
|
+
{this.state.items}
|
|
145
|
+
</div>
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
componentDidUpdate () {
|
|
149
|
+
if (this.props.animate && this.state.stage === 'prepared') {
|
|
150
|
+
// Start animations.
|
|
151
|
+
this.animation.animate(this.container!.childNodes, () => {
|
|
152
|
+
!this.unmounting && this.createItems(this.props)
|
|
153
|
+
})
|
|
154
|
+
this.setState({
|
|
155
|
+
stage: 'animating'
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export default Grid
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
const aligments: {[alignment: string]: 'flex-start' | 'center' | 'flex-end'} = {
|
|
4
|
+
start: 'flex-start',
|
|
5
|
+
center: 'center',
|
|
6
|
+
end: 'flex-end'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
type GridItemProps = {
|
|
10
|
+
style: React.CSSProperties,
|
|
11
|
+
alignment: {
|
|
12
|
+
h: 'start' | 'center' | 'end',
|
|
13
|
+
v: 'start' | 'center' | 'end'
|
|
14
|
+
}
|
|
15
|
+
width: number,
|
|
16
|
+
height: number,
|
|
17
|
+
horizontalGap: number,
|
|
18
|
+
verticalGap: number,
|
|
19
|
+
containerData: ContainerDataProps
|
|
20
|
+
fontSize?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type ContainerDataProps = {
|
|
24
|
+
ic_index: number
|
|
25
|
+
ic_rowIndex: number,
|
|
26
|
+
ic_columnIndex: number,
|
|
27
|
+
ic_firstChild: boolean,
|
|
28
|
+
ic_lastChild: boolean
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class GridItem extends React.Component<GridItemProps, any> {
|
|
32
|
+
el: any
|
|
33
|
+
|
|
34
|
+
constructor () {
|
|
35
|
+
super()
|
|
36
|
+
this.state = {}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
componentDidMount () {
|
|
40
|
+
this.setState({height: this.el.offsetHeight})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
componentWillReceiveProps () {
|
|
44
|
+
this.setState({ height: this.el.offsetHeight })
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
render () {
|
|
48
|
+
let props = this.props
|
|
49
|
+
let style: React.CSSProperties = {
|
|
50
|
+
overflow: 'hidden',
|
|
51
|
+
display: 'flex',
|
|
52
|
+
position: 'relative',
|
|
53
|
+
alignItems: aligments[props.alignment ? props.alignment.v : 'center'],
|
|
54
|
+
justifyContent: aligments[props.alignment ? props.alignment.h : 'center'],
|
|
55
|
+
width: `${props.width}%`,
|
|
56
|
+
height: `${props.height}%`,
|
|
57
|
+
fontSize: this.props.fontSize || this.state.height && `${this.state.height}px`,
|
|
58
|
+
top: props.containerData.ic_rowIndex === 0
|
|
59
|
+
? '0'
|
|
60
|
+
: props.verticalGap
|
|
61
|
+
? `${props.verticalGap * props.containerData.ic_rowIndex}%`
|
|
62
|
+
: '0',
|
|
63
|
+
paddingLeft: props.containerData.ic_columnIndex === 0
|
|
64
|
+
? '0'
|
|
65
|
+
: props.horizontalGap
|
|
66
|
+
? `${props.horizontalGap}%`
|
|
67
|
+
: '0',
|
|
68
|
+
...props.style
|
|
69
|
+
}
|
|
70
|
+
return <div style={style}
|
|
71
|
+
ref={(el) => this.el = el}>
|
|
72
|
+
{
|
|
73
|
+
React.cloneElement<any, any>(props.children as React.ReactElement<any>, props.containerData)
|
|
74
|
+
}
|
|
75
|
+
</div>
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default GridItem
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
let anime = require('animejs')
|
|
2
|
+
|
|
3
|
+
// Predefined animation modes.
|
|
4
|
+
const animationModes: {[mode: string]: any} = {
|
|
5
|
+
fade: {
|
|
6
|
+
in: {
|
|
7
|
+
opacity: [0, 1],
|
|
8
|
+
easing: 'linear'
|
|
9
|
+
},
|
|
10
|
+
out: {
|
|
11
|
+
opacity: [1, 0],
|
|
12
|
+
easing: 'linear'
|
|
13
|
+
},
|
|
14
|
+
init: {
|
|
15
|
+
opacity: 0
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
slideRight: {
|
|
19
|
+
in: {
|
|
20
|
+
translateX: (_el: any, _i: any) => {
|
|
21
|
+
return [`-100vw`, '0vw']
|
|
22
|
+
},
|
|
23
|
+
easing: 'easeOutQuad'
|
|
24
|
+
},
|
|
25
|
+
out: {
|
|
26
|
+
translateX: (_el: any, _i: any) => {
|
|
27
|
+
return ['0vw', `100vw`]
|
|
28
|
+
},
|
|
29
|
+
easing: 'easeInQuad'
|
|
30
|
+
},
|
|
31
|
+
init: {
|
|
32
|
+
transform: 'translate(0vw)'
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
slideLeft: {
|
|
36
|
+
in: {
|
|
37
|
+
translateX: (_el: any, _i: any) => {
|
|
38
|
+
return [`100vw`, '0vw']
|
|
39
|
+
},
|
|
40
|
+
easing: 'easeOutQuad'
|
|
41
|
+
},
|
|
42
|
+
out: {
|
|
43
|
+
translateX: (_el: any, _i: any) => {
|
|
44
|
+
return ['0vw', `-100vw`]
|
|
45
|
+
},
|
|
46
|
+
easing: 'easeInQuad'
|
|
47
|
+
},
|
|
48
|
+
init: {
|
|
49
|
+
transform: 'translate(0vw)'
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class Animation {
|
|
55
|
+
mode: any = animationModes.fade
|
|
56
|
+
duration: number = 10000
|
|
57
|
+
speed: number = 1000
|
|
58
|
+
stagger: number = 1000 / 4
|
|
59
|
+
reverse?: boolean = false
|
|
60
|
+
|
|
61
|
+
configure (options: { mode?: string, duration?: number, speed?: number, stagger?: number, reverse?: boolean }) {
|
|
62
|
+
this.mode = options.mode && animationModes.hasOwnProperty(options.mode) && animationModes[options.mode] || animationModes.fade
|
|
63
|
+
this.duration = options.duration && options.duration > 1000 && options.duration || 10000
|
|
64
|
+
this.speed = 1000 * (options.speed || 1)
|
|
65
|
+
this.stagger = this.speed / (options.stagger || 4)
|
|
66
|
+
this.reverse = options.reverse
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
getInitialStyle () {
|
|
70
|
+
return this.mode.init
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
animate (listNodes: any, finished: Function) {
|
|
74
|
+
let self = this
|
|
75
|
+
let els = [].slice.call(listNodes, 0)
|
|
76
|
+
if (this.reverse) els = els.reverse()
|
|
77
|
+
if (!els || els.length < 1) return
|
|
78
|
+
let offset = this.duration - (((els.length - 1) * this.stagger) + this.speed) * 2
|
|
79
|
+
offset = offset < 0 ? 0 : offset
|
|
80
|
+
let animation = anime.timeline({
|
|
81
|
+
autoplay: false
|
|
82
|
+
})
|
|
83
|
+
animation.add(Object.assign({
|
|
84
|
+
targets: els,
|
|
85
|
+
duration: this.speed,
|
|
86
|
+
delay: function (_el: any, _i: any, _l: any) {
|
|
87
|
+
return _i * self.stagger
|
|
88
|
+
}
|
|
89
|
+
}, this.mode.in))
|
|
90
|
+
animation.add(Object.assign({
|
|
91
|
+
targets: els,
|
|
92
|
+
duration: this.speed,
|
|
93
|
+
delay: function (_el: any, _i: any, _l: any) {
|
|
94
|
+
return _i * self.stagger
|
|
95
|
+
},
|
|
96
|
+
offset: `+=${offset}`,
|
|
97
|
+
complete: () => {
|
|
98
|
+
finished()
|
|
99
|
+
}
|
|
100
|
+
}, this.mode.out))
|
|
101
|
+
animation.play()
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export default Animation
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import FormattedText from '../../FormattedText'
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
data: string
|
|
6
|
+
vixonicData: VixonicData
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default class OptionItem extends React.Component<Props> {
|
|
10
|
+
render () {
|
|
11
|
+
let { vixonicData } = this.props
|
|
12
|
+
return <FormattedText
|
|
13
|
+
text={this.props.data}
|
|
14
|
+
downloadsPath={vixonicData.downloadsPath}
|
|
15
|
+
defaults={{
|
|
16
|
+
fontSize: 10,
|
|
17
|
+
alignment: 'left',
|
|
18
|
+
fontColor: 'black'
|
|
19
|
+
}}
|
|
20
|
+
format={vixonicData.parameters.itemOptionsTextFormat || {}}
|
|
21
|
+
unit='%'
|
|
22
|
+
multiline
|
|
23
|
+
style={{width: '100%', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap'}} />
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import FormattedText from '../../../FormattedText'
|
|
3
|
+
import { ModernStyle, FramedStyle, TitleStyle } from './styles'
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
text: string
|
|
7
|
+
vixonicData: VixonicData
|
|
8
|
+
getPadding: (padding: string) => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const TitleStyles: {[name: string]: TitleStyle} = {
|
|
12
|
+
standard: {
|
|
13
|
+
component: null,
|
|
14
|
+
getPadding: () => ('0'),
|
|
15
|
+
heightOffset: 1
|
|
16
|
+
},
|
|
17
|
+
modern: ModernStyle,
|
|
18
|
+
framed: FramedStyle
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const defaultFontSize = 20
|
|
22
|
+
|
|
23
|
+
class Title extends React.Component<Props> {
|
|
24
|
+
style: TitleStyle
|
|
25
|
+
|
|
26
|
+
constructor () {
|
|
27
|
+
super()
|
|
28
|
+
this.style = TitleStyles.standard
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
componentDidMount () {
|
|
32
|
+
this.setup(this.props)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
setup (props: Props) {
|
|
36
|
+
let { parameters } = props.vixonicData
|
|
37
|
+
if (parameters.itemStyle && TitleStyles[parameters.itemStyle]) {
|
|
38
|
+
this.style = TitleStyles[parameters.itemStyle]
|
|
39
|
+
}
|
|
40
|
+
let fontSize = parameters.itemTitleTextFormat && parameters.itemTitleTextFormat.fontSize
|
|
41
|
+
props.getPadding(this.style.getPadding(fontSize || defaultFontSize))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
render () {
|
|
45
|
+
let { text } = this.props
|
|
46
|
+
let { parameters, downloadsPath } = this.props.vixonicData
|
|
47
|
+
let backgroundColor = parameters.itemTitleBackgroundColor
|
|
48
|
+
let fontSize = parameters.itemTitleTextFormat
|
|
49
|
+
&& parameters.itemTitleTextFormat.fontSize
|
|
50
|
+
&& (parameters.itemTitleTextFormat.fontSize / 100)
|
|
51
|
+
|| defaultFontSize / 100
|
|
52
|
+
return <div style={{display: 'flex', height: `${fontSize * (this.style.heightOffset || 1)}em`}}>
|
|
53
|
+
{this.style.component && <this.style.component type='l' color={backgroundColor}/>}
|
|
54
|
+
<div style={{flex: 1, display: 'flex', alignItems: 'center', position: 'relative', width: '100%'}}>
|
|
55
|
+
<FormattedText
|
|
56
|
+
text={text}
|
|
57
|
+
downloadsPath={downloadsPath}
|
|
58
|
+
defaults={{
|
|
59
|
+
fontSize: defaultFontSize,
|
|
60
|
+
alignment: 'left',
|
|
61
|
+
fontColor: 'black'
|
|
62
|
+
}}
|
|
63
|
+
format={parameters.itemTitleTextFormat || {}}
|
|
64
|
+
unit='%'
|
|
65
|
+
style={{
|
|
66
|
+
overflow: 'hidden',
|
|
67
|
+
position: 'absolute',
|
|
68
|
+
zIndex: 1,
|
|
69
|
+
width: '100%',
|
|
70
|
+
textOverflow: 'ellipsis',
|
|
71
|
+
whiteSpace: 'nowrap',
|
|
72
|
+
height: '100%',
|
|
73
|
+
alignItems: 'center'
|
|
74
|
+
}} />
|
|
75
|
+
{this.style.component && <this.style.component type='c' color={backgroundColor}/>}
|
|
76
|
+
</div>
|
|
77
|
+
{this.style.component && <this.style.component type='r' color={backgroundColor}/>}
|
|
78
|
+
</div>
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export default Title
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React, { SFC } from 'react'
|
|
2
|
+
import { TitleStyle, StyleProps } from './'
|
|
3
|
+
|
|
4
|
+
const Left: SFC<{color: string}> = (props) =>
|
|
5
|
+
(<svg x='0px' y='0px' style={{flexShrink: 0}} height='100%' viewBox='0 0 40 100'>
|
|
6
|
+
<g>
|
|
7
|
+
<path fill={props.color} d='M40,0H37.75C26.43,0,17.25,8.33,17.25,18.59v1.33a34.85,34.85,0,0,0,0,60.16v1.33c0,10.27,9.18,18.59,20.51,18.59H40ZM23.89,54.94A4.94,4.94,0,1,1,28.83,50,4.94,4.94,0,0,1,23.89,54.94Z'/>
|
|
8
|
+
<path fill='#fff' d='M40,95.21H37.75C29.08,95.21,22,89,22,81.41V77.34L19.67,76a30.07,30.07,0,0,1,0-51.9L22,22.66V18.59C22,11,29.08,4.79,37.75,4.79H40V3.42H37.75c-9.42,0-17.09,6.81-17.09,15.17v3.29l-1.69,1a31.44,31.44,0,0,0,0,54.26l1.69,1v3.29c0,8.37,7.67,15.17,17.09,15.17H40Z'/>
|
|
9
|
+
</g>
|
|
10
|
+
</svg>)
|
|
11
|
+
|
|
12
|
+
const Center: SFC<{color: string}> = (props) => (
|
|
13
|
+
<div style={{position: 'absolute', left: -1, right: 0, top: 0, bottom: 0}}>
|
|
14
|
+
<svg x='0px' y='0px' style={{position: 'absolute'}} width='100%' height='100%'
|
|
15
|
+
viewBox='0 0 40 100' preserveAspectRatio='none'>
|
|
16
|
+
<g>
|
|
17
|
+
<rect fill={props.color} width='40' height='100'/>
|
|
18
|
+
<g fill='#fff'>
|
|
19
|
+
<rect y='95.21' width='40' height='1.37'/>
|
|
20
|
+
<rect y='3.42' width='40' height='1.37'/>
|
|
21
|
+
</g>
|
|
22
|
+
</g>
|
|
23
|
+
</svg>
|
|
24
|
+
</div>
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
const Right: SFC<{color: string}> = (props) =>
|
|
28
|
+
(<svg x='0px' y='0px' style={{flexShrink: 0, marginLeft: -2}} height='100%' viewBox='0 0 40 100'>
|
|
29
|
+
<g>
|
|
30
|
+
<path fill={props.color} d='M0,100H2.25c11.33,0,20.51-8.33,20.51-18.59V80.08a34.85,34.85,0,0,0,0-60.16V18.59C22.75,8.32,13.57,0,2.25,0H0ZM16.11,45.06A4.94,4.94,0,1,1,11.17,50,4.94,4.94,0,0,1,16.11,45.06Z'/>
|
|
31
|
+
<path fill='#fff' d='M0,4.79H2.25C10.92,4.79,18,11,18,18.59v4.07L20.33,24a30.07,30.07,0,0,1,0,51.9L18,77.34v4.07C18,89,10.92,95.21,2.25,95.21H0v1.37H2.25c9.42,0,17.09-6.81,17.09-15.17V78.12l1.69-1a31.44,31.44,0,0,0,0-54.26l-1.69-1V18.59c0-8.37-7.67-15.17-17.09-15.17H0Z'/>
|
|
32
|
+
</g>
|
|
33
|
+
</svg>)
|
|
34
|
+
|
|
35
|
+
const Framed: SFC<StyleProps> = (props) => (
|
|
36
|
+
props.type === 'l'
|
|
37
|
+
? <Left color={props.color || 'rgba(0,0,0,0)'} />
|
|
38
|
+
: props.type === 'c'
|
|
39
|
+
? <Center color={props.color || 'rgba(0,0,0,0)'} />
|
|
40
|
+
: <Right color={props.color || 'rgba(0,0,0,0)'} />
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
const getPadding = (fontSize: number) => {
|
|
44
|
+
let height = (fontSize * 2) / 100
|
|
45
|
+
return `0 ${height * (40 / 100)}em 0 ${height * (40 / 100)}em`
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const FramedStyle: TitleStyle = {
|
|
49
|
+
component: Framed,
|
|
50
|
+
getPadding,
|
|
51
|
+
heightOffset: 2
|
|
52
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React, { SFC } from 'react'
|
|
2
|
+
import { TitleStyle, StyleProps } from './'
|
|
3
|
+
|
|
4
|
+
const Left: SFC<{color: string}> = (props) =>
|
|
5
|
+
(<svg x='0px' y='0px' style={{flexShrink: 0}} height='100%' viewBox='0 0 100 79.5'>
|
|
6
|
+
<g>
|
|
7
|
+
<polygon fill='#666665' points='14.7,17.5 14.4,17.1 0,17.1 0.3,17.5 16.8,39.4 0.3,61.4 14.7,61.4 31.2,39.4 '/>
|
|
8
|
+
<path fill={props.color} d='M100,0h-4.3C73.8,0,55.9,17.9,55.9,39.8v0c0,21.9,17.9,39.8,39.8,39.8h4.3V0z'/>
|
|
9
|
+
</g>
|
|
10
|
+
</svg>)
|
|
11
|
+
|
|
12
|
+
const Center: SFC<{color: string}> = (props) => (
|
|
13
|
+
<div style={{position: 'absolute', left: -1, right: 0, top: 0, bottom: 0}}>
|
|
14
|
+
<svg x='0px' y='0px' style={{position: 'absolute'}} width='100%' height='100%'
|
|
15
|
+
viewBox='0 0 100 79.5' preserveAspectRatio='none'>
|
|
16
|
+
<g>
|
|
17
|
+
<rect fill={props.color} width='100' height='79.5' />
|
|
18
|
+
</g>
|
|
19
|
+
</svg>
|
|
20
|
+
</div>
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const Right: SFC<{color: string}> = (props) =>
|
|
24
|
+
(<svg x='0px' y='0px' style={{flexShrink: 0, marginLeft: -2}} height='100%' viewBox='0 0 44.1 79.5'>
|
|
25
|
+
<g>
|
|
26
|
+
<path fill={props.color} d='M0,79.5h4.3c21.9,0,39.8-17.9,39.8-39.8v0C44.1,17.9,26.2,0,4.3,0H0V79.5z'/>
|
|
27
|
+
</g>
|
|
28
|
+
</svg>)
|
|
29
|
+
|
|
30
|
+
const Modern: SFC<StyleProps> = (props) => (
|
|
31
|
+
props.type === 'l'
|
|
32
|
+
? <Left color={props.color || 'rgba(0,0,0,0)'} />
|
|
33
|
+
: props.type === 'c'
|
|
34
|
+
? <Center color={props.color || 'rgba(0,0,0,0)'} />
|
|
35
|
+
: <Right color={props.color || 'rgba(0,0,0,0)'} />
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
const getPadding = (fontSize: number) => {
|
|
39
|
+
let height = (fontSize * 2) / 100
|
|
40
|
+
return `0 ${height * (44.1 / 79.5)}em 0 ${height * (100 / 79.5)}em`
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const ModernStyle: TitleStyle = {
|
|
44
|
+
component: Modern,
|
|
45
|
+
getPadding,
|
|
46
|
+
heightOffset: 2
|
|
47
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type StyleProps = {
|
|
2
|
+
color?: string
|
|
3
|
+
type: 'l' | 'c' | 'r'
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export type TitleStyle = {
|
|
7
|
+
component: React.StatelessComponent<StyleProps> | null
|
|
8
|
+
getPadding: ((height: number) => string)
|
|
9
|
+
heightOffset: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { ModernStyle } from './Modern'
|
|
13
|
+
export { FramedStyle } from './Framed'
|