diff --git a/src/components/TopbarDesktop/TopbarDesktop.css b/src/components/TopbarDesktop/TopbarDesktop.css
new file mode 100644
index 00000000..9a57b172
--- /dev/null
+++ b/src/components/TopbarDesktop/TopbarDesktop.css
@@ -0,0 +1,131 @@
+@import '../../marketplace.css';
+
+/* Desktop */
+.root {
+ display: none;
+
+ @media (min-width: 768px) {
+ /* Size */
+ width: 100%;
+ height: 72px;
+
+ /* Layout for child components */
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: baseline;
+ padding: 0 36px;
+
+ /* fill */
+ background-color: var(--matterColorLight);
+
+ /* shadows */
+ box-shadow: var(--boxShadowLight);
+ }
+}
+
+/* Compose text label items on top of this */
+/* This stretches inline element (link) to take available vertical space (big hover area),
+ * and align baselines, and passes text-decoration hover effect
+ */
+.topbarDesktopLabel {
+ display: inline-block;
+ margin: 24px 0 16px 0;
+ text-decoration: inherit;
+}
+
+/* logo */
+.logoLink {
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ height: 100%;
+ margin-right: 24px;
+}
+
+.logo {
+ width: 155px;
+ height: 27px;
+}
+
+/* Search */
+/* TODO This is placeholder, it needs Search component */
+.searchLink {
+ min-width: 220px;
+ align-self: flex-start;
+ height: 100%;
+ margin-right: 24px;
+}
+
+.search {
+ composes: topbarDesktopLabel;
+ composes: bodyFont from '../../marketplace.css';
+ color: var(--matterColor);
+}
+
+/* Spacer */
+/* Extra space is gathered between search and createListingLink */
+.spacer {
+ flex-grow: 1;
+}
+
+/* Create listing (CTA for providers) */
+.createListingLink {
+ align-self: flex-start;
+ height: 100%;
+ margin-right: 24px;
+}
+
+.createListing {
+ composes: topbarDesktopLabel;
+ composes: bodyFont from '../../marketplace.css';
+ color: var(--marketplaceColor);
+}
+
+/* Inbox */
+.inboxLink {
+ align-self: flex-start;
+ height: 100%;
+ margin-right: 24px;
+}
+
+.inbox {
+ composes: topbarDesktopLabel;
+ composes: bodyFont from '../../marketplace.css';
+ color: var(--matterColor);
+}
+
+/* Profile menu */
+/* TODO This is placeholder, it needs Menu component */
+.avatarLink {
+ align-self: flex-start;
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ height: 100%;
+ cursor: pointer;
+}
+
+.avatar {
+ width: 41px;
+ height: 41px;
+}
+
+/* Authentication */
+.signupLink {
+ align-self: flex-start;
+ height: 100%;
+ margin-right: 24px;
+}
+
+.loginLink {
+ align-self: flex-start;
+ height: 100%;
+}
+
+.signup,
+.login {
+ composes: topbarDesktopLabel;
+ composes: bodyFont from '../../marketplace.css';
+ color: var(--matterColor);
+}
diff --git a/src/components/TopbarDesktop/TopbarDesktop.example.js b/src/components/TopbarDesktop/TopbarDesktop.example.js
new file mode 100644
index 00000000..dc50f621
--- /dev/null
+++ b/src/components/TopbarDesktop/TopbarDesktop.example.js
@@ -0,0 +1,14 @@
+import { fakeIntl } from '../../util/test-data';
+import TopbarDesktop from './TopbarDesktop';
+
+
+export const AuthenticatedDesktopTopbar = {
+ component: TopbarDesktop,
+ props: {
+ isAuthenticated: true,
+ currentUserHasListings: true,
+ name: 'John Doe',
+ intl: fakeIntl,
+ },
+ group: 'navigation',
+};
diff --git a/src/components/TopbarDesktop/TopbarDesktop.js b/src/components/TopbarDesktop/TopbarDesktop.js
new file mode 100644
index 00000000..727098c9
--- /dev/null
+++ b/src/components/TopbarDesktop/TopbarDesktop.js
@@ -0,0 +1,82 @@
+import React, { PropTypes } from 'react';
+import { FormattedMessage, intlShape, injectIntl } from 'react-intl';
+import classNames from 'classnames';
+import { Avatar, NamedLink } from '../../components';
+
+import logo from './images/saunatime-logo.png';
+import css from './TopbarDesktop.css';
+
+const TopbarDesktop = props => {
+ const { className, rootClassName, currentUserHasListings, intl, isAuthenticated, name } = props;
+
+ const rootClass = rootClassName || css.root;
+ const classes = classNames(rootClass, className);
+
+ // TODO This is just a placeholder
+ const search = (
+
+ Search should be here
+
+ );
+
+ const inboxLink = isAuthenticated
+ ?
+
+
+ : null;
+
+ // TODO This is just a placeholder
+ const profileMenu = isAuthenticated
+ ?
+ : null;
+
+ const signupLink = isAuthenticated
+ ? null
+ :
+
+ ;
+
+ const loginLink = isAuthenticated
+ ? null
+ :
+
+ ;
+
+ return (
+
+
+
+
+ {search}
+
+
+
+
+ {inboxLink}
+ {profileMenu}
+ {signupLink}
+ {loginLink}
+
+ );
+};
+
+TopbarDesktop.defaultProps = { name: '', className: null, rootClassName: '' };
+
+const { bool, string } = PropTypes;
+
+TopbarDesktop.propTypes = {
+ className: string,
+ currentUserHasListings: bool.isRequired,
+ isAuthenticated: bool.isRequired,
+ name: string,
+ rootClassName: string,
+
+ // from injectIntl
+ intl: intlShape.isRequired,
+};
+
+export default injectIntl(TopbarDesktop);
diff --git a/src/components/TopbarDesktop/TopbarDesktop.test.js b/src/components/TopbarDesktop/TopbarDesktop.test.js
new file mode 100644
index 00000000..a56c64a9
--- /dev/null
+++ b/src/components/TopbarDesktop/TopbarDesktop.test.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import { fakeIntl } from '../../util/test-data';
+import { renderDeep } from '../../util/test-helpers';
+import { RoutesProvider } from '../../components';
+import routesConfiguration from '../../routesConfiguration';
+import { flattenRoutes } from '../../util/routes';
+import TopbarDesktop from './TopbarDesktop';
+
+describe('TopbarDesktop', () => {
+ it('data matches snapshot', () => {
+ const flattenedRoutes = flattenRoutes(routesConfiguration);
+ const tree = renderDeep(
+
+
+
+ );
+ expect(tree).toMatchSnapshot();
+ });
+
+});
diff --git a/src/components/TopbarDesktop/__snapshots__/TopbarDesktop.test.js.snap b/src/components/TopbarDesktop/__snapshots__/TopbarDesktop.test.js.snap
new file mode 100644
index 00000000..39cbadbd
--- /dev/null
+++ b/src/components/TopbarDesktop/__snapshots__/TopbarDesktop.test.js.snap
@@ -0,0 +1,56 @@
+exports[`TopbarDesktop data matches snapshot 1`] = `
+
+`;
diff --git a/src/components/TopbarDesktop/images/saunatime-logo.png b/src/components/TopbarDesktop/images/saunatime-logo.png
new file mode 100644
index 00000000..b8f5ed40
Binary files /dev/null and b/src/components/TopbarDesktop/images/saunatime-logo.png differ
diff --git a/src/components/index.js b/src/components/index.js
index ff3d06b6..976575fd 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -40,6 +40,7 @@ import Select from './Select/Select';
import StripeBankAccountToken from './StripeBankAccountToken/StripeBankAccountToken';
import TabNav from './TabNav/TabNav';
import Tabs from './Tabs/Tabs';
+import TopbarDesktop from './TopbarDesktop/TopbarDesktop';
import ValidationError from './ValidationError/ValidationError';
export {
@@ -87,5 +88,6 @@ export {
StripeBankAccountToken,
TabNav,
Tabs,
+ TopbarDesktop,
ValidationError,
};
diff --git a/src/examples.js b/src/examples.js
index cb139c66..92635dbb 100644
--- a/src/examples.js
+++ b/src/examples.js
@@ -17,6 +17,7 @@ import * as StripeBankAccountToken
from './components/StripeBankAccountToken/StripeBankAccountToken.example';
import * as TabNav from './components/TabNav/TabNav.example';
import * as Tabs from './components/Tabs/Tabs.example';
+import * as TopbarDesktop from './components/TopbarDesktop/TopbarDesktop.example';
// containers
import * as BookingDatesForm from './containers/BookingDatesForm/BookingDatesForm.example';
@@ -72,5 +73,6 @@ export {
StripePaymentForm,
TabNav,
Tabs,
+ TopbarDesktop,
Typography,
};
diff --git a/src/translations/en.json b/src/translations/en.json
index 27d663f3..9069ca3a 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -188,5 +188,10 @@
"StripePaymentForm.stripe.validation_error.processing_error": "An error occurred while processing the card.",
"StripePaymentForm.submitPaymentInfo": "Send request",
"Topbar.menuIcon": "Open menu",
- "Topbar.searchIcon": "Open search"
+ "Topbar.searchIcon": "Open search",
+ "TopbarDesktop.createListing": "+ Add your sauna",
+ "TopbarDesktop.inbox": "Inbox",
+ "TopbarDesktop.login": "Log in",
+ "TopbarDesktop.logo": "Logo",
+ "TopbarDesktop.signup": "Sign up"
}