build(navigation): integrate namespaces and fonts
This commit is contained in:
parent
76c6d18695
commit
86e60e6c5f
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "my-joy-images",
|
"name": "my-joy-images",
|
||||||
"version": "1.3.6",
|
"version": "1.4.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"repository": "github:yldio/joyent-portal",
|
"repository": "github:yldio/joyent-portal",
|
||||||
|
@ -13,6 +13,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="header"></div>
|
<div id="header"></div>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script src="/nav-static/main.js"></script>
|
<script src="/navigation/static/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "my-joy-instances",
|
"name": "my-joy-instances",
|
||||||
"version": "2.2.6",
|
"version": "2.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"repository": "github:yldio/joyent-portal",
|
"repository": "github:yldio/joyent-portal",
|
||||||
|
@ -13,6 +13,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="header"></div>
|
<div id="header"></div>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script src="/nav-static/main.js"></script>
|
<script src="/navigation/static/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,33 +1,90 @@
|
|||||||
const Inert = require('inert');
|
const Inert = require('inert');
|
||||||
const Path = require('path');
|
const Path = require('path');
|
||||||
|
const Url = require('url');
|
||||||
|
const Intercept = require('apr-intercept');
|
||||||
|
const Fs = require('mz/fs');
|
||||||
|
|
||||||
const ROOT = Path.join(__dirname, '../build');
|
const { NAMESPACE = 'navigation' } = process.env;
|
||||||
|
|
||||||
exports.register = async server => {
|
exports.register = async server => {
|
||||||
const manifest = require('../build/asset-manifest.json');
|
const manifest = require('../build/asset-manifest.json');
|
||||||
|
const buildRoot = Path.join(__dirname, '../build');
|
||||||
|
const buildStatic = Path.join(buildRoot, `${NAMESPACE}`);
|
||||||
|
const publicRoot = Path.join(__dirname, `../public/static`);
|
||||||
|
|
||||||
await server.register(Inert);
|
await server.register([
|
||||||
|
{
|
||||||
|
plugin: Inert
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
server.route([
|
server.route([
|
||||||
{
|
{
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: '/nav-static/{path*}',
|
path: `/${NAMESPACE}/service-worker.js`,
|
||||||
config: {
|
config: {
|
||||||
auth: false,
|
auth: false,
|
||||||
handler: (request, h) => {
|
handler: {
|
||||||
const { params } = request;
|
file: {
|
||||||
const { path } = params;
|
path: Path.join(__dirname, '../build/service-worker.js')
|
||||||
|
|
||||||
const file = manifest[path];
|
|
||||||
|
|
||||||
if (!file) {
|
|
||||||
return h.continue;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
path: `/${NAMESPACE}/favicon.ico`,
|
||||||
|
config: {
|
||||||
|
auth: false,
|
||||||
|
handler: {
|
||||||
|
file: {
|
||||||
|
path: Path.join(__dirname, '../build/favicon.ico')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
path: `/${NAMESPACE}/static/{rest*}`,
|
||||||
|
config: {
|
||||||
|
auth: false
|
||||||
|
},
|
||||||
|
handler: async (request, h) => {
|
||||||
|
const { params } = request;
|
||||||
|
const { rest } = params;
|
||||||
|
|
||||||
return h.file(Path.join(ROOT, file), {
|
const publicPathname = Path.join(publicRoot, rest);
|
||||||
confine: ROOT
|
const [err1] = await Intercept(
|
||||||
|
Fs.access(publicPathname, Fs.constants.R_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log({ publicPathname });
|
||||||
|
|
||||||
|
if (!err1) {
|
||||||
|
return h.file(publicPathname, {
|
||||||
|
confine: publicRoot
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const buildMapPathname = Path.join(buildRoot, manifest[rest]);
|
||||||
|
const [err2] = await Intercept(
|
||||||
|
Fs.access(buildMapPathname, Fs.constants.R_OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log({ buildMapPathname });
|
||||||
|
|
||||||
|
if (!err2) {
|
||||||
|
return h.file(buildMapPathname, {
|
||||||
|
confine: buildStatic
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log({ buildPathname });
|
||||||
|
|
||||||
|
const buildPathname = Path.join(buildStatic, rest);
|
||||||
|
return h.file(buildPathname, {
|
||||||
|
confine: buildStatic
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "my-joy-navigation",
|
"name": "my-joy-navigation",
|
||||||
"version": "2.2.0",
|
"version": "2.3.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "NODE_ENV=development PREACT=1 REACT_APP_GQL_PORT=4000 PORT=3000 joyent-react-scripts start",
|
"dev": "NAMESPACE=navigation NODE_ENV=development PREACT=1 REACT_APP_GQL_PORT=3068 PORT=3000 joyent-react-scripts start",
|
||||||
"build:test": "echo 0",
|
"build:test": "echo 0",
|
||||||
"build:lib": "echo 0",
|
"build:lib": "echo 0",
|
||||||
"build:bundle": "NODE_ENV=production redrun build",
|
"build:bundle": "NAMESPACE=navigation NODE_ENV=production redrun build",
|
||||||
"prepublish": "NODE_ENV=production redrun build",
|
"prepublish": "NAMESPACE=navigation NODE_ENV=production redrun build",
|
||||||
"lint": "redrun lint:ci -- --fix",
|
"lint": "redrun lint:ci -- --fix",
|
||||||
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
||||||
"test": "echo 0",
|
"test": "echo 0",
|
||||||
@ -22,6 +22,7 @@
|
|||||||
"apollo-link": "^1.2.1",
|
"apollo-link": "^1.2.1",
|
||||||
"apollo-link-http": "^1.5.2",
|
"apollo-link-http": "^1.5.2",
|
||||||
"apollo-link-state": "^0.4.0",
|
"apollo-link-state": "^0.4.0",
|
||||||
|
"apr-intercept": "^3.0.3",
|
||||||
"emotion": "^8.0.12",
|
"emotion": "^8.0.12",
|
||||||
"emotion-theming": "^8.0.12",
|
"emotion-theming": "^8.0.12",
|
||||||
"graphql-tag": "^2.8.0",
|
"graphql-tag": "^2.8.0",
|
||||||
@ -29,9 +30,10 @@
|
|||||||
"joyent-icons": "^5.1.0",
|
"joyent-icons": "^5.1.0",
|
||||||
"joyent-ui-toolkit": "^6.0.0",
|
"joyent-ui-toolkit": "^6.0.0",
|
||||||
"lodash.chunk": "^4.2.0",
|
"lodash.chunk": "^4.2.0",
|
||||||
|
"lodash.groupby": "^4.6.0",
|
||||||
"lodash.keys": "^4.2.0",
|
"lodash.keys": "^4.2.0",
|
||||||
|
"mz": "^2.7.0",
|
||||||
"outy": "^0.1.2",
|
"outy": "^0.1.2",
|
||||||
"param-case": "^2.1.1",
|
|
||||||
"pascal-case": "^2.0.1",
|
"pascal-case": "^2.0.1",
|
||||||
"preact": "^8.2.7",
|
"preact": "^8.2.7",
|
||||||
"preact-compat": "^3.18.0",
|
"preact-compat": "^3.18.0",
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@import url('https://fonts.googleapis.com/css?family=Libre+Franklin:400,500,600');
|
@import url('/instances/static/css/libra-franklin.css');
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Libre Franklin';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Libre Franklin'), local('LibreFranklin-Regular'),
|
||||||
|
url(../fonts/libre-franklin/libre-franklin-regular.ttf) format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Libre Franklin';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: local('Libre Franklin Medium'), local('LibreFranklin-Medium'),
|
||||||
|
url(../fonts/libre-franklin/libre-franklin-medium.ttf) format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Libre Franklin';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
src: local('Libre Franklin SemiBold'), local('LibreFranklin-SemiBold'),
|
||||||
|
url(../fonts/libre-franklin/libre-franklin-semibold.ttf) format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Libre Franklin';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Libre Franklin Bold'), local('LibreFranklin-Bold'),
|
||||||
|
url(../fonts/libre-franklin/libre-franklin-bold.ttf) format('truetype');
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
93
packages/my-joy-navigation/public/static/fonts/libre-franklin/license.txt
Executable file
93
packages/my-joy-navigation/public/static/fonts/libre-franklin/license.txt
Executable file
@ -0,0 +1,93 @@
|
|||||||
|
Copyright (c) 2015, Impallari Type (www.impallari.com)
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
@ -2,35 +2,14 @@ import React from 'react';
|
|||||||
import { ApolloProvider } from 'react-apollo';
|
import { ApolloProvider } from 'react-apollo';
|
||||||
import { ThemeProvider } from 'emotion-theming';
|
import { ThemeProvider } from 'emotion-theming';
|
||||||
|
|
||||||
import theme from 'joyent-ui-toolkit/dist/es/theme';
|
import theme from '@state/theme';
|
||||||
|
|
||||||
import { client } from './state';
|
import { client } from './state';
|
||||||
import Header from './header';
|
import Header from './header';
|
||||||
|
|
||||||
const fullTheme = {
|
|
||||||
...theme,
|
|
||||||
flexboxgrid: {
|
|
||||||
gridSize: 12, // rem
|
|
||||||
gutterWidth: 1.25, // rem
|
|
||||||
outerMargin: 1.875, // rem
|
|
||||||
mediaQuery: 'only screen',
|
|
||||||
container: {
|
|
||||||
sm: 46, // rem
|
|
||||||
md: 56, // rem
|
|
||||||
lg: 59 // rem
|
|
||||||
},
|
|
||||||
breakpoints: {
|
|
||||||
xs: 0, // em
|
|
||||||
sm: 48, // em
|
|
||||||
md: 64, // em
|
|
||||||
lg: 75 // em
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default () => (
|
export default () => (
|
||||||
<ApolloProvider client={client}>
|
<ApolloProvider client={client}>
|
||||||
<ThemeProvider theme={fullTheme}>
|
<ThemeProvider theme={theme}>
|
||||||
<Header />
|
<Header />
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</ApolloProvider>
|
</ApolloProvider>
|
||||||
|
13
packages/my-joy-navigation/src/components/anchor.js
Normal file
13
packages/my-joy-navigation/src/components/anchor.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import emotion from 'preact-emotion';
|
||||||
|
|
||||||
|
export default emotion('a')`
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 24px;
|
||||||
|
font-size: 15px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: ${props => props.theme.text};
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: ${props => props.theme.primary}
|
||||||
|
}
|
||||||
|
`;
|
@ -30,7 +30,7 @@ export const Item = emotion('div')`
|
|||||||
${props =>
|
${props =>
|
||||||
props.active &&
|
props.active &&
|
||||||
`
|
`
|
||||||
height: ${remcalc(27)};
|
margin-top: ${remcalc(3)};
|
||||||
border-bottom: ${remcalc(3)} solid #E38200;
|
border-bottom: ${remcalc(3)} solid #E38200;
|
||||||
background-color: rgba(0, 0, 0, 0.25);
|
background-color: rgba(0, 0, 0, 0.25);
|
||||||
`};
|
`};
|
||||||
|
@ -32,3 +32,5 @@ export {
|
|||||||
} from './service';
|
} from './service';
|
||||||
|
|
||||||
export { default as Overlay } from './overlay';
|
export { default as Overlay } from './overlay';
|
||||||
|
export { default as Anchor } from './anchor';
|
||||||
|
export { default as Sup } from './sup';
|
||||||
|
@ -31,5 +31,8 @@ export const Description = emotion('h6')`
|
|||||||
|
|
||||||
export default emotion('a')`
|
export default emotion('a')`
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
margin-bottom: ${remcalc(22)};
|
margin-bottom: ${remcalc(22)};
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
14
packages/my-joy-navigation/src/components/sup.js
Normal file
14
packages/my-joy-navigation/src/components/sup.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import emotion from 'preact-emotion';
|
||||||
|
import remcalc from 'remcalc';
|
||||||
|
|
||||||
|
export default emotion('sup')`
|
||||||
|
position: absolute;
|
||||||
|
margin-left: ${remcalc(6)};
|
||||||
|
font-weight: ${props => props.theme.font.weight.semibold};
|
||||||
|
line-height: normal;
|
||||||
|
font-size: ${remcalc(8)};
|
||||||
|
color: ${props => (props.new ? props.theme.orange : props.theme.primary)};
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
`;
|
@ -3,21 +3,30 @@ import emotion from 'preact-emotion';
|
|||||||
import { graphql, compose } from 'react-apollo';
|
import { graphql, compose } from 'react-apollo';
|
||||||
import gql from 'graphql-tag';
|
import gql from 'graphql-tag';
|
||||||
import remcalc from 'remcalc';
|
import remcalc from 'remcalc';
|
||||||
|
import groupBy from 'lodash.groupby';
|
||||||
|
|
||||||
import { Grid, Row, Col } from 'preact-emotion-flexboxgrid';
|
import { Grid, Row, Col } from 'preact-emotion-flexboxgrid';
|
||||||
import {
|
import {
|
||||||
DatacenterPlace,
|
DatacenterPlace,
|
||||||
DatacenterRegion,
|
DatacenterRegion,
|
||||||
Datacenter,
|
Datacenter,
|
||||||
Overlay
|
Overlay,
|
||||||
|
Anchor
|
||||||
} from '../components';
|
} from '../components';
|
||||||
|
|
||||||
|
const fixContinentName = name =>
|
||||||
|
name
|
||||||
|
.toLowerCase()
|
||||||
|
.split('_')
|
||||||
|
.join(' ');
|
||||||
|
|
||||||
const Container = emotion('div')`
|
const Container = emotion('div')`
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const TitleContainer = emotion('div')`
|
const TitleContainer = emotion('div')`
|
||||||
background-color: ${props => props.theme.background};
|
background-color: ${props => props.theme.background};
|
||||||
|
text-transform:capitalize;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const RegionContainer = emotion('div')`
|
const RegionContainer = emotion('div')`
|
||||||
@ -27,19 +36,13 @@ const RegionContainer = emotion('div')`
|
|||||||
|
|
||||||
const GetDatacenters = gql`
|
const GetDatacenters = gql`
|
||||||
{
|
{
|
||||||
regions @client {
|
regions {
|
||||||
name
|
name
|
||||||
slug
|
continent
|
||||||
|
datacenters {
|
||||||
|
name
|
||||||
|
url
|
||||||
}
|
}
|
||||||
places @client {
|
|
||||||
name
|
|
||||||
slug
|
|
||||||
region
|
|
||||||
}
|
|
||||||
datacenters @client {
|
|
||||||
name
|
|
||||||
slug
|
|
||||||
place
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -47,13 +50,15 @@ const GetDatacenters = gql`
|
|||||||
const Datacenters = ({ expanded, regions = [] }) =>
|
const Datacenters = ({ expanded, regions = [] }) =>
|
||||||
expanded ? (
|
expanded ? (
|
||||||
<Overlay>
|
<Overlay>
|
||||||
{regions.map(({ name, slug, places }) => (
|
{Object.keys(regions).map(region => (
|
||||||
<div key={slug}>
|
<div key={region}>
|
||||||
<TitleContainer>
|
<TitleContainer>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
<DatacenterRegion>{name}</DatacenterRegion>
|
<DatacenterRegion>
|
||||||
|
{fixContinentName(region)}
|
||||||
|
</DatacenterRegion>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -62,11 +67,13 @@ const Datacenters = ({ expanded, regions = [] }) =>
|
|||||||
<Grid>
|
<Grid>
|
||||||
<RegionContainer>
|
<RegionContainer>
|
||||||
<Row>
|
<Row>
|
||||||
{places.map(({ name, slug, datacenters }) => (
|
{regions[region].map(({ name, datacenters }) => (
|
||||||
<Col key={slug} xs={12} md={6} lg={3}>
|
<Col key={name} xs={12} md={6} lg={3}>
|
||||||
<DatacenterPlace>{name}</DatacenterPlace>
|
<DatacenterPlace>{name}</DatacenterPlace>
|
||||||
{datacenters.map(({ name, slug }) => (
|
{datacenters.map(({ name, url }) => (
|
||||||
<Datacenter key={slug}>{name}</Datacenter>
|
<Datacenter key={name}>
|
||||||
|
<Anchor href={url}>{name}</Anchor>
|
||||||
|
</Datacenter>
|
||||||
))}
|
))}
|
||||||
</Col>
|
</Col>
|
||||||
))}
|
))}
|
||||||
@ -84,28 +91,10 @@ export default compose(
|
|||||||
options: () => ({
|
options: () => ({
|
||||||
ssr: false
|
ssr: false
|
||||||
}),
|
}),
|
||||||
props: ({ data }) => {
|
props: ({ data: { regions = [], loading = false, error = null } }) => ({
|
||||||
const {
|
regions: groupBy(regions, 'continent'),
|
||||||
regions = [],
|
loading,
|
||||||
places = [],
|
error
|
||||||
datacenters = [],
|
})
|
||||||
loading = false,
|
|
||||||
error = null
|
|
||||||
} = data;
|
|
||||||
|
|
||||||
const _regions = regions.map(({ slug, ...region }) => ({
|
|
||||||
...region,
|
|
||||||
places: places
|
|
||||||
.filter(({ region }) => region === slug)
|
|
||||||
.map(({ slug, ...place }) => ({
|
|
||||||
...place,
|
|
||||||
datacenters: datacenters.filter(({ place }) => place === slug),
|
|
||||||
slug
|
|
||||||
})),
|
|
||||||
slug
|
|
||||||
}));
|
|
||||||
|
|
||||||
return { regions: _regions, loading, error };
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
)(Datacenters);
|
)(Datacenters);
|
||||||
|
@ -2,7 +2,6 @@ import React from 'react';
|
|||||||
import emotion from 'preact-emotion';
|
import emotion from 'preact-emotion';
|
||||||
import { graphql, compose } from 'react-apollo';
|
import { graphql, compose } from 'react-apollo';
|
||||||
import gql from 'graphql-tag';
|
import gql from 'graphql-tag';
|
||||||
import chunk from 'lodash.chunk';
|
|
||||||
import remcalc from 'remcalc';
|
import remcalc from 'remcalc';
|
||||||
|
|
||||||
import { Grid, Row, Col } from 'preact-emotion-flexboxgrid';
|
import { Grid, Row, Col } from 'preact-emotion-flexboxgrid';
|
||||||
@ -12,7 +11,9 @@ import {
|
|||||||
ServiceName,
|
ServiceName,
|
||||||
ServiceDescription,
|
ServiceDescription,
|
||||||
Service,
|
Service,
|
||||||
Overlay
|
Overlay,
|
||||||
|
Anchor,
|
||||||
|
Sup
|
||||||
} from '../components';
|
} from '../components';
|
||||||
|
|
||||||
const Container = emotion('div')`
|
const Container = emotion('div')`
|
||||||
@ -20,75 +21,81 @@ const Container = emotion('div')`
|
|||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const GetCategories = gql`
|
const CategoryWrapper = emotion(Col)`
|
||||||
{
|
margin-bottom: ${remcalc(48)};
|
||||||
categories @client {
|
|
||||||
name
|
|
||||||
slug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const sliptTag = tag => tag.split('=').map(n => n.replace(/'/g, ''));
|
||||||
|
|
||||||
|
const isNew = tag => sliptTag(tag)[0] === 'is-new';
|
||||||
|
|
||||||
|
const formatTag = tag => {
|
||||||
|
if (sliptTag(tag)[0] === 'note') {
|
||||||
|
return sliptTag(tag)[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sliptTag(tag)[0] === 'is-new') {
|
||||||
|
return 'New!';
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
};
|
||||||
|
|
||||||
const GetProducts = gql`
|
const GetProducts = gql`
|
||||||
{
|
{
|
||||||
products {
|
categories {
|
||||||
name
|
name
|
||||||
description
|
services {
|
||||||
category
|
name
|
||||||
|
slug
|
||||||
url
|
url
|
||||||
|
tags
|
||||||
|
description
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Services = ({ expanded = false, categories = [], products = [] }) =>
|
const Services = ({ expanded = false, categories = [], loading }) =>
|
||||||
expanded ? (
|
expanded ? (
|
||||||
<Overlay>
|
<Overlay>
|
||||||
<Container>
|
<Container>
|
||||||
<Grid>
|
<Grid>
|
||||||
{chunk(
|
|
||||||
categories.map(({ slug, ...category }) => ({
|
|
||||||
...category,
|
|
||||||
services: products.filter(({ category }) => category === slug),
|
|
||||||
slug
|
|
||||||
})),
|
|
||||||
4
|
|
||||||
).map(chunk => (
|
|
||||||
<Row>
|
<Row>
|
||||||
{chunk.map(({ name, services }) => (
|
{!loading &&
|
||||||
<Col xs={12} sm={6} md={4} lg={3}>
|
categories.map(({ name, services }) => (
|
||||||
|
<CategoryWrapper xs={12} sm={6} md={4}>
|
||||||
<ServiceCategory>{name}</ServiceCategory>
|
<ServiceCategory>{name}</ServiceCategory>
|
||||||
{services.map(({ name, description }) => (
|
{services.map(({ name, description, url, tags }) => (
|
||||||
<Service>
|
<Service>
|
||||||
<ServiceName>{name}</ServiceName>
|
<ServiceName>
|
||||||
|
<Anchor href={url}>{name}</Anchor>
|
||||||
|
{tags
|
||||||
|
? tags.map(tag => (
|
||||||
|
<Sup new={isNew(tag)}>{formatTag(tag)}</Sup>
|
||||||
|
))
|
||||||
|
: null}
|
||||||
|
</ServiceName>
|
||||||
<ServiceDescription>{description}</ServiceDescription>
|
<ServiceDescription>{description}</ServiceDescription>
|
||||||
</Service>
|
</Service>
|
||||||
))}
|
))}
|
||||||
</Col>
|
</CategoryWrapper>
|
||||||
))}
|
))}
|
||||||
</Row>
|
</Row>
|
||||||
))}
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Container>
|
</Container>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
graphql(GetCategories, {
|
|
||||||
options: () => ({
|
|
||||||
ssr: false
|
|
||||||
}),
|
|
||||||
props: ({ data }) => {
|
|
||||||
const { categories = [] } = data;
|
|
||||||
return { categories };
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
graphql(GetProducts, {
|
graphql(GetProducts, {
|
||||||
options: () => ({
|
options: () => ({
|
||||||
ssr: false
|
ssr: false
|
||||||
}),
|
}),
|
||||||
props: ({ data }) => {
|
props: ({ data: { categories = [], loading = false, error = null } }) => ({
|
||||||
const { products = [] } = data;
|
categories,
|
||||||
return { products };
|
loading,
|
||||||
}
|
error
|
||||||
|
})
|
||||||
})
|
})
|
||||||
)(Services);
|
)(Services);
|
||||||
|
@ -5,7 +5,6 @@ import pascalCase from 'pascal-case';
|
|||||||
import keys from 'lodash.keys';
|
import keys from 'lodash.keys';
|
||||||
|
|
||||||
import { DataCenterIcon, TritonIcon, ServicesIcon } from './components';
|
import { DataCenterIcon, TritonIcon, ServicesIcon } from './components';
|
||||||
// import { ServicesIcon } from './components';
|
|
||||||
import * as Overlays from './containers';
|
import * as Overlays from './containers';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -34,32 +33,21 @@ const GetHeader = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const GetAccount = gql`
|
// Needs to be revised
|
||||||
{
|
// const GetAccount = gql`
|
||||||
datacenter {
|
// {
|
||||||
name
|
// datacenter {
|
||||||
}
|
// name
|
||||||
account {
|
// }
|
||||||
login
|
// account {
|
||||||
}
|
// login
|
||||||
}
|
// }
|
||||||
`;
|
// }
|
||||||
|
// `;
|
||||||
// <HeaderDividerItem />
|
|
||||||
// <HeaderItem
|
|
||||||
// onClick={() => toggleSectionOpen('services')}
|
|
||||||
// active={isOpen && activePanel === 'services'}
|
|
||||||
// >
|
|
||||||
// <HeaderItemContent>Products & Services</HeaderItemContent>
|
|
||||||
// <HeaderItemIcon>
|
|
||||||
// <ServicesIcon light />
|
|
||||||
// </HeaderItemIcon>
|
|
||||||
// </HeaderItem>
|
|
||||||
// <HeaderDividerItem />
|
|
||||||
|
|
||||||
const Navigation = ({
|
const Navigation = ({
|
||||||
login,
|
login,
|
||||||
datacenter,
|
datacenter = true,
|
||||||
toggleSectionOpen,
|
toggleSectionOpen,
|
||||||
isOpen,
|
isOpen,
|
||||||
activePanel
|
activePanel
|
||||||
@ -69,6 +57,17 @@ const Navigation = ({
|
|||||||
<HeaderItem>
|
<HeaderItem>
|
||||||
<TritonIcon light />
|
<TritonIcon light />
|
||||||
</HeaderItem>
|
</HeaderItem>
|
||||||
|
<HeaderDividerItem />
|
||||||
|
<HeaderItem
|
||||||
|
onClick={() => toggleSectionOpen('services')}
|
||||||
|
active={isOpen && activePanel === 'services'}
|
||||||
|
>
|
||||||
|
<HeaderItemContent>Products & Services</HeaderItemContent>
|
||||||
|
<HeaderItemIcon>
|
||||||
|
<ServicesIcon light />
|
||||||
|
</HeaderItemIcon>
|
||||||
|
</HeaderItem>
|
||||||
|
<HeaderDividerItem />
|
||||||
<HeaderFlexibleSpaceItem />
|
<HeaderFlexibleSpaceItem />
|
||||||
<HeaderDividerItem />
|
<HeaderDividerItem />
|
||||||
{datacenter ? (
|
{datacenter ? (
|
||||||
@ -79,7 +78,7 @@ const Navigation = ({
|
|||||||
<HeaderItemContent>
|
<HeaderItemContent>
|
||||||
<HeaderItemSubContent>Data Center:</HeaderItemSubContent>
|
<HeaderItemSubContent>Data Center:</HeaderItemSubContent>
|
||||||
<HeaderSpace />
|
<HeaderSpace />
|
||||||
<span>{datacenter}</span>
|
<span>us-east-1</span>
|
||||||
</HeaderItemContent>
|
</HeaderItemContent>
|
||||||
<HeaderItemIcon>
|
<HeaderItemIcon>
|
||||||
<DataCenterIcon light />
|
<DataCenterIcon light />
|
||||||
@ -87,18 +86,17 @@ const Navigation = ({
|
|||||||
</HeaderItem>
|
</HeaderItem>
|
||||||
) : null}
|
) : null}
|
||||||
{datacenter ? <HeaderDividerItem /> : null}
|
{datacenter ? <HeaderDividerItem /> : null}
|
||||||
{login ? (
|
|
||||||
<HeaderItem>
|
<HeaderItem>
|
||||||
<HeaderItemContent>
|
<HeaderItemContent>
|
||||||
<HeaderItemSubContent>Account:</HeaderItemSubContent>
|
<HeaderItemSubContent>Account:</HeaderItemSubContent>
|
||||||
<HeaderSpace />
|
<HeaderSpace />
|
||||||
{login}
|
Raul Millais
|
||||||
</HeaderItemContent>
|
</HeaderItemContent>
|
||||||
<HeaderItemIcon>
|
<HeaderItemIcon>
|
||||||
<Avatar />
|
<Avatar />
|
||||||
</HeaderItemIcon>
|
</HeaderItemIcon>
|
||||||
</HeaderItem>
|
</HeaderItem>
|
||||||
) : null}
|
)
|
||||||
</HeaderRow>
|
</HeaderRow>
|
||||||
{keys(Overlays).map(panelName =>
|
{keys(Overlays).map(panelName =>
|
||||||
React.createElement(Overlays[panelName], {
|
React.createElement(Overlays[panelName], {
|
||||||
@ -109,23 +107,23 @@ const Navigation = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
graphql(GetAccount, {
|
// graphql(GetAccount, {
|
||||||
options: () => ({
|
// options: () => ({
|
||||||
ssr: false
|
// ssr: false
|
||||||
}),
|
// }),
|
||||||
props: ({ data }) => {
|
// props: ({ data }) => {
|
||||||
const {
|
// const {
|
||||||
account = {},
|
// account = {},
|
||||||
datacenter = {},
|
// datacenter = {},
|
||||||
loading = false,
|
// loading = false,
|
||||||
error = null
|
// error = null
|
||||||
} = data;
|
// } = data;
|
||||||
const { login } = account;
|
// const { login } = account;
|
||||||
const { name } = datacenter;
|
// const { name } = datacenter;
|
||||||
|
|
||||||
return { login, datacenter: name, loading, error };
|
// return { login, datacenter: name, loading, error };
|
||||||
}
|
// }
|
||||||
}),
|
// }),
|
||||||
graphql(GetHeader, {
|
graphql(GetHeader, {
|
||||||
options: () => ({
|
options: () => ({
|
||||||
ssr: false
|
ssr: false
|
||||||
|
@ -1,12 +1,3 @@
|
|||||||
import paramCase from 'param-case';
|
|
||||||
|
|
||||||
const dataSlugFromObjects = (arr = []) =>
|
|
||||||
arr.map(({ name, ...obj }) => ({
|
|
||||||
...obj,
|
|
||||||
name,
|
|
||||||
slug: paramCase(name)
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
resolvers: {
|
resolvers: {
|
||||||
Mutation: {
|
Mutation: {
|
||||||
@ -17,106 +8,6 @@ export default {
|
|||||||
},
|
},
|
||||||
defaults: {
|
defaults: {
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
activePanel: '',
|
activePanel: ''
|
||||||
regions: dataSlugFromObjects([
|
|
||||||
{
|
|
||||||
name: 'Americas',
|
|
||||||
__typename: 'Region'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Europe',
|
|
||||||
__typename: 'Region'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Asia',
|
|
||||||
__typename: 'Region'
|
|
||||||
}
|
|
||||||
]),
|
|
||||||
places: dataSlugFromObjects([
|
|
||||||
{
|
|
||||||
name: 'Ashburn, Virginia, USA',
|
|
||||||
region: 'americas',
|
|
||||||
__typename: 'Place'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Las Vegas, Nevada, USA',
|
|
||||||
region: 'americas',
|
|
||||||
__typename: 'Place'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Emeryville, California, USA',
|
|
||||||
region: 'americas',
|
|
||||||
__typename: 'Place'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Amsterdam, Netherlands',
|
|
||||||
region: 'europe',
|
|
||||||
__typename: 'Place'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Singapore',
|
|
||||||
region: 'asia',
|
|
||||||
__typename: 'Place'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Seoul, South Korea',
|
|
||||||
region: 'asia',
|
|
||||||
__typename: 'Place'
|
|
||||||
}
|
|
||||||
]),
|
|
||||||
datacenters: dataSlugFromObjects([
|
|
||||||
{
|
|
||||||
name: 'us-east-1',
|
|
||||||
place: 'ashburn-virginia-usa',
|
|
||||||
__typename: 'Datacenter'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'us-east-2',
|
|
||||||
place: 'ashburn-virginia-usa',
|
|
||||||
__typename: 'Datacenter'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'us-east-3',
|
|
||||||
place: 'ashburn-virginia-usa',
|
|
||||||
__typename: 'Datacenter'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'us-west-1',
|
|
||||||
place: 'emeryville-california-usa',
|
|
||||||
__typename: 'Datacenter'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'us-sw-1',
|
|
||||||
place: 'las-vegas-nevada-usa',
|
|
||||||
__typename: 'Datacenter'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'eu-ams-1',
|
|
||||||
place: 'amsterdam-netherlands',
|
|
||||||
__typename: 'Datacenter'
|
|
||||||
}
|
|
||||||
]),
|
|
||||||
categories: dataSlugFromObjects([
|
|
||||||
{
|
|
||||||
name: 'Compute',
|
|
||||||
__typename: 'Category'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Network',
|
|
||||||
__typename: 'Category'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Storage',
|
|
||||||
__typename: 'Category'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Access',
|
|
||||||
__typename: 'Category'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Help & Support',
|
|
||||||
__typename: 'Category'
|
|
||||||
}
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
40
packages/my-joy-navigation/src/state/theme.js
Normal file
40
packages/my-joy-navigation/src/state/theme.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import theme from 'joyent-ui-toolkit/dist/es/theme';
|
||||||
|
|
||||||
|
const font = theme.font.href({
|
||||||
|
namespace: 'navigation'
|
||||||
|
});
|
||||||
|
|
||||||
|
const monoFont = theme.monoFont.href({
|
||||||
|
namespace: 'navigation'
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
...theme,
|
||||||
|
font: {
|
||||||
|
...theme.font,
|
||||||
|
href: () => font
|
||||||
|
},
|
||||||
|
monoFont: {
|
||||||
|
...theme.monoFont,
|
||||||
|
href: () => monoFont
|
||||||
|
},
|
||||||
|
headerbg: '#1e313b',
|
||||||
|
overlay: 'rgba(0, 0, 0, 0.25)',
|
||||||
|
flexboxgrid: {
|
||||||
|
gridSize: 12, // rem
|
||||||
|
gutterWidth: 1.25, // rem
|
||||||
|
outerMargin: 1.875, // rem
|
||||||
|
mediaQuery: 'only screen',
|
||||||
|
container: {
|
||||||
|
sm: 46, // rem
|
||||||
|
md: 56, // rem
|
||||||
|
lg: 59 // rem
|
||||||
|
},
|
||||||
|
breakpoints: {
|
||||||
|
xs: 0, // em
|
||||||
|
sm: 48, // em
|
||||||
|
md: 64, // em
|
||||||
|
lg: 75 // em
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user