diff --git a/.csscomb.json b/.csscomb.json new file mode 100644 index 00000000..9b710499 --- /dev/null +++ b/.csscomb.json @@ -0,0 +1,323 @@ +{ + "exclude": [ + ".git/**", + "node_modules/**", + "bower_components/**" + ], + "always-semicolon": true, + "block-indent": " ", + "color-case": "lower", + "color-shorthand": true, + "element-case": "lower", + "eof-newline": true, + "leading-zero": false, + "quotes": "single", + "remove-empty-rulesets": true, + "space-after-colon": " ", + "space-after-combinator": " ", + "space-after-opening-brace": "\n", + "space-after-selector-delimiter": " ", + "space-before-closing-brace": "\n", + "space-before-colon": "", + "space-before-combinator": " ", + "space-before-opening-brace": " ", + "space-before-selector-delimiter": "", + "strip-spaces": true, + "unitless-zero": true, + "vendor-prefix-align": true, + "sort-order": [ + [ + "font", + "font-family", + "font-size", + "font-weight", + "font-style", + "font-variant", + "font-size-adjust", + "font-stretch", + "font-effect", + "font-emphasize", + "font-emphasize-position", + "font-emphasize-style", + "font-smooth", + "src", + "line-height", + "position", + "z-index", + "top", + "right", + "bottom", + "left", + "display", + "visibility", + "float", + "clear", + "overflow", + "overflow-x", + "overflow-y", + "-ms-overflow-x", + "-ms-overflow-y", + "clip", + "zoom", + "flex", + "flex-direction", + "flex-order", + "flex-pack", + "flex-align", + "flex-wrap", + "flex-grow", + "flex-shrink", + "align-items", + "justify-content", + "-webkit-box-sizing", + "-moz-box-sizing", + "box-sizing", + "width", + "min-width", + "max-width", + "height", + "min-height", + "max-height", + "margin", + "margin-top", + "margin-right", + "margin-bottom", + "margin-left", + "padding", + "padding-top", + "padding-right", + "padding-bottom", + "padding-left", + "table-layout", + "empty-cells", + "caption-side", + "border-spacing", + "border-collapse", + "list-style", + "list-style-position", + "list-style-type", + "list-style-image", + "content", + "quotes", + "counter-reset", + "counter-increment", + "resize", + "cursor", + "-webkit-user-select", + "-moz-user-select", + "-ms-user-select", + "user-select", + "nav-index", + "nav-up", + "nav-right", + "nav-down", + "nav-left", + "-webkit-transition", + "-moz-transition", + "-ms-transition", + "-o-transition", + "transition", + "-webkit-transition-delay", + "-moz-transition-delay", + "-ms-transition-delay", + "-o-transition-delay", + "transition-delay", + "-webkit-transition-timing-function", + "-moz-transition-timing-function", + "-ms-transition-timing-function", + "-o-transition-timing-function", + "transition-timing-function", + "-webkit-transition-duration", + "-moz-transition-duration", + "-ms-transition-duration", + "-o-transition-duration", + "transition-duration", + "-webkit-transition-property", + "-moz-transition-property", + "-ms-transition-property", + "-o-transition-property", + "transition-property", + "-webkit-transform", + "-moz-transform", + "-ms-transform", + "-o-transform", + "transform", + "-webkit-transform-origin", + "-moz-transform-origin", + "-ms-transform-origin", + "-o-transform-origin", + "transform-origin", + "-webkit-animation", + "-moz-animation", + "-ms-animation", + "-o-animation", + "animation", + "-webkit-animation-name", + "-moz-animation-name", + "-ms-animation-name", + "-o-animation-name", + "animation-name", + "-webkit-animation-duration", + "-moz-animation-duration", + "-ms-animation-duration", + "-o-animation-duration", + "animation-duration", + "-webkit-animation-play-state", + "-moz-animation-play-state", + "-ms-animation-play-state", + "-o-animation-play-state", + "animation-play-state", + "-webkit-animation-timing-function", + "-moz-animation-timing-function", + "-ms-animation-timing-function", + "-o-animation-timing-function", + "animation-timing-function", + "-webkit-animation-delay", + "-moz-animation-delay", + "-ms-animation-delay", + "-o-animation-delay", + "animation-delay", + "-webkit-animation-iteration-count", + "-moz-animation-iteration-count", + "-ms-animation-iteration-count", + "-o-animation-iteration-count", + "animation-iteration-count", + "-webkit-animation-direction", + "-moz-animation-direction", + "-ms-animation-direction", + "-o-animation-direction", + "animation-direction", + "text-align", + "-webkit-text-align-last", + "-moz-text-align-last", + "-ms-text-align-last", + "text-align-last", + "vertical-align", + "white-space", + "text-decoration", + "text-emphasis", + "text-emphasis-color", + "text-emphasis-style", + "text-emphasis-position", + "text-indent", + "-ms-text-justify", + "text-justify", + "letter-spacing", + "word-spacing", + "-ms-writing-mode", + "text-outline", + "text-transform", + "text-wrap", + "text-overflow", + "-ms-text-overflow", + "text-overflow-ellipsis", + "text-overflow-mode", + "-ms-word-wrap", + "word-wrap", + "word-break", + "-ms-word-break", + "-moz-tab-size", + "-o-tab-size", + "tab-size", + "-webkit-hyphens", + "-moz-hyphens", + "hyphens", + "pointer-events", + "opacity", + "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity", + "-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha", + "-ms-interpolation-mode", + "color", + "border", + "border-width", + "border-style", + "border-color", + "border-top", + "border-top-width", + "border-top-style", + "border-top-color", + "border-right", + "border-right-width", + "border-right-style", + "border-right-color", + "border-bottom", + "border-bottom-width", + "border-bottom-style", + "border-bottom-color", + "border-left", + "border-left-width", + "border-left-style", + "border-left-color", + "-webkit-border-radius", + "-moz-border-radius", + "border-radius", + "-webkit-border-top-left-radius", + "-moz-border-radius-topleft", + "border-top-left-radius", + "-webkit-border-top-right-radius", + "-moz-border-radius-topright", + "border-top-right-radius", + "-webkit-border-bottom-right-radius", + "-moz-border-radius-bottomright", + "border-bottom-right-radius", + "-webkit-border-bottom-left-radius", + "-moz-border-radius-bottomleft", + "border-bottom-left-radius", + "-webkit-border-image", + "-moz-border-image", + "-o-border-image", + "border-image", + "-webkit-border-image-source", + "-moz-border-image-source", + "-o-border-image-source", + "border-image-source", + "-webkit-border-image-slice", + "-moz-border-image-slice", + "-o-border-image-slice", + "border-image-slice", + "-webkit-border-image-width", + "-moz-border-image-width", + "-o-border-image-width", + "border-image-width", + "-webkit-border-image-outset", + "-moz-border-image-outset", + "-o-border-image-outset", + "border-image-outset", + "-webkit-border-image-repeat", + "-moz-border-image-repeat", + "-o-border-image-repeat", + "border-image-repeat", + "outline", + "outline-width", + "outline-style", + "outline-color", + "outline-offset", + "background", + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader", + "background-color", + "background-image", + "background-repeat", + "background-attachment", + "background-position", + "background-position-x", + "-ms-background-position-x", + "background-position-y", + "-ms-background-position-y", + "-webkit-background-clip", + "-moz-background-clip", + "background-clip", + "background-origin", + "-webkit-background-size", + "-moz-background-size", + "-o-background-size", + "background-size", + "box-decoration-break", + "-webkit-box-shadow", + "-moz-box-shadow", + "box-shadow", + "filter:progid:DXImageTransform.Microsoft.gradient", + "-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient", + "text-shadow" + ] + ] +} diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..de829399 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,38 @@ +{ + "parser": "babel-eslint", + "env": { + "browser": true, + "node": true, + "jest": true + }, + "plugins": [ + "import", + "react" + ], + "extends": [ + "eslint:recommended", + "plugin:import/errors", + "plugin:react/recommended" + ], + "settings": { + "import/resolver": "webpack" + }, + "rules": { + "array-bracket-spacing": [1, "always"], + "comma-dangle": [1, "never"], + "eqeqeq": [2, "smart"], + "jsx-quotes": [1, "prefer-double"], + "no-unused-vars": 0, + "object-curly-spacing": [1, "always"], + "quotes": [1, "single", "avoid-escape"], + "react/jsx-space-before-closing": [1, "never"], + "react/no-did-mount-set-state": 0, + "react/prop-types": 1, + "semi": [1, "never"], + "space-before-blocks": [1, "always"] + }, + "globals": { + "describe": false, + "it": false + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..41b0c8ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/node_modules +/packages/fragment-chat/node_modules +/packages/fragment-common/node_modules +/packages/fragment-contacts/node_modules +/packages/fragment-header/node_modules diff --git a/lerna.json b/lerna.json new file mode 100644 index 00000000..f19b9681 --- /dev/null +++ b/lerna.json @@ -0,0 +1,7 @@ +{ + "lerna": "2.5.1", + "packages": [ + "packages/*" + ], + "version": "0.0.0" +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..e4671d49 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "mosaic-tailor-react-example", + "version": "1.0.0", + "description": "mosaic-tailor-react-example", + "main": "index.js", + "scripts": { + "start": "node tailor.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/tsnolan23/mosaic-tailor-react-example.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/tsnolan23/mosaic-tailor-react-example/issues" + }, + "homepage": "https://github.com/tsnolan23/mosaic-tailor-react-example#readme", + "devDependencies": { + "babel-eslint": "^8.0.2", + "eslint": "^4.11.0", + "eslint-import-resolver-webpack": "^0.8.3", + "eslint-plugin-import": "^2.8.0", + "eslint-plugin-react": "^7.5.1", + "lerna": "^2.5.1", + "node-tailor": "^3.4.0", + "webpack": "^3.8.1" + } +} diff --git a/packages/fragment-chat/.babelrc b/packages/fragment-chat/.babelrc new file mode 100644 index 00000000..4ffef06d --- /dev/null +++ b/packages/fragment-chat/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["env", "react"] +} diff --git a/packages/fragment-chat/.gitignore b/packages/fragment-chat/.gitignore new file mode 100644 index 00000000..c75eeccc --- /dev/null +++ b/packages/fragment-chat/.gitignore @@ -0,0 +1 @@ +/public diff --git a/packages/fragment-chat/app/Chat/index.js b/packages/fragment-chat/app/Chat/index.js new file mode 100644 index 00000000..5197770f --- /dev/null +++ b/packages/fragment-chat/app/Chat/index.js @@ -0,0 +1,30 @@ +import React, { Component } from 'react' +import classNames from 'classnames' +import './styles.scss' + +class Chat extends Component { + + constructor(props) { + super(props) + this.state ={ + isExpanded: false + } + } + + toggleExpansion() { + this.setState({ isExpanded: !this.state.isExpanded }) + } + + render() { + const classes = classNames({ + chat: true, + expanded: this.state.isExpanded + }) + return( +
this.toggleExpansion() } className={classes}>
+ ) + } + +} + +export default Chat diff --git a/packages/fragment-chat/app/Chat/styles.scss b/packages/fragment-chat/app/Chat/styles.scss new file mode 100644 index 00000000..ba01c9c4 --- /dev/null +++ b/packages/fragment-chat/app/Chat/styles.scss @@ -0,0 +1,15 @@ +.chat { + position: fixed; + right: 30px; + bottom: 0; + width: 250px; + height: 30px; + cursor: pointer; + transition: height .3s; + border-top-left-radius: 5px; + border-top-right-radius: 5px; + background: #5e81ac; + &.expanded { + height: 250px; + } +} diff --git a/packages/fragment-chat/app/index.js b/packages/fragment-chat/app/index.js new file mode 100644 index 00000000..fe26a125 --- /dev/null +++ b/packages/fragment-chat/app/index.js @@ -0,0 +1,6 @@ +import React, { Component } from 'react' +import { render } from 'react-dom' + +import Chat from './Chat' + +render(, document.getElementById('chat')) diff --git a/packages/fragment-chat/fragment.js b/packages/fragment-chat/fragment.js new file mode 100644 index 00000000..2cfb30ad --- /dev/null +++ b/packages/fragment-chat/fragment.js @@ -0,0 +1,23 @@ +const http = require('http') +const url = require('url') +const fs = require('fs') + +const server = http.createServer((req, res) => { + const pathname = url.parse(req.url).pathname + const jsHeader = { 'Content-Type': 'application/javascript' } + switch(pathname) { + case '/public/bundle.js': + res.writeHead(200, jsHeader) + return fs.createReadStream('./public/bundle.js').pipe(res) + default: + res.writeHead(200, { + 'Content-Type': 'text/html', + 'Link': '; rel="fragment-script"' + }) + return res.end('') + } +}) + +server.listen(3000, () => { + console.log('SPA Fragment Server started at 3000') +}) diff --git a/packages/fragment-chat/package.json b/packages/fragment-chat/package.json new file mode 100644 index 00000000..0d0fae76 --- /dev/null +++ b/packages/fragment-chat/package.json @@ -0,0 +1,30 @@ +{ + "name": "fragment-chat", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "webpack -p", + "start": "node fragment.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "classnames": "^2.2.5", + "react": "^16.1.1", + "react-dom": "^16.1.1" + }, + "devDependencies": { + "babel": "^6.23.0", + "babel-core": "^6.26.0", + "babel-loader": "^7.1.2", + "babel-preset-env": "^1.6.1", + "babel-preset-react": "^6.24.1", + "css-loader": "^0.28.7", + "node-sass": "^4.7.2", + "path": "^0.12.7", + "sass-loader": "^6.0.6", + "style-loader": "^0.19.0", + "webpack": "^3.8.1" + } +} diff --git a/packages/fragment-chat/webpack.config.js b/packages/fragment-chat/webpack.config.js new file mode 100644 index 00000000..7c87d3dc --- /dev/null +++ b/packages/fragment-chat/webpack.config.js @@ -0,0 +1,29 @@ +var webpack = require('webpack') + +module.exports = { + entry: './app/index.js', + output: { + path: __dirname + '/public', + publicPath: 'http://localhost:8081/public/', + filename: 'bundle.js', + libraryTarget: 'amd' + }, + module: { + loaders: [ + { + test: /\.js$/, + exclude: /node_modules/, + loader: 'babel-loader' + }, + { + test: /\.scss$/, + loader: 'style-loader!css-loader!sass-loader' + } + ] + }, + externals: { + 'react': 'react', + 'react-dom': 'react-dom', + 'classnames': 'classnames' + } +} diff --git a/packages/fragment-common/.babelrc b/packages/fragment-common/.babelrc new file mode 100644 index 00000000..4ffef06d --- /dev/null +++ b/packages/fragment-common/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["env", "react"] +} diff --git a/packages/fragment-common/.gitignore b/packages/fragment-common/.gitignore new file mode 100644 index 00000000..c75eeccc --- /dev/null +++ b/packages/fragment-common/.gitignore @@ -0,0 +1 @@ +/public diff --git a/packages/fragment-common/common.js b/packages/fragment-common/common.js new file mode 100644 index 00000000..358da683 --- /dev/null +++ b/packages/fragment-common/common.js @@ -0,0 +1,3 @@ +exports.react = require('react') +exports['react-dom'] = require('react-dom') +exports.classnames = require('classnames') diff --git a/packages/fragment-common/fragment.js b/packages/fragment-common/fragment.js new file mode 100644 index 00000000..d19eaba2 --- /dev/null +++ b/packages/fragment-common/fragment.js @@ -0,0 +1,23 @@ +const http = require('http') +const url = require('url') +const fs = require('fs') + +const server = http.createServer((req, res) => { + const pathname = url.parse(req.url).pathname + const jsHeader = { 'Content-Type': 'application/javascript' } + switch(pathname) { + case '/public/bundle.js': + res.writeHead(200, jsHeader) + return fs.createReadStream('./public/bundle.js').pipe(res) + default: + res.writeHead(200, { + 'Content-Type': 'text/html', + 'Link': '; rel="fragment-script"' + }) + return res.end('') + } +}) + +server.listen(6006, () => { + console.log('SPA Fragment Server started at 6006') +}) diff --git a/packages/fragment-common/package.json b/packages/fragment-common/package.json new file mode 100644 index 00000000..9ab3d021 --- /dev/null +++ b/packages/fragment-common/package.json @@ -0,0 +1,25 @@ +{ + "name": "fragment-common", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "webpack -p", + "start": "node fragment.js" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "babel": "^6.23.0", + "babel-core": "^6.26.0", + "babel-loader": "^7.1.2", + "babel-preset-env": "^1.6.1", + "babel-preset-react": "^6.24.1", + "webpack": "^3.8.1" + }, + "dependencies": { + "classnames": "^2.2.5", + "react": "^16.1.1", + "react-dom": "^16.1.1" + } +} diff --git a/packages/fragment-common/webpack.config.js b/packages/fragment-common/webpack.config.js new file mode 100644 index 00000000..ba2ac805 --- /dev/null +++ b/packages/fragment-common/webpack.config.js @@ -0,0 +1,11 @@ +var webpack = require('webpack') + +module.exports = { + entry: './common.js', + output: { + path: __dirname + '/public', + publicPath: 'http://localhost:8081/public/', + filename: 'bundle.js', + libraryTarget: 'umd' + } +} diff --git a/packages/fragment-contacts/.babelrc b/packages/fragment-contacts/.babelrc new file mode 100644 index 00000000..4ffef06d --- /dev/null +++ b/packages/fragment-contacts/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["env", "react"] +} diff --git a/packages/fragment-contacts/.gitignore b/packages/fragment-contacts/.gitignore new file mode 100644 index 00000000..c75eeccc --- /dev/null +++ b/packages/fragment-contacts/.gitignore @@ -0,0 +1 @@ +/public diff --git a/packages/fragment-contacts/app/Contact/index.js b/packages/fragment-contacts/app/Contact/index.js new file mode 100644 index 00000000..9bce57e3 --- /dev/null +++ b/packages/fragment-contacts/app/Contact/index.js @@ -0,0 +1,16 @@ +import React, { Component } from 'react' +import './styles.scss' + +class Contact extends Component { + render() { + return( +
+
+ +
+
+ ) + } +} + +export default Contact diff --git a/packages/fragment-contacts/app/Contact/styles.scss b/packages/fragment-contacts/app/Contact/styles.scss new file mode 100644 index 00000000..f276df7e --- /dev/null +++ b/packages/fragment-contacts/app/Contact/styles.scss @@ -0,0 +1,15 @@ +.contact { + display: flex; + flex: 1; + box-sizing: border-box; + min-width: 25%; + max-width: 25%; + height: 250px; + padding: 10px; + cursor: pointer; + .contact-details { + flex: 1; + border-radius: 3px; + background: #d8dee9; + } +} diff --git a/packages/fragment-contacts/app/Contacts/index.js b/packages/fragment-contacts/app/Contacts/index.js new file mode 100644 index 00000000..82894cf6 --- /dev/null +++ b/packages/fragment-contacts/app/Contacts/index.js @@ -0,0 +1,40 @@ +import React, { Component } from 'react' +import axios from 'axios' +import Contact from '../Contact' +import './styles.scss' + +class Contacts extends Component { + + constructor(props) { + super(props) + this.state ={ + contacts: [] + } + } + + componentWillMount() { + this.fetchContacts() + } + + fetchContacts() { + axios.get('https://randomuser.me/api/?results=20').then((response) => { + this.setState({ contacts: response.data.results }) + }) + } + + render() { + const { contacts } = this.state + return( +
+ { + contacts.length > 0 && contacts.map((contact) => { + return + }) + } +
+ ) + } + +} + +export default Contacts diff --git a/packages/fragment-contacts/app/Contacts/styles.scss b/packages/fragment-contacts/app/Contacts/styles.scss new file mode 100644 index 00000000..d7146dc0 --- /dev/null +++ b/packages/fragment-contacts/app/Contacts/styles.scss @@ -0,0 +1,8 @@ +.contacts { + position: relative; + display: flex; + flex-wrap: wrap; + box-sizing: border-box; + width: 100%; + padding: 100px 20px 20px 20px; +} diff --git a/packages/fragment-contacts/app/index.js b/packages/fragment-contacts/app/index.js new file mode 100644 index 00000000..2ab05c5e --- /dev/null +++ b/packages/fragment-contacts/app/index.js @@ -0,0 +1,6 @@ +import React, { Component } from 'react' +import { render } from 'react-dom' + +import Contacts from './Contacts' + +render(, document.getElementById('contacts')) diff --git a/packages/fragment-contacts/fragment.js b/packages/fragment-contacts/fragment.js new file mode 100644 index 00000000..f5943e6d --- /dev/null +++ b/packages/fragment-contacts/fragment.js @@ -0,0 +1,23 @@ +const http = require('http') +const url = require('url') +const fs = require('fs') + +const server = http.createServer((req, res) => { + const pathname = url.parse(req.url).pathname + const jsHeader = { 'Content-Type': 'application/javascript' } + switch(pathname) { + case '/public/bundle.js': + res.writeHead(200, jsHeader) + return fs.createReadStream('./public/bundle.js').pipe(res) + default: + res.writeHead(200, { + 'Content-Type': 'text/html', + 'Link': '; rel="fragment-script"' + }) + return res.end('') + } +}) + +server.listen(5000, () => { + console.log('SPA Fragment Server started at 5000') +}) diff --git a/packages/fragment-contacts/package.json b/packages/fragment-contacts/package.json new file mode 100644 index 00000000..9f9edb7a --- /dev/null +++ b/packages/fragment-contacts/package.json @@ -0,0 +1,30 @@ +{ + "name": "fragment-contacts", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "webpack -p", + "start": "node fragment.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "axios": "^0.17.1", + "classnames": "^2.2.5", + "react": "^16.1.1", + "react-dom": "^16.1.1" + }, + "devDependencies": { + "babel": "^6.23.0", + "babel-core": "^6.26.0", + "babel-loader": "^7.1.2", + "babel-preset-env": "^1.6.1", + "babel-preset-react": "^6.24.1", + "css-loader": "^0.28.7", + "node-sass": "^4.7.2", + "sass-loader": "^6.0.6", + "style-loader": "^0.19.0", + "webpack": "^3.8.1" + } +} diff --git a/packages/fragment-contacts/webpack.config.js b/packages/fragment-contacts/webpack.config.js new file mode 100644 index 00000000..7c87d3dc --- /dev/null +++ b/packages/fragment-contacts/webpack.config.js @@ -0,0 +1,29 @@ +var webpack = require('webpack') + +module.exports = { + entry: './app/index.js', + output: { + path: __dirname + '/public', + publicPath: 'http://localhost:8081/public/', + filename: 'bundle.js', + libraryTarget: 'amd' + }, + module: { + loaders: [ + { + test: /\.js$/, + exclude: /node_modules/, + loader: 'babel-loader' + }, + { + test: /\.scss$/, + loader: 'style-loader!css-loader!sass-loader' + } + ] + }, + externals: { + 'react': 'react', + 'react-dom': 'react-dom', + 'classnames': 'classnames' + } +} diff --git a/packages/fragment-header/.babelrc b/packages/fragment-header/.babelrc new file mode 100644 index 00000000..4ffef06d --- /dev/null +++ b/packages/fragment-header/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["env", "react"] +} diff --git a/packages/fragment-header/.gitignore b/packages/fragment-header/.gitignore new file mode 100644 index 00000000..c75eeccc --- /dev/null +++ b/packages/fragment-header/.gitignore @@ -0,0 +1 @@ +/public diff --git a/packages/fragment-header/app/Header/index.js b/packages/fragment-header/app/Header/index.js new file mode 100644 index 00000000..f44f832e --- /dev/null +++ b/packages/fragment-header/app/Header/index.js @@ -0,0 +1,48 @@ +import React, { Component } from 'react' +import './styles.scss' +import NavItem from '../NavItem' +import Logo from '../Logo' + +const items = [ 0, 1, 2, 3 ] + +class Header extends Component { + + constructor(props) { + super(props) + this.state = { + name: 'Test', + active: 1 + } + } + + toggle() { + this.setState({ name: this.state.name === 'Test' ? 'New' : 'Test' }) + } + + selectNavItem(index) { + this.setState({ active: index }) + } + + render() { + return( +
{ this.toggle()}} className="header"> + + { + items.map((item, index) => { + return( + this.selectNavItem(index)} + key={index} + /> + ) + }) + } +
+ ) + } + +} + +export default Header diff --git a/packages/fragment-header/app/Header/styles.scss b/packages/fragment-header/app/Header/styles.scss new file mode 100644 index 00000000..6ea6f3d5 --- /dev/null +++ b/packages/fragment-header/app/Header/styles.scss @@ -0,0 +1,13 @@ +.header { + position: fixed; + z-index: 10; + top: 0; + left: 0; + display: flex; + align-items: center; + box-sizing: border-box; + width: 100%; + height: 80px; + padding: 0 30px; + background: #5e81ac; +} diff --git a/packages/fragment-header/app/Logo/index.js b/packages/fragment-header/app/Logo/index.js new file mode 100644 index 00000000..55f9fcce --- /dev/null +++ b/packages/fragment-header/app/Logo/index.js @@ -0,0 +1,12 @@ +import React, { PureComponent } from 'react' +import './styles.scss' + +class Logo extends PureComponent { + render() { + return( +
+ ) + } +} + +export default Logo diff --git a/packages/fragment-header/app/Logo/styles.scss b/packages/fragment-header/app/Logo/styles.scss new file mode 100644 index 00000000..1bc15f59 --- /dev/null +++ b/packages/fragment-header/app/Logo/styles.scss @@ -0,0 +1,7 @@ +.logo { + width: 100px; + height: 40px; + margin-right: 100px; + border-radius: 2px; + background: #8fbcbb; +} diff --git a/packages/fragment-header/app/NavItem/index.js b/packages/fragment-header/app/NavItem/index.js new file mode 100644 index 00000000..416cc536 --- /dev/null +++ b/packages/fragment-header/app/NavItem/index.js @@ -0,0 +1,30 @@ +import React, { Component } from 'react' +import { bool, func, number } from 'prop-types' +import './styles.scss' +import classNames from 'classnames' + +class NavItem extends Component { + + handleClick() { + this.props.onClick(this.props.index) + } + + render() { + const classes = classNames({ + 'nav-item': true, + 'current': this.props.active + }) + return( +
this.handleClick()}>
+ ) + } + +} + +NavItem.propTypes = { + active: bool, + index: number, + onClick: func +} + +export default NavItem diff --git a/packages/fragment-header/app/NavItem/styles.scss b/packages/fragment-header/app/NavItem/styles.scss new file mode 100644 index 00000000..9a690795 --- /dev/null +++ b/packages/fragment-header/app/NavItem/styles.scss @@ -0,0 +1,15 @@ +.nav-item { + width: 100px; + height: 18px; + margin-right: 20px; + cursor: pointer; + transition: all .3s; + border-radius: 3px; + background: #81a1c1; + &:not(.current):hover { + background: lighten(#81a1c1, 10%); + } + &.current { + background: #ebcb8b; + } +} diff --git a/packages/fragment-header/app/index.js b/packages/fragment-header/app/index.js new file mode 100644 index 00000000..f426cc17 --- /dev/null +++ b/packages/fragment-header/app/index.js @@ -0,0 +1,6 @@ +import React, { Component } from 'react' +import { render } from 'react-dom' + +import Header from './Header' + +render(
, document.getElementById('header')) diff --git a/packages/fragment-header/fragment.js b/packages/fragment-header/fragment.js new file mode 100644 index 00000000..d826e48f --- /dev/null +++ b/packages/fragment-header/fragment.js @@ -0,0 +1,23 @@ +const http = require('http') +const url = require('url') +const fs = require('fs') + +const server = http.createServer((req, res) => { + const pathname = url.parse(req.url).pathname + const jsHeader = { 'Content-Type': 'application/javascript' } + switch(pathname) { + case '/public/bundle.js': + res.writeHead(200, jsHeader) + return fs.createReadStream('./public/bundle.js').pipe(res) + default: + res.writeHead(200, { + 'Content-Type': 'text/html', + 'Link': '; rel="fragment-script"' + }) + return res.end('') + } +}) + +server.listen(8081, () => { + console.log('SPA Fragment Server started at 8081') +}) diff --git a/packages/fragment-header/package.json b/packages/fragment-header/package.json new file mode 100644 index 00000000..e0c2c8fb --- /dev/null +++ b/packages/fragment-header/package.json @@ -0,0 +1,30 @@ +{ + "name": "fragment-header", + "version": "1.0.0", + "description": "", + "main": "index.js", + "dependencies": { + "classnames": "^2.2.5", + "prop-types": "^15.6.0", + "react": "^16.1.1", + "react-dom": "^16.1.1" + }, + "scripts": { + "build": "webpack -p", + "start": "node fragment.js" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "babel": "^6.23.0", + "babel-core": "^6.26.0", + "babel-loader": "^7.1.2", + "babel-preset-env": "^1.6.1", + "babel-preset-react": "^6.24.1", + "css-loader": "^0.28.7", + "node-sass": "^4.7.2", + "sass-loader": "^6.0.6", + "style-loader": "^0.19.0", + "webpack": "^3.8.1" + } +} diff --git a/packages/fragment-header/webpack.config.js b/packages/fragment-header/webpack.config.js new file mode 100644 index 00000000..7c87d3dc --- /dev/null +++ b/packages/fragment-header/webpack.config.js @@ -0,0 +1,29 @@ +var webpack = require('webpack') + +module.exports = { + entry: './app/index.js', + output: { + path: __dirname + '/public', + publicPath: 'http://localhost:8081/public/', + filename: 'bundle.js', + libraryTarget: 'amd' + }, + module: { + loaders: [ + { + test: /\.js$/, + exclude: /node_modules/, + loader: 'babel-loader' + }, + { + test: /\.scss$/, + loader: 'style-loader!css-loader!sass-loader' + } + ] + }, + externals: { + 'react': 'react', + 'react-dom': 'react-dom', + 'classnames': 'classnames' + } +} diff --git a/tailor.js b/tailor.js new file mode 100644 index 00000000..2c2b9012 --- /dev/null +++ b/tailor.js @@ -0,0 +1,19 @@ +'use strict' + +const http = require('http') +const Tailor = require('node-tailor') +const tailor = new Tailor({ + templatesPath: __dirname + '/templates' +}) + +http + .createServer((req, res) => { + if (req.url === '/favicon.ico') { + res.writeHead(200, { 'Content-Type': 'image/x-icon' }) + return res.end('') + } + tailor.requestHandler(req, res) + }) + .listen(8080, function() { + console.log('Tailor server listening on port 8080') + }) diff --git a/templates/contacts.html b/templates/contacts.html new file mode 100644 index 00000000..61f31250 --- /dev/null +++ b/templates/contacts.html @@ -0,0 +1,29 @@ + + + + + + + + +
+
+ + + + +