+
Rain: ${rain.value} ${units === 'us' ? 'in' : 'mm'}
`;
@@ -50,12 +52,16 @@ export const chartConfig: any = (units: string, timezone: Timezone, hourly: any)
legend: {
data: ['Temperature', 'Rain'],
right: '10%',
+ textStyle: {
+ fontSize,
+ },
},
xAxis: {
type: 'category',
data: map(hourly.data, 'time').slice(0, 23),
axisLabel: {
formatter: formatterXAxisLabel,
+ fontSize,
},
},
yAxis: [
@@ -64,6 +70,7 @@ export const chartConfig: any = (units: string, timezone: Timezone, hourly: any)
max: temperatureMax,
axisLabel: {
formatter: units === 'us' ? '{value} ℉' : '{value} ℃',
+ fontSize,
},
splitLine: {
show: false,
@@ -81,6 +88,7 @@ export const chartConfig: any = (units: string, timezone: Timezone, hourly: any)
max: rainMax,
axisLabel: {
formatter: units === 'us' ? '{value} in' : '{value} mm',
+ fontSize,
},
},
],
diff --git a/src/components/current-weather.tsx b/src/components/current-weather.tsx
index a41ad53..3b7a231 100644
--- a/src/components/current-weather.tsx
+++ b/src/components/current-weather.tsx
@@ -2,6 +2,7 @@ import Col from 'antd/lib/col';
import Row from 'antd/lib/row';
import * as React from 'react';
import { connect } from 'react-redux';
+
import { Utils } from '../utils';
import { WeatherIcon } from './icon/weather-icon';
import { WindIcon } from './icon/wind-icon';
@@ -13,42 +14,49 @@ export class CurrentWeather extends React.Component
{
return (
-
-
+
+
Rain: {Utils.getRain(weather.precipIntensity, weather.precipProbability, filter.units)}
-
-
+
-
- Wind: {Utils.getWindSpeed(weather.windSpeed, filter.units)}
+
+
+ Wind: {Utils.getWindSpeed(weather.windSpeed, filter.units)}
+
-
-
+
+
Humidity: {Math.round(weather.humidity * 100)}
-
+
-
- Pressure: {Utils.getPressure(weather.pressure, filter.units)}
+
+
+ Pressure: {Utils.getPressure(weather.pressure, filter.units)}
+
-
- Dew Point: {Utils.getTemperature(weather.dewPoint, filter.units)}
+
+
+ Dew Point: {Utils.getTemperature(weather.dewPoint, filter.units)}
+
-
- UV Index: {weather.uvIndex}
+
+ UV Index: {weather.uvIndex}
-
- Visibility: {Utils.getDistance(weather.visibility, filter.units)}
+
+
+ Visibility: {Utils.getDistance(weather.visibility, filter.units)}
+
{location}
-
+
-
-
+
+
{Utils.getLocalTime(weather.time, timezone.offset, 'YYYY-MM-DD HH:mm')}
{weather.summary} {Utils.getTemperature(weather.temperature, filter.units)}
@@ -64,13 +72,13 @@ export class CurrentWeather extends React.Component
{
const mapStateToProps = (state: any) => {
return {
- filter: state.filter,
- location: state.location,
- weather: state.weather,
- forecast: state.forecast,
- timezone: state.timezone,
- isLoading: state.isLoading,
- error: state.error,
+ filter: state.weather.filter,
+ location: state.weather.location,
+ weather: state.weather.weather,
+ forecast: state.weather.forecast,
+ timezone: state.weather.timezone,
+ isLoading: state.weather.isLoading,
+ error: state.weather.error,
};
};
diff --git a/src/components/d3-demo/d3-force.css b/src/components/d3-demo/d3-force.css
deleted file mode 100644
index 727fe6d..0000000
--- a/src/components/d3-demo/d3-force.css
+++ /dev/null
@@ -1,89 +0,0 @@
-.content {
- padding-top: 1rem;
-}
-
-.nav-link {
- padding-left: 2rem;
- padding-top: 2rem;
-}
-
-.link {
- stroke: #555;
-}
-
-.node text {
- fill: #000;
- cursor: pointer;
- font-size: 0.8rem;
-}
-
-text {
- fill: #000;
- cursor: pointer;
- font-size: 0.7rem;
-}
-
-text.axis-t {
- fill: #7dc7f4;
-}
-
-text.axis-p {
- fill: #A4A4A4;
-}
-
-text.legendHeading, .responseHeading {
- font-size: 1.1rem;
-}
-
-rect.responseTimesChart, tspan.averageLabel {
- fill: #d75107;
-}
-
-rect.responseTimesChartMax, tspan.maxLabel {
- fill: rgba(215, 81, 7, 0.38);
-}
-
-text.legendRequestId, text.responseTimesText tspan {
- font-size: 0.7rem;
-}
-
-.node circle, .nodeLegend circle {
- stroke-width: 0.25rem;
- fill: #fff;
- stroke: #d16107
-}
-
-.node circle.DEBUG, .nodeLegend circle.DEBUG {
- stroke: #62679a
-}
-
-.node circle.INFO, .nodeLegend circle.INFO {
- stroke: #008376;
-}
-
-.node circle.WARN, .nodeLegend circle.WARN {
- stroke: #d1b948;
-}
-
-.node circle.ERROR, .nodeLegend circle.ERROR {
- stroke: #c10901;
-}
-
-circle.az-center {
- opacity: .0;
-}
-
-circle.az {
- stroke-width: 0.4rem;
- opacity: .2;
- fill: #666;
- stroke: #666
-}
-
-.link.light {
- opacity: .0;
-}
-
-text.label.az {
- font-size: 1.1rem;
-}
diff --git a/src/components/daily-forecast.tsx b/src/components/daily-forecast.tsx
index 718d09c..1c55043 100644
--- a/src/components/daily-forecast.tsx
+++ b/src/components/daily-forecast.tsx
@@ -2,37 +2,42 @@ import { Table } from 'antd';
import Col from 'antd/lib/col';
import Row from 'antd/lib/row';
import Column from 'antd/lib/table/Column';
-import ColumnGroup from 'antd/lib/table/ColumnGroup';
import * as React from 'react';
import { connect } from 'react-redux';
import { Utils } from '../utils';
-import { Weather } from './data-model';
import { MoonIcon } from './icon/moon-icon';
import { WeatherIcon } from './icon/weather-icon';
export class DailyForecast extends React.Component {
render() {
const { timezone, dailyForecast, filter } = this.props;
+ const isMobile = Utils.isMobile();
+ const scroll = isMobile ? { x: '130%', y: '100%' } : {};
const renderDailyForecastTable = () => (
-
+ data.time} scroll={scroll}>
(
-
+
-
+
)}
/>
(
- {index === 0 ? 'Today' : Utils.getLocalTime(time, timezone.offset, 'ddd')}
+
+ {index === 0 ? 'Today' : Utils.getLocalTime(time, timezone.offset, 'ddd')}
+
)}
/>
{
dataIndex='sunriseTime'
key='sunriseTime'
align='center'
+ width='9rem'
render={sunriseTime => (
-
+
-
@{Utils.getLocalTime(sunriseTime, timezone.offset, 'HH:mm')}
-
+
@{Utils.getLocalTime(sunriseTime, timezone.offset, 'HH:mm')}
+
)}
/>
{
dataIndex='sunsetTime'
key='sunsetTime'
align='center'
+ width='9rem'
render={sunsetTime => (
-
+
-
@{Utils.getLocalTime(sunsetTime, timezone.offset, 'HH:mm')}
-
+
@{Utils.getLocalTime(sunsetTime, timezone.offset, 'HH:mm')}
+
)}
/>
{
dataIndex='moonPhase'
key='moonPhase'
align='center'
- render={moonPhase => (
-
-
-
- )}
+ width='5.5rem'
+ render={moonPhase => }
/>
(
-
+
{Utils.getTemperature(data.temperatureLow, filter.units)}
-
- @{Utils.getLocalTime(data.temperatureLowTime, timezone.offset, 'ha')}
-
-
+
@{Utils.getLocalTime(data.temperatureLowTime, timezone.offset, 'ha')}
+
)}
/>
(
-
+
{Utils.getTemperature(data.temperatureHigh, filter.units)}
-
- @{Utils.getLocalTime(data.temperatureHighTime, timezone.offset, 'ha')}
-
-
+
@{Utils.getLocalTime(data.temperatureHighTime, timezone.offset, 'ha')}
+
)}
/>
(
-
- {Utils.getRain(data.precipIntensity, data.precipProbability, filter.units)}{' '}
-
-
+
+ {Utils.getRain(data.precipIntensity, data.precipProbability, filter.units)}
+
)}
/>
{
dataIndex='humidity'
key='humidity'
align='center'
+ width='9rem'
render={humidity => (
-
+
{Math.round(humidity * 100)}
-
+
)}
/>
@@ -124,13 +127,13 @@ export class DailyForecast extends React.Component {
return (
- 7 days forecast
+ {dailyForecast.data.length} days forecast
{dailyForecast.summary}
-
+
{renderDailyForecastTable()}
@@ -141,9 +144,9 @@ export class DailyForecast extends React.Component
{
const mapStateToProps = (state: any) => {
return {
- filter: state.filter,
- timezone: state.timezone,
- dailyForecast: state.dailyForecast,
+ filter: state.weather.filter,
+ timezone: state.weather.timezone,
+ dailyForecast: state.weather.dailyForecast,
};
};
diff --git a/src/components/hourly-forecast.tsx b/src/components/hourly-forecast.tsx
index 7a600f5..346f340 100644
--- a/src/components/hourly-forecast.tsx
+++ b/src/components/hourly-forecast.tsx
@@ -53,11 +53,11 @@ export class HourlyForecast extends React.Component {
const mapStateToProps = (state: any) => {
return {
- isLoading: state.isLoading,
- filter: state.filter,
- timezone: state.timezone,
- weather: state.weather,
- hourlyForecast: state.hourlyForecast,
+ isLoading: state.weather.isLoading,
+ filter: state.weather.filter,
+ timezone: state.weather.timezone,
+ weather: state.weather.weather,
+ hourlyForecast: state.weather.hourlyForecast,
};
};
diff --git a/src/components/nav-bar.tsx b/src/components/nav-bar.tsx
index aafd001..b38dc7a 100644
--- a/src/components/nav-bar.tsx
+++ b/src/components/nav-bar.tsx
@@ -1,16 +1,23 @@
import Button from 'antd/lib/button';
import Col from 'antd/lib/col';
import DatePicker from 'antd/lib/date-picker';
+import Icon from 'antd/lib/icon';
import Layout from 'antd/lib/layout';
import Menu from 'antd/lib/menu';
+import Popover from 'antd/lib/popover';
import Row from 'antd/lib/row';
import Select from 'antd/lib/select';
+
+import { push } from 'connected-react-router';
import * as moment from 'moment';
import * as React from 'react';
import { connect } from 'react-redux';
-import { NavLink } from 'react-router-dom';
+import { Link } from 'react-router-dom';
import { bindActionCreators } from 'redux';
-import { fetchingData, setFilter } from '../redux/actions';
+
+import store from '../store';
+import { setFilter } from '../store/actions';
+import { Utils } from '../utils';
import { WeatherSearch } from './weather-search';
const Option = Select.Option;
@@ -50,53 +57,93 @@ class NavBar extends React.Component {
};
render() {
- return (
+ let path = this.props.path.substring(1) === '' ? 'weather' : this.props.path.substring(1);
+
+ const weatherLink = (
+ {
+ store.dispatch(push('/'));
+ }}>
+ Weather
+
+ );
+
+ const aboutLink = (
+ {
+ store.dispatch(push('/about'));
+ }}>
+ About
+
+ );
+
+ const weatherMapLink = (
+ {
+ store.dispatch(push('/map'));
+ }}>
+ Map
+
+ );
+
+ const datePicker = (
+
+ );
+
+ const search = (
+
+ );
+
+ const units = (
+
+ ℃, kph
+ ℉, mph
+
+ );
+
+ const navBar = (
-
+
-
-
-
-
- Weather
-
-
-
-
- About
-
-
-
-
- D3 Demo
-
+
+
+ {weatherLink}
+ {weatherMapLink}
+ {aboutLink}
+ {
+ store.dispatch(push('/d3_demo_app'));
+ }}>
+ D3 Demo
-
+ {datePicker}
-
-
-
+ {search}
-
-
- ℃, kph
- ℉, mph
-
+
+ {units}
{
);
+
+ const content = (
+
+ {weatherLink}
+ {aboutLink}
+ {weatherMapLink}
+ {datePicker}
+ {search}
+ {units}
+
+ );
+
+ const navBarMobile = (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ return {Utils.isMobile() ? navBarMobile : navBar}
;
}
}
const mapStateToProps = (state: any) => {
return {
- isLoading: state.isLoading,
- filter: state.filter,
+ isLoading: state.weather.isLoading,
+ filter: state.weather.filter,
+ path: state.router.location.pathname,
};
};
@@ -124,7 +199,6 @@ const mapDispatchToProps = (dispatch: any) => {
return bindActionCreators(
{
setFilter,
- fetchingData,
},
dispatch
);
diff --git a/src/components/weather-search.tsx b/src/components/weather-search.tsx
index 71083a4..42679b8 100644
--- a/src/components/weather-search.tsx
+++ b/src/components/weather-search.tsx
@@ -37,7 +37,7 @@ export class WeatherSearch extends React.Component
);
}
diff --git a/src/constants/message.ts b/src/constants/message.ts
new file mode 100644
index 0000000..45ad2f2
--- /dev/null
+++ b/src/constants/message.ts
@@ -0,0 +1 @@
+export const USE_DEFAULT_LOCATION = 'Use default location: Auckland, New Zealand';
diff --git a/src/css/index.css b/src/css/index.css
index 579b89f..aab4caf 100644
--- a/src/css/index.css
+++ b/src/css/index.css
@@ -1,98 +1,193 @@
-@import url('https://fonts.googleapis.com/css?family=Roboto');
+@import url('https://fonts.googleapis.com/css?family=Roboto:400,500,700');
body {
- font-size: 1rem;
- font-family: 'Roboto', sans-serif;
+ font-size: 1rem;
+ font-family: 'Roboto', sans-serif;
+ height: 100%;
}
.content {
- min-height: 40rem;
- padding: 4rem 0 0 0;
+ min-height: 100%;
+ width: 100%;
}
.footer {
- text-align: center;
- background: #FFF;
+ text-align: center;
+ background: #fff;
+ font-size: 1rem;
}
.about-content {
- padding-top: 2rem;
+ padding-top: 2rem;
}
+/* Navigation bar for desktop version */
.nav-bar {
- padding: 0 1rem;
- position: fixed;
- z-index: 1;
- width: 100%;
+ padding: 0 1rem;
+ z-index: 1;
+ width: 100%;
}
.nav-bar-menu {
- line-height: 4rem;
+ line-height: 4rem;
}
.nav-bar-icon {
- text-align: right;
+ text-align: right;
+}
+
+.weather-search-outer {
+ padding: 0 0.5rem;
+}
+/* Navigation bar for desktop version */
+
+/* Navigation bar for mobile device */
+.nav-bar-mobile {
+ padding: 0 1.5rem;
}
+.nav-bar-mobile-menu-icon {
+ color: white;
+}
+
+.ant-popover-inner-content {
+ padding: 0;
+}
+/* Navigation bar for mobile device */
+
.error {
- padding: 2rem 2rem;
+ padding: 2rem 2rem;
}
.fetching-weather-content {
- padding: 4rem 2rem;
+ padding: 4rem 2rem;
}
.fetching-weather-spinner {
- padding-left: 0.5rem;
+ padding-left: 0.5rem;
}
+/* Current weather section */
.current-weather-top {
- background: #FAFAFA;
- font-size: 0.8rem;
- padding: 0.5rem 2rem;
+ background: #fafafa;
+ padding: 0.5rem 2rem;
+}
+
+.current-weather-top-item {
+ text-align: center;
+ font-size: 0.8rem;
}
.current-weather-location {
- padding: 1rem 2rem 0.5rem 1rem;
- font-size: 2rem;
- font-weight: bolder;
+ padding: 0.5rem 1rem;
+ font-size: 2rem;
+ font-weight: 700;
+}
+
+.current-weather-summary {
+ padding-top: 1rem;
+ font-size: 1rem;
+}
+
+.current-weather-icon {
+ margin-right: 1rem;
}
+/* Current weather section */
.forecast-summary {
- padding: 1rem 2rem 0.5rem 1rem;
- font-size: 1.2rem;
- font-weight: 700;
+ padding: 0.5rem 1rem;
+ font-size: 1.2rem;
+ font-weight: 700;
}
.forecast-title {
- font-size: 1.8rem;
- font-weight: 500;
+ font-size: 1.8rem;
+ font-weight: 500;
}
.daily-forecast-table-outer {
- padding: 1rem 0;
+ padding: 1rem 0;
}
.daily-forecast-item {
- font-size: 0.8rem;
+ font-size: 0.8rem;
}
+/* Weather chart section */
#weather-chart-wrapper {
- padding: 0 2rem
+ padding: 0 2rem;
}
.weather-chart {
- height: 20rem;
- width: 50rem;
+ height: 20rem;
+ width: 50rem;
+}
+
+.weather-chart-tooltip-time {
+ font-size: 0.9rem;
+ color: #949494;
+ line-height: 1.1rem;
+}
+
+.weather-chart-tooltip-item {
+ color: #2e2e2e;
+ font-size: 0.8rem;
+ font-weight: 500;
+ line-height: 0.5rem;
+}
+/* Weather chart section */
+
+#windy {
+ width: 100%;
+ min-height: 100%;
+ height: 85vh;
}
::-webkit-scrollbar {
- height: 0.8rem;
- width: 0.8rem;
- background-color: #FAFAFA;
+ height: 0.8rem;
+ width: 0.8rem;
+ background-color: #fafafa;
}
::-webkit-scrollbar-thumb {
- border-radius: 1rem;
- background-color: #A4A4A4;
+ border-radius: 1rem;
+ background-color: #a4a4a4;
+}
+
+@media screen and (min-width: 993px) and (max-width: 1200px) {
+}
+
+@media screen and (min-width: 769px) and (max-width: 992px) {
+}
+
+@media screen and (min-device-width: 577px) and (max-device-width: 768px) {
+}
+
+@media screen and (min-device-width: 320px) and (max-device-width: 576px) {
+ .current-weather-top {
+ background: #fafafa;
+ padding: 0.5rem 1rem;
+ }
+
+ .current-weather-top-item {
+ text-align: center;
+ font-size: 0.8rem;
+ }
+
+ .current-weather-location {
+ padding: 0.5rem 1rem;
+ font-size: 1.4rem;
+ font-weight: 700;
+ }
+
+ .forecast-title {
+ font-size: 1.4rem;
+ font-weight: 500;
+ }
+
+ .forecast-summary {
+ padding: 0.5rem 1rem;
+ font-size: 1rem;
+ font-weight: 700;
+ }
}
diff --git a/src/components/d3-demo/d3-demo-app.tsx b/src/d3-demo/d3-demo-app.tsx
similarity index 98%
rename from src/components/d3-demo/d3-demo-app.tsx
rename to src/d3-demo/d3-demo-app.tsx
index b148f66..cda9571 100644
--- a/src/components/d3-demo/d3-demo-app.tsx
+++ b/src/d3-demo/d3-demo-app.tsx
@@ -4,7 +4,7 @@ import { forceCenter, forceLink, forceManyBody, forceSimulation, forceX, forceY
import { select } from 'd3-selection';
import * as React from 'react';
import { Link } from 'react-router-dom';
-import appTraffic from '../../../sample/app-traffic.json';
+import appTraffic from '../../sample/app-traffic.json';
import './d3-force.css';
import Gauge from './gauge';
import { TrafficService } from './traffic';
@@ -255,7 +255,7 @@ export class D3DemoApp extends React.Component {
));
return (
-
+
Application Traffic
|
Network Traffic
diff --git a/src/components/d3-demo/d3-demo-network.tsx b/src/d3-demo/d3-demo-network.tsx
similarity index 98%
rename from src/components/d3-demo/d3-demo-network.tsx
rename to src/d3-demo/d3-demo-network.tsx
index e469a15..7c74a39 100644
--- a/src/components/d3-demo/d3-demo-network.tsx
+++ b/src/d3-demo/d3-demo-network.tsx
@@ -6,7 +6,7 @@ import { select } from 'd3-selection';
import { find } from 'lodash';
import * as React from 'react';
import { Link } from 'react-router-dom';
-import networkTraffic from '../../../sample/network-traffic.json';
+import networkTraffic from '../../sample/network-traffic.json';
import './d3-force.css';
import Gauge from './gauge';
import { ToolTip } from './tool-tip';
@@ -347,7 +347,7 @@ export class D3DemoNetwork extends React.Component
{
render() {
return (
-
+
Application Traffic
diff --git a/src/d3-demo/d3-force.css b/src/d3-demo/d3-force.css
new file mode 100644
index 0000000..bc5571c
--- /dev/null
+++ b/src/d3-demo/d3-force.css
@@ -0,0 +1,97 @@
+.d3-force-content {
+ padding-top: 1rem;
+}
+.nav-link {
+ padding-left: 2rem;
+ padding-top: 2rem;
+}
+
+.link {
+ stroke: #555;
+}
+
+.node text {
+ fill: #000;
+ cursor: pointer;
+ font-size: 0.8rem;
+}
+
+text {
+ fill: #000;
+ cursor: pointer;
+ font-size: 0.7rem;
+}
+
+text.axis-t {
+ fill: #7dc7f4;
+}
+
+text.axis-p {
+ fill: #a4a4a4;
+}
+
+text.legendHeading,
+.responseHeading {
+ font-size: 1.1rem;
+}
+
+rect.responseTimesChart,
+tspan.averageLabel {
+ fill: #d75107;
+}
+
+rect.responseTimesChartMax,
+tspan.maxLabel {
+ fill: rgba(215, 81, 7, 0.38);
+}
+
+text.legendRequestId,
+text.responseTimesText tspan {
+ font-size: 0.7rem;
+}
+
+.node circle,
+.nodeLegend circle {
+ stroke-width: 0.25rem;
+ fill: #fff;
+ stroke: #d16107;
+}
+
+.node circle.DEBUG,
+.nodeLegend circle.DEBUG {
+ stroke: #62679a;
+}
+
+.node circle.INFO,
+.nodeLegend circle.INFO {
+ stroke: #008376;
+}
+
+.node circle.WARN,
+.nodeLegend circle.WARN {
+ stroke: #d1b948;
+}
+
+.node circle.ERROR,
+.nodeLegend circle.ERROR {
+ stroke: #c10901;
+}
+
+circle.az-center {
+ opacity: 0;
+}
+
+circle.az {
+ stroke-width: 0.4rem;
+ opacity: 0.2;
+ fill: #666;
+ stroke: #666;
+}
+
+.link.light {
+ opacity: 0;
+}
+
+text.label.az {
+ font-size: 1.1rem;
+}
diff --git a/src/components/d3-demo/gauge.ts b/src/d3-demo/gauge.ts
similarity index 100%
rename from src/components/d3-demo/gauge.ts
rename to src/d3-demo/gauge.ts
diff --git a/src/components/d3-demo/tool-tip.tsx b/src/d3-demo/tool-tip.tsx
similarity index 100%
rename from src/components/d3-demo/tool-tip.tsx
rename to src/d3-demo/tool-tip.tsx
diff --git a/src/components/d3-demo/traffic.ts b/src/d3-demo/traffic.ts
similarity index 100%
rename from src/components/d3-demo/traffic.ts
rename to src/d3-demo/traffic.ts
diff --git a/src/index.html b/src/index.html
index 3d136e6..b40f846 100644
--- a/src/index.html
+++ b/src/index.html
@@ -2,10 +2,12 @@
React Weather App
-
+
+
+