Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniele Bertella committed May 6, 2016
0 parents commit ac23feb
Show file tree
Hide file tree
Showing 36 changed files with 876 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"presets": ["es2015", "stage-0", "react"],
"plugins": ["transform-runtime"]
}
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.DS_STORE
node_modules
static
.module-cache
*.log*

75 changes: 75 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Ventura Next Poc

Un proof of concept di una struttura a plugin per una applicazione react

## Contiene

- [x] [Webpack](https://webpack.github.io)
- [x] [React](https://facebook.github.io/react/)
- [x] [Redux](https://github.com/reactjs/redux)
- [x] [Babel](https://babeljs.io/)

## Setup

```
$ npm install
```

## Running

```
$ npm start
```

## Come funziona

Nel file package.json alcune dipendenze possono essere specificate anche dentro l'array *venturaPlugins*. Questo marca queste dipendenze come plugin compatibili con il sistema descritto in seguito, cio non toglie che questi plugin saranno gestibili come pacchetti npm indipendenti.
```json
"venturaPlugins": [
"Settings",
"Clients",
"Maps"
],
```
Attraverso webpack viene letto l'array dei plugin e messo in una costante *VENTURA_PLUGINS* che sarà disponibile nell'applicazione.

```javascript
new webpack.DefinePlugin({
VENTURA_PLUGINS: JSON.stringify(require("./package.json").venturaPlugins)
})
```

*App*, che è il nostro componente connesso con lo stato di redux, legge la costante VENTURA_PLUGINS e richiede i plugin durante la fase di boot dell'applicazione
```javascript
const plugins = VENTURA_PLUGINS.map(plugin => {
return require('components/' + plugin + '/index.js').default
});
```
Successivamente salva i nostri plugin nello stato di redux
```javascript
actions.addPlugins(plugins);
```
A questo punto, il nostro redux store è informato dei plugin che sono presenti.

Per esempio, un plugin che voglia aggiungere una voce al menu dell'applicazione, può passare tramite props il componente che implementa questa voce di menu al componente builtin *SideBar*

In questo POC i plugin sono fondamentalmente delle voci di menu a cui è associato un altro
componente che viene visualizzato nella sezione principale.

Ogni plugin caricato nella sidebar può essere associato una serie di componenti dipendenti, in questo caso cliccando su un elemento della sidebar viene caricato il componente selezionato in *MainSection*, nel nostro esempio viene caricato un h1 diverso.

## Caricamento Lazy dei plugin

Utilizzando [**bundle-loader**](https://github.com/webpack/bundle-loader) di webpack è possibile ottenere il caricamento Lazy dei plugin che quindi, inizialmente non fanno parte del bundle ma vengono caricati dinamicamente in un secondo momento.

```javascript
const plugin = 'Orders';
const waitForChunk = require('bundle?lazy!./../../../plugins/Orders/index.js')

waitForChunk((file) => {
const newPlugin = file.default
actions.addPlugins([newPlugin]);
});
```

Schiacciando sul bottone Add Order in alto a destra del POC, viene caricato un nuovo bundle js che aggiunge una nuova voce di menu, Orders nel nostro caso, caricando anche il suo componente figlio.
9 changes: 9 additions & 0 deletions client/actions/todos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

import { createAction } from 'redux-actions'

export const addPlugins = createAction('add plugins')
export const showPlugin = createAction('show plugin')
export const editTodo = createAction('edit todo')
export const completeTodo = createAction('complete todo')
export const completeAll = createAction('complete all')
export const clearCompleted = createAction('clear complete')
20 changes: 20 additions & 0 deletions client/components/Clients/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

import React, { Component } from 'react'
import style from './style.css'
import ClientsMain from './main'


class Clients extends Component {
renderPlugin = () => {
this.props.actions.showPlugin(<ClientsMain />);
};
render() {
return (
<li className={this.props.className} onClick={this.renderPlugin}>
Clients
</li>
);
}
}

export default Clients
17 changes: 17 additions & 0 deletions client/components/Clients/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

import React, { Component } from 'react'
import style from './style.css'


class ClientsMain extends Component {

render() {
return (
<h1>
Clients
</h1>
);
}
}

export default ClientsMain
5 changes: 5 additions & 0 deletions client/components/Clients/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.main {
flex: 1;
border-bottom: 1px solid #fff;
color: #fff;
}
66 changes: 66 additions & 0 deletions client/components/Footer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@

import React, { Component } from 'react'
import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from 'constants/filters'
import classnames from 'classnames'
import style from './style.css'

const FILTER_TITLES = {
[SHOW_ALL]: 'All',
[SHOW_ACTIVE]: 'Active',
[SHOW_COMPLETED]: 'Completed'
}

class Footer extends Component {
renderTodoCount = () => {
const { activeCount } = this.props
const itemWord = activeCount === 1 ? 'item' : 'items'

return (
<span className={style.count}>
<strong>{activeCount || 'No'}</strong> {itemWord} left
</span>
)
};

renderFilterLink = (filter) => {
const title = FILTER_TITLES[filter]
const { filter: selectedFilter, onShow } = this.props

return (
<a className={classnames({ [style.selected]: filter === selectedFilter })}
style={{ cursor: 'pointer' }}
onClick={() => onShow(filter)}>
{title}
</a>
)
};

renderClearButton = () => {
const { completedCount, onClearCompleted } = this.props
if (completedCount > 0) {
return (
<button className={style.clearCompleted} onClick={onClearCompleted} >
Clear completed
</button>
)
}
};

render() {
return (
<footer className={style.normal}>
{this.renderTodoCount()}
<ul className={style.filters}>
{[SHOW_ALL, SHOW_ACTIVE, SHOW_COMPLETED].map(filter =>
<li key={filter}>
{this.renderFilterLink(filter)}
</li>
)}
</ul>
{this.renderClearButton()}
</footer>
)
}
}

export default Footer
96 changes: 96 additions & 0 deletions client/components/Footer/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@

.normal {
color: #777;
padding: 10px 15px;
height: 20px;
text-align: center;
border-top: 1px solid #e6e6e6;
}

.normal:before {
content: '';
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 50px;
overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
0 8px 0 -3px #f6f6f6,
0 9px 1px -3px rgba(0, 0, 0, 0.2),
0 16px 0 -6px #f6f6f6,
0 17px 2px -6px rgba(0, 0, 0, 0.2);
}

.filters {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
right: 0;
left: 0;
}

.filters li {
display: inline;
}

.filters li a {
color: inherit;
margin: 3px;
padding: 3px 7px;
text-decoration: none;
border: 1px solid transparent;
border-radius: 3px;
}

.filters li a.selected,
.filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}

.filters li a.selected {
border-color: rgba(175, 47, 47, 0.2);
}

.count {
float: left;
text-align: left;
}

.count strong {
font-weight: 300;
}

.clearCompleted,
html .clearCompleted:active {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
cursor: pointer;
visibility: hidden;
position: relative;
}

.clearCompleted::after {
visibility: visible;
content: 'Clear completed';
position: absolute;
right: 0;
white-space: nowrap;
}

.clearCompleted:hover::after {
text-decoration: underline;
}

@media (max-width: 430px) {
.normal {
height: 50px;
}

.filters {
bottom: 10px;
}
}
14 changes: 14 additions & 0 deletions client/components/Header/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

import React, { Component } from 'react'

class Header extends Component {
render() {
return (
<header>
<h1>React redux plugin POC</h1>
</header>
)
}
}

export default Header
23 changes: 23 additions & 0 deletions client/components/MainSection/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

import React, { Component } from 'react'
import style from './style.css'


class MainSection extends Component {
render() {
const {
plugin
} = this.props;
return (
<div className={style.main}>
{
Object.keys(plugin).length > 0 && JSON.stringify(plugin) !== JSON.stringify({})
? plugin
: <h1>Dashboard</h1>
}
</div>
);
}
}

export default MainSection
7 changes: 7 additions & 0 deletions client/components/MainSection/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

.main {
flex: 3;
padding: 2em;
background: darkseagreen;
color: #fff;
}
20 changes: 20 additions & 0 deletions client/components/Maps/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

import React, { Component } from 'react'
import style from './style.css'
import MapsMain from './main'


class Maps extends Component {
renderPlugin = () => {
this.props.actions.showPlugin(<MapsMain />);
};
render() {
return (
<li className={this.props.className} onClick={this.renderPlugin}>
Maps
</li>
);
}
}

export default Maps
17 changes: 17 additions & 0 deletions client/components/Maps/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

import React, { Component } from 'react'
import style from './style.css'


class MapsMain extends Component {

render() {
return (
<h1>
Maps
</h1>
);
}
}

export default MapsMain
5 changes: 5 additions & 0 deletions client/components/Maps/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.main {
flex: 1;
border-bottom: 1px solid #fff;
color: #fff;
}
Loading

0 comments on commit ac23feb

Please sign in to comment.