From ef16cfd0417284208c23528d61fc575f7d909c01 Mon Sep 17 00:00:00 2001 From: Maria Zadnepryanets Date: Sat, 1 Aug 2020 11:37:20 +0000 Subject: [PATCH] Redesign chart --- assets/swipe.png | Bin 0 -> 1115 bytes components/chart/chart-legend.js | 38 ++-- components/chart/chart-line.js | 22 +-- components/chart/chart.js | 172 +++++++++++------ components/chart/cycle-day-label.js | 51 +++-- components/chart/day-column.js | 24 +-- components/chart/dot-and-line.js | 94 ++++++---- components/chart/horizontal-grid.js | 27 ++- components/chart/nfp-lines.js | 85 --------- components/chart/no-data.js | 43 +++-- components/chart/styles.js | 174 ------------------ components/chart/symptom-cell.js | 41 +++-- components/chart/symptom-icon.js | 17 +- components/chart/temperature-column.js | 25 ++- components/chart/tick-list.js | 42 +++-- components/chart/tick.js | 48 +++-- components/chart/tutorial.js | 48 +++++ components/chart/y-axis.js | 14 +- components/common/app-page.js | 32 +++- .../cycle-day/symptoms/temperature-input.js | 5 +- components/helpers/chart.js | 125 +++++++++++-- .../nfp-settings/temperature-slider.js | 8 +- config.js | 57 +++--- i18n/en/labels.js | 4 + local-storage.js | 21 ++- styles/colors.js | 48 +++++ styles/typography.js | 28 ++- 27 files changed, 718 insertions(+), 575 deletions(-) create mode 100644 assets/swipe.png delete mode 100644 components/chart/nfp-lines.js delete mode 100644 components/chart/styles.js create mode 100644 components/chart/tutorial.js diff --git a/assets/swipe.png b/assets/swipe.png new file mode 100644 index 0000000000000000000000000000000000000000..5ddf77a60613ded3ba79eaa9e0cf5274df919d1f GIT binary patch literal 1115 zcmV-h1f=_kP)U{>zsjkps( z;r)^WSFivr>6(S%^sWW-@h|$Z8&_c!b~L0;7hyx{)KkU4c6^3~Se*vkgKsf{M{sGb z|9^Nzc=(yrmLI#4#yC((4JQ)gMjT3=^EiyNg*IlT{#Rfb-o{rrnCstXdxnNgHs zUk?J~P%D83G|eP|=0sv}CJ8Wu9+)#-1gh@IdZeAKt~T=_HV)-9dbbb@(6|zXcD8(AzJ<_coC&QGXF0 zO835G>xY12*uwO20!jp zuMmRVQ)p`yRTZ&3tJC;LD?&7VcuiD3OYyKM95>OvpvU$S&b46{}Q7011MNPQ9F&X^^ zHwist7{q&cS%|Bid7xYJK(-6Eh${AO{_2xQ|3^x`d{{`JOkK)ta@ikQ`M zL6>m(QV}8NPXmEA5%f+u9p}-FeYhUirRQRdpDbE%2e#tiL@!d6)Q~r(Hz0$)Kt1ERNt~QBr3CX^&W%GH4Z5cuj5`N>{H~|E-1hUFj-=HlcwN hwSF+Wq=A~p{2v!E?$a$*+L-_V002ovPDHLkV1fiR0yF>s literal 0 HcmV?d00001 diff --git a/components/chart/chart-legend.js b/components/chart/chart-legend.js index f94609a..1339a57 100644 --- a/components/chart/chart-legend.js +++ b/components/chart/chart-legend.js @@ -1,32 +1,38 @@ import React from 'react' import PropTypes from 'prop-types' -import { View } from 'react-native' +import { StyleSheet, View } from 'react-native' import AppText from '../common/app-text' -import DripHomeIcon from '../../assets/drip-home-icons' - -import styles from './styles' -import { cycleDayColor } from '../../styles' +import { Typography } from '../../styles/redesign' +import { CHART_YAXIS_WIDTH } from '../../config' import { shared as labels } from '../../i18n/en/labels' -const ChartLegend = ({ xAxisHeight }) => { +const ChartLegend = ({ height }) => { return ( - - - - {labels.date.toLowerCase()} - + + # + {labels.date} ) } ChartLegend.propTypes = { - xAxisHeight: PropTypes.number.isRequired + height: PropTypes.number.isRequired } +const styles = StyleSheet.create({ + container: { + alignItems: 'center', + justifyContent: 'flex-end', + width: CHART_YAXIS_WIDTH + }, + text: { + ...Typography.label + }, + textBold: { + ...Typography.labelBold + } +}) + export default ChartLegend diff --git a/components/chart/chart-line.js b/components/chart/chart-line.js index 95300ad..c74d0a1 100644 --- a/components/chart/chart-line.js +++ b/components/chart/chart-line.js @@ -3,20 +3,16 @@ import PropTypes from 'prop-types' import { Shape } from 'react-native/Libraries/ART/ReactNativeART' -import styles from './styles' +import { Colors } from '../../styles/redesign' +import { CHART_STROKE_WIDTH, CHART_GRID_LINE_HORIZONTAL_WIDTH } from '../../config' -const ChartLine = ({ path, isNfpLine = false }) => { - const strokeStyle = - isNfpLine ? styles.nfpLine.stroke : styles.column.stroke.color - const strokeWidth = - isNfpLine ? styles.nfpLine.strokeWidth : styles.column.stroke.width +const ChartLine = ({ path, isNfpLine }) => { + const color = isNfpLine ? Colors.orange : Colors.grey + const width = isNfpLine + ? CHART_STROKE_WIDTH : CHART_GRID_LINE_HORIZONTAL_WIDTH return ( - + ) } @@ -25,4 +21,8 @@ ChartLine.propTypes = { isNfpLine: PropTypes.bool, } +ChartLine.defaultProps = { + isNfpLine: false +} + export default ChartLine diff --git a/components/chart/chart.js b/components/chart/chart.js index c182c92..5f6039b 100644 --- a/components/chart/chart.js +++ b/components/chart/chart.js @@ -1,26 +1,33 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import { View, FlatList, ActivityIndicator } from 'react-native' +import { ActivityIndicator, FlatList, StyleSheet, View } from 'react-native' -import NoData from './no-data' import AppLoadingView from '../common/app-loading' -import YAxis from './y-axis' -import nfpLines from './nfp-lines' +import AppPage from '../common/app-page' +import AppText from '../common/app-text' + import DayColumn from './day-column' import HorizontalGrid from './horizontal-grid' -import AppText from '../common/app-text' +import NoData from './no-data' +import Tutorial from './tutorial' +import YAxis from './y-axis' import { connect } from 'react-redux' import { navigate } from '../../slices/navigation' import { getCycleDaysSortedByDate } from '../../db' import nothingChanged from '../../db/db-unchanged' -import { scaleObservable } from '../../local-storage' -import { makeColumnInfo } from '../helpers/chart' +import { getChartFlag, scaleObservable, setChartFlag } from '../../local-storage' +import { makeColumnInfo, nfpLines } from '../helpers/chart' -import config from '../../config' +import { + CHART_COLUMN_WIDTH, + SYMPTOMS, + CHART_SYMPTOM_HEIGHT_RATIO, + CHART_XAXIS_HEIGHT_RATIO +} from '../../config' import { shared } from '../../i18n/en/labels' -import styles from './styles' +import { Colors, Spacing } from '../../styles/redesign' class CycleChart extends Component { static propTypes = { @@ -36,11 +43,35 @@ class CycleChart extends Component { this.getFhmAndLtlInfo = nfpLines() this.shouldShowTemperatureColumn = false + this.checkShouldShowHint() this.prepareSymptomData() } + componentWillUnmount() { + this.cycleDaysSortedByDate.removeListener(this.handleDbChange) + this.removeObvListener() + } + + checkShouldShowHint = async () => { + const flag = await getChartFlag() + const shouldShowHint = flag === 'true' ? true : false + this.setState({ shouldShowHint }) + } + + setShouldShowHint = async () => { + await setChartFlag() + this.setState({ shouldShowHint: false }) + } + + onLayout = ({ nativeEvent }) => { + if (this.state.chartHeight) return false + + this.reCalculateChartInfo(nativeEvent) + this.updateListeners(this.reCalculateChartInfo) + } + prepareSymptomData = () => { - this.symptomRowSymptoms = config.symptoms.filter((symptomName) => { + this.symptomRowSymptoms = SYMPTOMS.filter((symptomName) => { return this.cycleDaysSortedByDate.some(cycleDay => { return cycleDay[symptomName] }) @@ -71,33 +102,21 @@ class CycleChart extends Component { reCalculateChartInfo = (nativeEvent) => { const { height, width } = nativeEvent.layout - const xAxisCoefficient = this.shouldShowTemperatureColumn ? - config.xAxisHeightPercentage : config.xAxisHeightPercentageLarge - const symptomCoefficient = this.shouldShowTemperatureColumn ? - config.symptomHeightPercentage : config.symptomHeightPercentageLarge - this.xAxisHeight = height * xAxisCoefficient + this.xAxisHeight = height * CHART_XAXIS_HEIGHT_RATIO const remainingHeight = height - this.xAxisHeight - this.symptomHeight = remainingHeight * symptomCoefficient + this.symptomHeight = remainingHeight * CHART_SYMPTOM_HEIGHT_RATIO this.symptomRowHeight = this.symptomRowSymptoms.length * this.symptomHeight this.columnHeight = remainingHeight - this.symptomRowHeight const chartHeight = this.shouldShowTemperatureColumn ? height : (this.symptomRowHeight + this.xAxisHeight) - - const numberOfColumnsToRender = Math.round(width / config.columnWidth) + const numberOfColumnsToRender = Math.round(width / CHART_COLUMN_WIDTH) const columns = makeColumnInfo() this.setState({ columns, chartHeight, numberOfColumnsToRender }) } - onLayout = ({ nativeEvent }) => { - if (this.state.chartHeight) return - - this.reCalculateChartInfo(nativeEvent) - this.updateListeners(this.reCalculateChartInfo) - } - updateListeners(dataUpdateHandler) { // remove existing listeners if(this.handleDbChange) { @@ -114,38 +133,47 @@ class CycleChart extends Component { this.removeObvListener = scaleObservable(dataUpdateHandler, false) } - componentWillUnmount() { - this.cycleDaysSortedByDate.removeListener(this.handleDbChange) - this.removeObvListener() - } - render() { - const { chartHeight, chartLoaded, numberOfColumnsToRender } = this.state - const shouldShowChart = this.chartSymptoms.length > 0 ? true : false + const { + chartHeight, + chartLoaded, + shouldShowHint, + numberOfColumnsToRender + } = this.state + const hasDataToDisplay = this.chartSymptoms.length > 0 return ( - - {!shouldShowChart && } - {shouldShowChart && !chartHeight && !chartLoaded && } + + {!hasDataToDisplay && } + {hasDataToDisplay && !chartHeight && !chartLoaded && } - {shouldShowChart && ( + {shouldShowHint && chartLoaded && + + } + {hasDataToDisplay && chartLoaded && + !this.shouldShowTemperatureColumn && + + + {shared.noTemperatureWarning} + + + } + {hasDataToDisplay && ( {chartHeight && chartLoaded && ( - - - {this.shouldShowTemperatureColumn && ()} - + )} {chartHeight && @@ -162,27 +190,28 @@ class CycleChart extends Component { onEndReached={() => this.setState({end: true})} ListFooterComponent={} updateCellsBatchingPeriod={800} - contentContainerStyle={{height: chartHeight}} + contentContainerStyle={{ height: chartHeight }} /> } + {chartHeight && chartLoaded && ( + + {this.shouldShowTemperatureColumn && + + } + + )} )} - {shouldShowChart && chartLoaded && !this.shouldShowTemperatureColumn - && ( - - {shared.noTemperatureWarning} - - )} - + ) } } function LoadingMoreView({ end }) { return ( - - {!end && } + + {!end && } ) } @@ -191,6 +220,29 @@ LoadingMoreView.propTypes = { end: PropTypes.bool } +const styles = StyleSheet.create({ + chartArea: { + flexDirection: 'row' + }, + chartContainer: { + flexDirection: 'column' + }, + loadingContainer: { + height: '100%', + backgroundColor: Colors.tourquiseLight, + justifyContent: 'center' + }, + page: { + marginVertical: Spacing.small + }, + pageContainer: { + paddingHorizontal: Spacing.base + }, + warning: { + padding: Spacing.large + } +}) + const mapDispatchToProps = (dispatch) => { return({ navigate: (page) => dispatch(navigate(page)), diff --git a/components/chart/cycle-day-label.js b/components/chart/cycle-day-label.js index bb794f4..7378f92 100644 --- a/components/chart/cycle-day-label.js +++ b/components/chart/cycle-day-label.js @@ -1,32 +1,33 @@ import React from 'react' import PropTypes from 'prop-types' - -import { Text, View } from 'react-native' - -import moment from 'moment' +import { StyleSheet, View } from 'react-native' import { LocalDate } from 'js-joda' +import moment from 'moment' + +import AppText from '../common/app-text' -import styles from './styles' import cycleModule from '../../lib/cycle' +import { dateEnding } from '../helpers/home' +import { Containers, Typography } from '../../styles/redesign' const CycleDayLabel = ({ height, date }) => { - const { label } = styles.column const dayDate = LocalDate.parse(date) const cycleDayNumber = cycleModule().getCycleDayNumber(date) const isFirstDayOfMonth = dayDate.dayOfMonth() === 1 - const dateFormatting = isFirstDayOfMonth ? 'MMM' : 'Do' + const dateFormatting = isFirstDayOfMonth ? 'MMM' : 'D' const shortDate = moment(date, "YYYY-MM-DD").format(dateFormatting) - const boldDateLabel = isFirstDayOfMonth ? {fontWeight: 'bold'} : {} + const ending = isFirstDayOfMonth ? + '' : dateEnding[this.cycleDayNumber] || dateEnding['default'] + const cycleDayLabel = cycleDayNumber ? cycleDayNumber : ' ' return ( - - - {cycleDayNumber ? cycleDayNumber : ' '} - - - {shortDate} - + + {cycleDayLabel} + + {shortDate} + {ending} + ) } @@ -36,4 +37,24 @@ CycleDayLabel.propTypes = { date: PropTypes.string, } +const styles = StyleSheet.create({ + container: { + alignItems: 'flex-start', + justifyContent: 'flex-end', + left: 4, + }, + containerRow: { + ...Containers.rowContainer + }, + text: { + ...Typography.label + }, + textBold: { + ...Typography.labelBold + }, + textLight: { + ...Typography.labelLight + } +}) + export default CycleDayLabel diff --git a/components/chart/day-column.js b/components/chart/day-column.js index efefe2e..c5429a0 100644 --- a/components/chart/day-column.js +++ b/components/chart/day-column.js @@ -92,6 +92,18 @@ class DayColumn extends Component { activeOpacity={1} > + {shouldShowTemperatureColumn && } + + + { symptomRowSymptoms.map(symptom => { const hasSymptomData = this.data.hasOwnProperty(symptom) return ( @@ -107,18 +119,6 @@ class DayColumn extends Component { } )} - {shouldShowTemperatureColumn && } - - - ) } diff --git a/components/chart/dot-and-line.js b/components/chart/dot-and-line.js index be5be85..f7da601 100644 --- a/components/chart/dot-and-line.js +++ b/components/chart/dot-and-line.js @@ -2,8 +2,14 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import { Path, Shape } from 'react-native/Libraries/ART/ReactNativeART' -import styles from './styles' -import config from '../../config' +import { Colors } from '../../styles/redesign' + +import { + CHART_COLUMN_WIDTH, + CHART_COLUMN_MIDDLE, + CHART_DOT_RADIUS, + CHART_STROKE_WIDTH +} from '../../config' export default class DotAndLine extends Component { static propTypes = { @@ -20,48 +26,56 @@ export default class DotAndLine extends Component { } render() { - const y = this.props.y - const exclude = this.props.exclude - let lineToRight - let lineToLeft + const { + exclude, + leftTemperatureExclude, + leftY, + rightTemperatureExclude, + rightY, + y + } = this.props + let excludeLeftLine, excludeRightLine, lineLeft, lineRight - if (this.props.leftY) { - const middleY = ((this.props.leftY - y) / 2) + y - const excludedLine = this.props.leftTemperatureExclude || exclude - lineToLeft = makeLine(y, middleY, 0, excludedLine) + if (leftY) { + const middleY = ((leftY - y) / 2) + y + excludeLeftLine = leftTemperatureExclude || exclude + lineLeft = new Path() + .moveTo(CHART_COLUMN_MIDDLE - CHART_DOT_RADIUS, y) + .lineTo(0, middleY) } - if (this.props.rightY) { - const middleY = ((y - this.props.rightY) / 2) + this.props.rightY - const excludedLine = this.props.rightTemperatureExclude || exclude - lineToRight = makeLine(y, middleY, config.columnWidth, excludedLine) + if (rightY) { + const middleY = ((y - rightY) / 2) + rightY + excludeRightLine = rightTemperatureExclude || exclude + lineRight = new Path() + .moveTo(CHART_COLUMN_MIDDLE + CHART_DOT_RADIUS, y) + .lineTo(CHART_COLUMN_WIDTH, middleY) } - const dotStyle = exclude ? styles.curveDotsExcluded : styles.curveDots - const radius = dotStyle.r - const dot = ( - + const dot = new Path().moveTo(CHART_COLUMN_MIDDLE , y - CHART_DOT_RADIUS) + .arc(0, CHART_DOT_RADIUS * 2, CHART_DOT_RADIUS) + .arc(0, CHART_DOT_RADIUS * -2, CHART_DOT_RADIUS) + const dotColor = exclude ? Colors.tourquise : Colors.tourquiseDark + const lineColorLeft = excludeLeftLine ? + Colors.tourquise : Colors.tourquiseDark + const lineColorRight = excludeRightLine ? + Colors.tourquise : Colors.tourquiseDark + + return( + + + + + ) - return [lineToLeft, lineToRight, dot] } } - -function makeLine(currY, middleY, x, excludeLine) { - const lineStyle = excludeLine ? styles.curveExcluded : styles.curve - - return -} \ No newline at end of file diff --git a/components/chart/horizontal-grid.js b/components/chart/horizontal-grid.js index e7cf7cc..ddbbe53 100644 --- a/components/chart/horizontal-grid.js +++ b/components/chart/horizontal-grid.js @@ -1,26 +1,33 @@ import React from 'react' import PropTypes from 'prop-types' -import { View } from 'react-native' +import { StyleSheet, View } from 'react-native' import { getTickPositions } from '../helpers/chart' -import styles from './styles' +import { Colors } from '../../styles/redesign' +import { CHART_GRID_LINE_HORIZONTAL_WIDTH, CHART_YAXIS_WIDTH } from '../../config' -const HorizontalGrid = ({ height, startPosition }) => { +const HorizontalGrid = ({ height }) => { return getTickPositions(height).map(tick => { return ( - + ) }) } HorizontalGrid.propTypes = { - height: PropTypes.number, - startPosition: PropTypes.number, + height: PropTypes.number } +const styles = StyleSheet.create({ + line: { + borderStyle: 'solid', + borderBottomColor: Colors.grey, + borderBottomWidth: CHART_GRID_LINE_HORIZONTAL_WIDTH, + left: CHART_YAXIS_WIDTH, + position:'absolute', + right: 0 + } +}) + export default HorizontalGrid diff --git a/components/chart/nfp-lines.js b/components/chart/nfp-lines.js deleted file mode 100644 index 853dde5..0000000 --- a/components/chart/nfp-lines.js +++ /dev/null @@ -1,85 +0,0 @@ -import { getCycleStatusForDay } from '../../lib/sympto-adapter' -import { normalizeToScale } from '../helpers/chart' - -export default function () { - const cycle = { - status: null - } - - function updateCurrentCycle(dateString) { - // for the NFP lines, we don't care about potentially extending the - // preOvu phase, so we don't include all earlier cycles, as that is - // an expensive db operation at the moment - cycle.status = getCycleStatusForDay( - dateString, { excludeEarlierCycles: true } - ) - if(!cycle.status) { - cycle.noMoreCycles = true - return - } - if (cycle.status.phases.preOvulatory) { - cycle.startDate = cycle.status.phases.preOvulatory.start.date - } else { - cycle.startDate = cycle.status.phases.periOvulatory.start.date - } - } - - function dateIsInPeriOrPostPhase(dateString) { - return ( - dateString >= cycle.status.phases.periOvulatory.start.date - ) - } - - function precededByAnotherTempValue(dateString) { - return ( - // we are only interested in days that have a preceding - // temp - Object.keys(cycle.status.phases).some(phaseName => { - return cycle.status.phases[phaseName].cycleDays.some(day => { - return day.temperature && day.date < dateString - }) - }) - // and also a following temp, so we don't draw the line - // longer than necessary - && - cycle.status.phases.postOvulatory.cycleDays.some(day => { - return day.temperature && day.date > dateString - }) - ) - } - - function isInTempMeasuringPhase(temperature, dateString) { - return ( - temperature || precededByAnotherTempValue(dateString) - ) - } - - return function(dateString, temperature, columnHeight) { - const ret = { - drawLtlAt: null, - drawFhmLine: false - } - if (!cycle.status && !cycle.noMoreCycles) updateCurrentCycle(dateString) - if (cycle.noMoreCycles) return ret - - if (dateString < cycle.startDate) updateCurrentCycle(dateString) - if (cycle.noMoreCycles) return ret - - const tempShift = cycle.status.temperatureShift - - if (tempShift) { - if (tempShift.firstHighMeasurementDay.date === dateString) { - ret.drawFhmLine = true - } - - if ( - dateIsInPeriOrPostPhase(dateString) && - isInTempMeasuringPhase(temperature, dateString) - ) { - ret.drawLtlAt = normalizeToScale(tempShift.ltl, columnHeight) - } - } - - return ret - } -} \ No newline at end of file diff --git a/components/chart/no-data.js b/components/chart/no-data.js index 0115114..5044b18 100644 --- a/components/chart/no-data.js +++ b/components/chart/no-data.js @@ -1,31 +1,44 @@ import React from 'react' +import { StyleSheet, View } from 'react-native' import PropTypes from 'prop-types' -import { View } from 'react-native' import AppText from '../common/app-text' -import SettingsButton from '../settings/shared/settings-button' +import Button from '../common/button' +import { connect } from 'react-redux' +import { navigate } from '../../slices/navigation' + +import { Containers } from '../../styles/redesign' import { shared } from '../../i18n/en/labels' -import styles from './styles' const NoData = ({ navigate }) => { return ( - - - {shared.noDataWarning} - {navigate('CycleDay')}} - style={{marginHorizontal: 40}} - > - {shared.noDataButtonText} - - + + {shared.noDataWarning} + ) } NoData.propTypes = { - navigate: PropTypes.func, + navigate: PropTypes.func.isRequired, } -export default NoData \ No newline at end of file +const styles = StyleSheet.create({ + container: { + ...Containers.centerItems + } +}) + +const mapDispatchToProps = (dispatch) => { + return({ + navigate: (page) => dispatch(navigate(page)), + }) +} + +export default connect( + null, + mapDispatchToProps, +)(NoData) \ No newline at end of file diff --git a/components/chart/styles.js b/components/chart/styles.js deleted file mode 100644 index fba4df1..0000000 --- a/components/chart/styles.js +++ /dev/null @@ -1,174 +0,0 @@ -import config from '../../config' -import { shadesOfRed, cycleDayColor } from '../../styles/index' - -const colorTemperature = '#765285' -const colorTemperatureLight = '#a67fb5' -export const dotRadius = 5 -const lineWidth = 1.5 -const colorLtl = '#feb47b' -const gridColor = '#d3d3d3' -const gridLineWidthVertical = 0.6 -const gridLineWidthHorizontal = 0.3 -const numberLabelFontSize = 13 - -const redColor = '#c3000d' -const violetColor = '#6a7b98' -const shadesOfViolet = ['#e3e7ed', '#c8cfdc', '#acb8cb', '#91a0ba', '#7689a9', violetColor] // light to dark -const yellowColor = '#dbb40c' -const shadesOfYellow = ['#f0e19d', '#e9d26d', '#e2c33c', yellowColor] // light to dark -const magentaColor = '#6f2565' -const shadesOfMagenta = ['#a87ca2', '#8b5083', magentaColor] // light to dark -const pinkColor = '#9e346c' -const shadesOfPink = ['#c485a6', '#b15c89', pinkColor] // light to dark -const lightGreenColor = '#bccd67' -const orangeColor = '#bc6642' -const mintColor = '#6ca299' - -const styles = { - container: { flex: 1 }, - chartContainer: { flexDirection: 'column' }, - chartArea: { flexDirection: 'row' }, - centerItem: { - flex:1, - alignItems: 'center', - justifyContent: 'center', - marginHorizontal: 25, - }, - curve: { - stroke: colorTemperature, - strokeWidth: lineWidth, - }, - curveExcluded: { - stroke: colorTemperatureLight, - strokeWidth: lineWidth - }, - curveDots: { - fill: colorTemperature, - r: dotRadius - }, - curveDotsExcluded: { - fill: colorTemperatureLight, - r: dotRadius - }, - column: { - label: { - date: { - color: 'grey', - fontSize: 9, - fontWeight: '100', - textAlign: 'center', - paddingTop: 2.5 - }, - number: { - color: cycleDayColor, - fontSize: numberLabelFontSize, - textAlign: 'center', - } - }, - stroke: { - color: gridColor, - width: gridLineWidthVertical, - } - }, - symptomDot: { - width: 12, - height: 12, - borderRadius: 50, - }, - iconColors: { - 'bleeding': { - color: redColor, - shades: shadesOfRed, - }, - 'mucus': { - color: violetColor, - shades: shadesOfViolet, - }, - 'cervix': { - color: yellowColor, - shades: shadesOfYellow, - }, - 'sex': { - color: magentaColor, - shades: shadesOfMagenta, - }, - 'desire': { - color: pinkColor, - shades: shadesOfPink, - }, - 'pain': { - color: lightGreenColor, - shades: [lightGreenColor], - }, - 'mood': { - color: orangeColor, - shades: [orangeColor], - }, - 'note': { - color: mintColor, - shades: [mintColor], - }, - }, - yAxis: { - width: 27, - borderRightWidth: 1, - borderColor: 'lightgrey', - borderStyle: 'solid' - }, - yAxisLabels: { - tempScale: { - position: 'absolute', - right: 2, - color: 'grey', - fontSize: 9, - textAlign: 'left' - }, - cycleDayLabel: { - textAlign: 'center', - justifyContent: 'center', - fontSize: Math.ceil(numberLabelFontSize / 2) - }, - dateLabel: { - textAlign: 'center', - justifyContent: 'center', - color: 'grey', - fontSize: 9, - fontWeight: '100', - } - }, - symptomIcon: { - alignItems: 'center', - justifyContent: 'center', - }, - chartLegend: { - alignItems: 'center', - justifyContent: 'flex-end', - }, - boldTick: { - fontWeight: 'bold', - fontSize: 11, - }, - horizontalGrid: { - position:'absolute', - borderStyle: 'solid', - borderBottomColor: gridColor, - borderBottomWidth: gridLineWidthHorizontal, - width: '100%', - left: config.columnWidth - }, - nfpLine: { - stroke: colorLtl, - strokeWidth: lineWidth, - }, - symptomRow: { - alignItems: 'center', - justifyContent: 'center', - }, - loadingMore: { - height: '100%', - backgroundColor: 'lightgrey', - justifyContent: 'center' - } -} - -export default styles \ No newline at end of file diff --git a/components/chart/symptom-cell.js b/components/chart/symptom-cell.js index 4b1124c..23d1667 100644 --- a/components/chart/symptom-cell.js +++ b/components/chart/symptom-cell.js @@ -1,9 +1,13 @@ import React from 'react' import PropTypes from 'prop-types' -import { View } from 'react-native' +import { StyleSheet, View } from 'react-native' -import styles from './styles' -import config from '../../config' +import { Colors, Containers } from '../../styles/redesign' +import { + CHART_COLUMN_WIDTH, + CHART_DOT_RADIUS, + CHART_GRID_LINE_HORIZONTAL_WIDTH +} from '../../config' const SymptomCell = ({ height, @@ -13,29 +17,23 @@ const SymptomCell = ({ }) => { const shouldDrawDot = symptomValue !== false - const styleParent = [styles.symptomRow, { height, width: config.columnWidth }] - let styleChild + const styleCell = [styles.cell, { height, width: CHART_COLUMN_WIDTH }] + let styleDot if (shouldDrawDot) { - const styleSymptom = styles.iconColors[symptom] + const styleSymptom = Colors.iconColors[symptom] const symptomColor = styleSymptom.shades[symptomValue] - const isMucusOrCervix = (symptom === 'mucus') || (symptom === 'cervix') - const backgroundColor = (isMucusOrCervix && !isSymptomDataComplete) ? 'white' : symptomColor const borderWidth = (isMucusOrCervix && !isSymptomDataComplete) ? 2 : 0 const borderColor = symptomColor - styleChild = [styles.symptomDot, { - backgroundColor, - borderColor, - borderWidth - }] + styleDot = [styles.dot, { backgroundColor, borderColor, borderWidth }] } return ( - - {shouldDrawDot && } + + {shouldDrawDot && } ) } @@ -50,4 +48,17 @@ SymptomCell.propTypes = { isSymptomDataComplete: PropTypes.bool, } +const styles = StyleSheet.create({ + cell: { + backgroundColor: 'white', + borderColor: Colors.greyLight, + borderWidth: CHART_GRID_LINE_HORIZONTAL_WIDTH, + ...Containers.centerItems + }, + dot: { + width: CHART_DOT_RADIUS * 2, + height: CHART_DOT_RADIUS * 2, + borderRadius: 50 + } +}) export default SymptomCell diff --git a/components/chart/symptom-icon.js b/components/chart/symptom-icon.js index 3236c3b..849283d 100644 --- a/components/chart/symptom-icon.js +++ b/components/chart/symptom-icon.js @@ -1,18 +1,19 @@ import React from 'react' import PropTypes from 'prop-types' -import { View } from 'react-native' +import { StyleSheet , View } from 'react-native' import DripIcon from '../../assets/drip-icons' -import styles from './styles' +import { Colors, Containers } from '../../styles/redesign' +import { CHART_YAXIS_WIDTH, CHART_ICON_SIZE } from '../../config' const SymptomIcon = ({ symptom, height }) => { return ( - + ) @@ -23,4 +24,10 @@ SymptomIcon.propTypes = { symptom: PropTypes.string, } +const styles = StyleSheet.create({ + container: { + ...Containers.centerItems + } +}) + export default SymptomIcon diff --git a/components/chart/temperature-column.js b/components/chart/temperature-column.js index fab3d97..18f36bf 100644 --- a/components/chart/temperature-column.js +++ b/components/chart/temperature-column.js @@ -1,13 +1,13 @@ import React from 'react' import PropTypes from 'prop-types' +import { StyleSheet } from 'react-native' import { Surface , Path } from 'react-native/Libraries/ART/ReactNativeART' import ChartLine from './chart-line' import DotAndLine from './dot-and-line' -import styles from './styles' -import config from '../../config' +import { CHART_COLUMN_WIDTH, CHART_STROKE_WIDTH } from '../../config' const TemperatureColumn = ({ horizontalLinePosition, @@ -15,20 +15,21 @@ const TemperatureColumn = ({ data, columnHeight }) => { - - const x = styles.nfpLine.strokeWidth / 2 + const x = CHART_STROKE_WIDTH / 2 return ( - + - + {horizontalLinePosition && { + return ( - { - getTickList(height) - .map(({ label, position, isBold, shouldShowLabel}) => { - return ( - - ) - }) - } + + { + getTickList(height) + .map(({ isBold, label, position, shouldShowLabel, tickHeight}) => { + return ( + + ) + }) + } + ) } @@ -31,4 +33,10 @@ TickList.propTypes = { height: PropTypes.number, } +const styles = StyleSheet.create({ + container: { + flex: 1 + } +}) + export default TickList diff --git a/components/chart/tick.js b/components/chart/tick.js index 4dc6b28..01b260d 100644 --- a/components/chart/tick.js +++ b/components/chart/tick.js @@ -1,29 +1,53 @@ import React from 'react' +import { StyleSheet, View } from 'react-native' import PropTypes from 'prop-types' import AppText from '../common/app-text' -import styles from './styles' +import { Sizes } from '../../styles/redesign' -const Tick = ({ yPosition, isBold, shouldShowLabel, label }) => { - // this eyeballing is sadly necessary because RN does not - // support percentage values for transforms, which we'd need - // to reliably place the label vertically centered to the grid - const topPosition = yPosition - 8 - const style = [ - styles.yAxisLabels.tempScale, - {top: topPosition}, - isBold && styles.boldTick - ] +const Tick = ({ yPosition, height, isBold, shouldShowLabel, label }) => { + const top = yPosition - height / 2 + const containerStyle = [ styles.container, { flexBasis: height, height, top }] + const textStyle = isBold ? styles.textBold : styles.textNormal - return {shouldShowLabel && label} + return( + + {shouldShowLabel && label} + + ) } Tick.propTypes = { yPosition: PropTypes.number, + height: PropTypes.number.isRequired, isBold: PropTypes.bool, shouldShowLabel: PropTypes.bool, label: PropTypes.string, } + +const text = { + right: 4, + lineHeight: Sizes.base, + textAlign: 'right', + textAlignVertical: 'center' +} +const styles = StyleSheet.create({ + container: { + position: 'absolute', + right: 0, + width: 40 + }, + textBold: { + fontSize: Sizes.base, + fontWeight: 'bold', + ...text + }, + textNormal: { + fontSize: Sizes.small, + ...text + } +}) + export default Tick diff --git a/components/chart/tutorial.js b/components/chart/tutorial.js new file mode 100644 index 0000000..49dec5c --- /dev/null +++ b/components/chart/tutorial.js @@ -0,0 +1,48 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { Image, StyleSheet, TouchableOpacity, View } from 'react-native' + +import AppIcon from '../common/app-icon' +import AppText from '../common/app-text' + +import { Colors, Containers, Sizes, Spacing } from '../../styles/redesign' +import { chart } from '../../i18n/en/labels' + +const image = require('../../assets/swipe.png') + +const Tutorial = ({ onClose }) => { + return ( + + + + {chart.tutorial} + + + + + + ) +} + +Tutorial.propTypes = { + onClose: PropTypes.func.isRequired +} + +const styles = StyleSheet.create({ + container: { + ...Containers.rowContainer, + padding: Spacing.large + }, + iconContainer: { + alignSelf: 'flex-start', + marginBottom: Sizes.base + }, + image: { + height: 40 + }, + textContainer: { + width: '70%' + } +}) + +export default Tutorial \ No newline at end of file diff --git a/components/chart/y-axis.js b/components/chart/y-axis.js index db27e10..c9e13f2 100644 --- a/components/chart/y-axis.js +++ b/components/chart/y-axis.js @@ -1,12 +1,12 @@ import React from 'react' import PropTypes from 'prop-types' -import { View } from 'react-native' +import { StyleSheet, View } from 'react-native' import SymptomIcon from './symptom-icon' import TickList from './tick-list' import ChartLegend from './chart-legend' -import styles from './styles' +import { CHART_YAXIS_WIDTH } from '../../config' const YAxis = ({ height, @@ -19,6 +19,8 @@ const YAxis = ({ return ( + {shouldShowTemperatureColumn && } + {symptomsToDisplay.map(symptom => ( - {shouldShowTemperatureColumn && } - ) } @@ -43,4 +43,10 @@ YAxis.propTypes = { xAxisHeight: PropTypes.number.isRequired } +const styles = StyleSheet.create({ + yAxis: { + width: CHART_YAXIS_WIDTH + } +}) + export default YAxis diff --git a/components/common/app-page.js b/components/common/app-page.js index a9559dc..87910dd 100644 --- a/components/common/app-page.js +++ b/components/common/app-page.js @@ -1,26 +1,36 @@ import React from 'react' import PropTypes from 'prop-types' -import { ScrollView, StyleSheet } from 'react-native' +import { ScrollView, StyleSheet, View } from 'react-native' import AppText from '../common/app-text' import { Colors, Typography } from '../../styles/redesign' -const AppPage = ({ children, contentContainerStyle, title }) => { +const AppPage = ({ + children, + contentContainerStyle, + scrollViewStyle, + title, + ...props +}) => { return( - - {title && {title}} - {children} - + + + {title && {title}} + {children} + + ) } AppPage.propTypes = { children: PropTypes.node, contentContainerStyle: PropTypes.object, + scrollViewStyle: PropTypes.object, title: PropTypes.string } @@ -29,6 +39,10 @@ const styles = StyleSheet.create({ backgroundColor: Colors.tourquiseLight, flex: 1 }, + scrollView: { + backgroundColor: Colors.tourquiseLight, + flexGrow: 1 + }, title: { ...Typography.title } diff --git a/components/cycle-day/symptoms/temperature-input.js b/components/cycle-day/symptoms/temperature-input.js index c333e77..fad6da7 100644 --- a/components/cycle-day/symptoms/temperature-input.js +++ b/components/cycle-day/symptoms/temperature-input.js @@ -11,7 +11,7 @@ import styles from '../../../styles' import { getPreviousTemperature } from '../../../db' import { scaleObservable } from '../../../local-storage' -import config from '../../../config' +import { TEMP_MAX, TEMP_MIN } from '../../../config' export default class TemperatureInput extends Component { @@ -86,8 +86,7 @@ const OutOfRangeWarning = ({ temperature }) => { } const value = Number(temperature) - const { min, max } = config.temperatureScale - const range = { min, max } + const range = { min: TEMP_MIN, max: TEMP_MAX } const scale = scaleObservable.value let warningMsg diff --git a/components/helpers/chart.js b/components/helpers/chart.js index dac2faf..245df1f 100644 --- a/components/helpers/chart.js +++ b/components/helpers/chart.js @@ -1,10 +1,9 @@ import { LocalDate } from 'js-joda' import { scaleObservable, unitObservable } from '../../local-storage' +import { getCycleStatusForDay } from '../../lib/sympto-adapter' import { getCycleDay, getAmountOfCycleDays } from '../../db' -import config from '../../config' - //YAxis helpers export function normalizeToScale(temp, columnHeight) { @@ -14,17 +13,21 @@ export function normalizeToScale(temp, columnHeight) { } function getAbsoluteValue(relative, columnHeight) { - // we add some height to have some breathing room - const verticalPadding = columnHeight * config.temperatureScale.verticalPadding - const scaleHeight = columnHeight - 2 * verticalPadding - return scaleHeight * relative + verticalPadding + return columnHeight * relative +} + +function getTickConfig() { + const unit = unitObservable.value + //Add 1 tick above the max value to display on chart + const scaleMax = scaleObservable.value.max + unit + const scaleMin = scaleObservable.value.min - unit + const numberOfTicks = (scaleMax - scaleMin) / unit + 1 + + return { numberOfTicks, scaleMax, scaleMin, unit } } export function getTickPositions(columnHeight) { - const units = unitObservable.value - const scaleMin = scaleObservable.value.min - const scaleMax = scaleObservable.value.max - const numberOfTicks = (scaleMax - scaleMin) * (1 / units) + 1 + const { numberOfTicks } = getTickConfig() const tickDistance = 1 / (numberOfTicks - 1) const tickPositions = [] for (let i = 0; i < numberOfTicks; i++) { @@ -35,13 +38,12 @@ export function getTickPositions(columnHeight) { } export function getTickList(columnHeight) { - - const units = unitObservable.value - const scaleMax = scaleObservable.value.max + const { numberOfTicks, scaleMax, unit } = getTickConfig() + const tickHeight = columnHeight / numberOfTicks return getTickPositions(columnHeight).map((tickPosition, i) => { - const tick = scaleMax - i * units + const tick = scaleMax - i * unit let isBold, label, shouldShowLabel if (Number.isInteger(tick)) { @@ -52,10 +54,10 @@ export function getTickList(columnHeight) { label = tick.toString() } - // when temp range <= 3, units === 0.1 we show temp values with step 0.2 - // when temp range > 3, units === 0.5 we show temp values with step 0.5 + // when temp range <= 2, units === 0.1 we show temp values with step 0.2 + // when temp range > 2, units === 0.5 we show temp values with step 0.5 - if (units === 0.1) { + if (unit === 0.1) { // show label with step 0.2 shouldShowLabel = !(tick * 10 % 2) } else { @@ -63,11 +65,17 @@ export function getTickList(columnHeight) { shouldShowLabel = !(tick * 10 % 5) } + // don't show label, if first or last tick + if ( i === 0 || i === (numberOfTicks - 1) ) { + shouldShowLabel = false + } + return { position: tickPosition, label, isBold, shouldShowLabel, + tickHeight } }) } @@ -201,4 +209,87 @@ function getTodayAndPreviousDays(n) { } return getDaysInRange(today, []) +} + +export function nfpLines() { + const cycle = { + status: null + } + + function updateCurrentCycle(dateString) { + // for the NFP lines, we don't care about potentially extending the + // preOvu phase, so we don't include all earlier cycles, as that is + // an expensive db operation at the moment + cycle.status = getCycleStatusForDay( + dateString, { excludeEarlierCycles: true } + ) + if(!cycle.status) { + cycle.noMoreCycles = true + return + } + if (cycle.status.phases.preOvulatory) { + cycle.startDate = cycle.status.phases.preOvulatory.start.date + } else { + cycle.startDate = cycle.status.phases.periOvulatory.start.date + } + } + + function dateIsInPeriOrPostPhase(dateString) { + return ( + dateString >= cycle.status.phases.periOvulatory.start.date + ) + } + + function precededByAnotherTempValue(dateString) { + return ( + // we are only interested in days that have a preceding + // temp + Object.keys(cycle.status.phases).some(phaseName => { + return cycle.status.phases[phaseName].cycleDays.some(day => { + return day.temperature && day.date < dateString + }) + }) + // and also a following temp, so we don't draw the line + // longer than necessary + && + cycle.status.phases.postOvulatory.cycleDays.some(day => { + return day.temperature && day.date > dateString + }) + ) + } + + function isInTempMeasuringPhase(temperature, dateString) { + return ( + temperature || precededByAnotherTempValue(dateString) + ) + } + + return function(dateString, temperature, columnHeight) { + const ret = { + drawLtlAt: null, + drawFhmLine: false + } + if (!cycle.status && !cycle.noMoreCycles) updateCurrentCycle(dateString) + if (cycle.noMoreCycles) return ret + + if (dateString < cycle.startDate) updateCurrentCycle(dateString) + if (cycle.noMoreCycles) return ret + + const tempShift = cycle.status.temperatureShift + + if (tempShift) { + if (tempShift.firstHighMeasurementDay.date === dateString) { + ret.drawFhmLine = true + } + + if ( + dateIsInPeriOrPostPhase(dateString) && + isInTempMeasuringPhase(temperature, dateString) + ) { + ret.drawLtlAt = normalizeToScale(tempShift.ltl, columnHeight) + } + } + + return ret + } } \ No newline at end of file diff --git a/components/settings/nfp-settings/temperature-slider.js b/components/settings/nfp-settings/temperature-slider.js index 94db021..14adf12 100644 --- a/components/settings/nfp-settings/temperature-slider.js +++ b/components/settings/nfp-settings/temperature-slider.js @@ -8,7 +8,7 @@ import SliderLabel from './slider-label' import { scaleObservable, saveTempScale } from '../../../local-storage' import { Colors, Sizes } from '../../../styles/redesign' import labels from '../../../i18n/en/settings' -import config from '../../../config' +import { TEMP_MIN, TEMP_MAX, TEMP_SLIDER_STEP } from '../../../config' export default class TemperatureSlider extends Component { constructor(props) { @@ -41,11 +41,11 @@ export default class TemperatureSlider extends Component { enableLabel={true} markerStyle={styles.marker} markerOffsetY={Sizes.tiny} - max={config.temperatureScale.max} - min={config.temperatureScale.min} + max={TEMP_MAX} + min={TEMP_MIN} onValuesChange={this.onTemperatureSliderChange} selectedStyle={styles.sliderAccentBackground} - step={config.temperatureScale.step} + step={TEMP_SLIDER_STEP} trackStyle={styles.slider} unselectedStyle={styles.sliderBackground} values={[minTemperature, maxTemperature]} diff --git a/config.js b/config.js index 1fd1589..4f11d22 100644 --- a/config.js +++ b/config.js @@ -1,34 +1,31 @@ -const config = { - columnWidth: 25, - xAxisHeightPercentage: 0.08, - xAxisHeightPercentageLarge: 0.12, - symptomHeightPercentage: 0.05, - symptomHeightPercentageLarge: 0.1, - temperatureScale: { - defaultLow: 35, - defaultHigh: 38, - min: 34, - max: 40, - step: 0.5, - units: 0.1, - verticalPadding: 0.03 - }, - symptoms: [ - 'bleeding', - 'mucus', - 'cervix', - 'sex', - 'desire', - 'pain', - 'mood', - 'note' - ], -} - -config.columnMiddle = config.columnWidth / 2 - export const ACTION_DELETE = 'delete' export const ACTION_EXPORT = 'export' export const ACTION_IMPORT = 'import' -export default config \ No newline at end of file +export const SYMPTOMS = [ + 'bleeding', + 'mucus', + 'cervix', + 'sex', + 'desire', + 'pain', + 'mood', + 'note' +] + +export const CHART_COLUMN_WIDTH = 32 +export const CHART_COLUMN_MIDDLE = CHART_COLUMN_WIDTH / 2 +export const CHART_DOT_RADIUS = 6 +export const CHART_GRID_LINE_HORIZONTAL_WIDTH = 0.3 +export const CHART_ICON_SIZE = 20 +export const CHART_STROKE_WIDTH = 3 +export const CHART_SYMPTOM_HEIGHT_RATIO = 0.1 +export const CHART_XAXIS_HEIGHT_RATIO = 0.14 +export const CHART_YAXIS_WIDTH = 32 + +export const TEMP_SCALE_MAX = 38 +export const TEMP_SCALE_MIN = 35 +export const TEMP_SCALE_UNITS = 0.1 +export const TEMP_MAX = 40 +export const TEMP_MIN = 34 +export const TEMP_SLIDER_STEP = 0.5 diff --git a/i18n/en/labels.js b/i18n/en/labels.js index 3b5e8df..5f6adf5 100644 --- a/i18n/en/labels.js +++ b/i18n/en/labels.js @@ -7,6 +7,10 @@ export const homeRedesign = { addData: 'add data for today' } +export const chart = { + tutorial: 'You can swipe the chart to view more dates.' +} + export const shared = { cancel: 'Cancel', save: 'Save', diff --git a/local-storage.js b/local-storage.js index 4cc9c75..b23ac6f 100644 --- a/local-storage.js +++ b/local-storage.js @@ -1,18 +1,16 @@ import { AsyncStorage } from 'react-native' import Observable from 'obv' -import config from './config' +import { TEMP_SCALE_MIN, TEMP_SCALE_MAX, TEMP_SCALE_UNITS } from './config' export const scaleObservable = Observable() -setObvWithInitValue('tempScale', scaleObservable, { - min: config.temperatureScale.defaultLow, - max: config.temperatureScale.defaultHigh -}) +setObvWithInitValue('tempScale', + scaleObservable, { min: TEMP_SCALE_MIN, max: TEMP_SCALE_MAX }) export const unitObservable = Observable() -unitObservable.set(config.temperatureScale.units) +unitObservable.set(TEMP_SCALE_UNITS) scaleObservable((scale) => { const scaleRange = scale.max - scale.min - if (scaleRange <= 3) { + if (scaleRange <= 2) { unitObservable.set(0.1) } else { unitObservable.set(0.5) @@ -69,6 +67,15 @@ export async function saveLicenseFlag() { await AsyncStorage.setItem('agreedToLicense', JSON.stringify(true)) } +export async function getChartFlag() { + const isFirstChartView = await AsyncStorage.getItem('isFirstChartView') + return isFirstChartView === null ? 'true' : isFirstChartView +} + +export async function setChartFlag() { + await AsyncStorage.setItem('isFirstChartView', JSON.stringify(false)) +} + async function setObvWithInitValue(key, obv, defaultValue) { const result = await AsyncStorage.getItem(key) let value diff --git a/styles/colors.js b/styles/colors.js index 3c797d5..87ffc8a 100644 --- a/styles/colors.js +++ b/styles/colors.js @@ -1,3 +1,17 @@ +const redColor = '#c3000d' +export const shadesOfRed = ['#e7999e', '#db666d', '#cf323d', '#c3000d'] // light to dark +const violetColor = '#6a7b98' +const shadesOfViolet = ['#e3e7ed', '#c8cfdc', '#acb8cb', '#91a0ba', '#7689a9', violetColor] // light to dark +const yellowColor = '#dbb40c' +const shadesOfYellow = ['#f0e19d', '#e9d26d', '#e2c33c', yellowColor] // light to dark +const magentaColor = '#6f2565' +const shadesOfMagenta = ['#a87ca2', '#8b5083', magentaColor] // light to dark +const pinkColor = '#9e346c' +const shadesOfPink = ['#c485a6', '#b15c89', pinkColor] // light to dark +const lightGreenColor = '#bccd67' +const orangeColor = '#bc6642' +const mintColor = '#6ca299' + export default { greyDark: '#A5A5A5', grey: '#D2D2D2', @@ -8,4 +22,38 @@ export default { tourquiseDark: '#69CBC1', tourquise: '#CFECEA', tourquiseLight: '#E9F2ED', + iconColors: { + 'bleeding': { + color: redColor, + shades: shadesOfRed, + }, + 'mucus': { + color: violetColor, + shades: shadesOfViolet, + }, + 'cervix': { + color: yellowColor, + shades: shadesOfYellow, + }, + 'sex': { + color: magentaColor, + shades: shadesOfMagenta, + }, + 'desire': { + color: pinkColor, + shades: shadesOfPink, + }, + 'pain': { + color: lightGreenColor, + shades: [lightGreenColor], + }, + 'mood': { + color: orangeColor, + shades: [orangeColor], + }, + 'note': { + color: mintColor, + shades: [mintColor], + }, + }, } \ No newline at end of file diff --git a/styles/typography.js b/styles/typography.js index 4034f12..153f1fa 100644 --- a/styles/typography.js +++ b/styles/typography.js @@ -8,6 +8,7 @@ export const fonts = { export const sizes = { tiny: 7, + footnote: 10, small: 14, base: 18, subtitle: 22, @@ -15,11 +16,6 @@ export const sizes = { huge: 40 } -const title = { - color: Colors.purple, - marginVertical: Spacing.large -} - const accentText = { fontFamily: fonts.bold, textAlignVertical: 'center', @@ -46,6 +42,16 @@ const accentTextSmall = { fontSize: sizes.small } +const title = { + color: Colors.purple, + marginVertical: Spacing.large +} + +const label = { + fontSize: sizes.small, + textTransform: 'uppercase' +} + export default { accentOrange: { ...accentTextSmall, @@ -67,6 +73,18 @@ export default { fontFamily: fonts.main, fontSize: sizes.base }, + label: { + ...label + }, + labelBold: { + color: Colors.greyDark, + fontWeight: 'bold', + ...label + }, + labelLight: { + color: Colors.grey, + fontSize: sizes.footnote, + }, subtitle: { fontSize: sizes.subtitle, ...title