Structured main content of site with Bulma
This commit is contained in:
parent
a3437771f5
commit
067489225a
|
@ -40,6 +40,7 @@
|
|||
"dexie": "^1.5.1",
|
||||
"inferno": "^1.6.0",
|
||||
"inferno-component": "^1.6.0",
|
||||
"inferno-devtools": "^1.6.0",
|
||||
"marked": "^0.3.6",
|
||||
"papaparse": "^4.2.0"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import Inferno from 'inferno';
|
||||
import Component from 'inferno-component';
|
||||
|
||||
import {LeftColumn} from './structure/LeftColumn';
|
||||
import {RightColumn} from './structure/RightColumn';
|
||||
|
||||
import {WordForm} from './management/WordForm';
|
||||
import {DictionaryDetails} from './display/DictionaryDetails';
|
||||
|
||||
export class Lexiconga extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<section className='section'>
|
||||
<div className='container'>
|
||||
<div className='columns'>
|
||||
|
||||
<LeftColumn>
|
||||
<WordForm
|
||||
partsOfSpeech={['Noun','Adjective','Verb']}
|
||||
/>
|
||||
</LeftColumn>
|
||||
|
||||
<RightColumn>
|
||||
<DictionaryDetails
|
||||
description='Test Description'
|
||||
details={{
|
||||
custom: [
|
||||
{
|
||||
name: 'Test Tab'
|
||||
}
|
||||
]
|
||||
}}
|
||||
/>
|
||||
</RightColumn>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
import Inferno from 'inferno';
|
||||
import Component from 'inferno-component';
|
||||
import marked from 'marked';
|
||||
|
||||
import {SearchBox} from '../management/SearchBox';
|
||||
|
||||
const DISPLAY = {
|
||||
NONE: false
|
||||
, DESCRIPTION: 1
|
||||
, DETAILS: 2
|
||||
, STATS: 3
|
||||
, SEARCH: 4
|
||||
}
|
||||
|
||||
export class DictionaryDetails extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
currentDisplay: DISPLAY.NONE
|
||||
}
|
||||
|
||||
this._descriptionHTML = marked(props.description);
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
const currentDescription = this.props.description
|
||||
, nextDescription = nextProps.description;
|
||||
|
||||
if (currentDescription !== nextDescription) {
|
||||
this._descriptionHTML = marked(nextProps.description);
|
||||
}
|
||||
}
|
||||
|
||||
toggleDisplay (display) {
|
||||
display = (this.state.currentDisplay !== display) ? display : DISPLAY.NONE;
|
||||
|
||||
this.setState({
|
||||
currentDisplay: display
|
||||
});
|
||||
}
|
||||
|
||||
displayInfo () {
|
||||
if (this.state.currentDisplay !== DISPLAY.NONE) {
|
||||
let displayJSX;
|
||||
|
||||
switch(this.state.currentDisplay) {
|
||||
case DISPLAY.DESCRIPTION : {
|
||||
// Not sure why, but the dangerouslySet div needs to be wrapped in another div or else
|
||||
// the HTML content sticks around for some reason.
|
||||
displayJSX = (
|
||||
<div>
|
||||
<div className="content"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: this._descriptionHTML
|
||||
}} />
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case DISPLAY.DETAILS : {
|
||||
let additionalMenu;
|
||||
if (this.props.details.hasOwnProperty('custom')) {
|
||||
let customTabsJSX = this.props.details.custom.map((tab) => {
|
||||
return (
|
||||
<li key={'customTab' + Date.now().toString()}>
|
||||
<a>
|
||||
{tab.name}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
additionalMenu = (
|
||||
<div>
|
||||
<p className="menu-label">
|
||||
Additional
|
||||
</p>
|
||||
<ul className="menu-list">
|
||||
{customTabsJSX}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const menu = (
|
||||
<aside className="column is-one-quarter menu">
|
||||
<p className="menu-label">
|
||||
Linguistics
|
||||
</p>
|
||||
<ul className="menu-list">
|
||||
<li><a className="is-active">Phonology</a></li>
|
||||
<li><a>Grammar</a></li>
|
||||
</ul>
|
||||
|
||||
{additionalMenu}
|
||||
|
||||
</aside>
|
||||
);
|
||||
|
||||
let content = (
|
||||
<div className='column'>
|
||||
<p>
|
||||
Details Content!
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
displayJSX = (
|
||||
<div className='columns'>
|
||||
{menu}
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case DISPLAY.STATS : {
|
||||
displayJSX = (
|
||||
<div className="content">
|
||||
<p>Stats!</p>
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case DISPLAY.SEARCH : {
|
||||
displayJSX = <SearchBox />;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='box'>
|
||||
{displayJSX}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className='box'>
|
||||
|
||||
<div className='level'>
|
||||
<div className='level-left'>
|
||||
<div className='level-item'>
|
||||
<h2 className='title is-2'>
|
||||
Dictionary Name
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='level-right'>
|
||||
<div className='level-item'>
|
||||
<div className='field is-grouped'>
|
||||
<div className='control'>
|
||||
<a className='button' onClick={this.toggleDisplay.bind(this, DISPLAY.SEARCH)}>
|
||||
Search
|
||||
</a>
|
||||
</div>
|
||||
<div className='control'>
|
||||
<a className='button'>
|
||||
Edit Dictionary
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='level'>
|
||||
<div className='level-left'>
|
||||
<div className='level-item'>
|
||||
<div className='tabs is-toggle'>
|
||||
<ul>
|
||||
<li className={(this.state.currentDisplay === DISPLAY.DESCRIPTION) ? 'is-active' : null}>
|
||||
<a onClick={this.toggleDisplay.bind(this, DISPLAY.DESCRIPTION)}>
|
||||
<span>Description</span>
|
||||
</a>
|
||||
</li>
|
||||
<li className={(this.state.currentDisplay === DISPLAY.DETAILS) ? 'is-active' : null}>
|
||||
<a onClick={this.toggleDisplay.bind(this, DISPLAY.DETAILS)}>
|
||||
<span>Details</span>
|
||||
</a>
|
||||
</li>
|
||||
<li className={(this.state.currentDisplay === DISPLAY.STATS) ? 'is-active' : null}>
|
||||
<a onClick={this.toggleDisplay.bind(this, DISPLAY.STATS)}>
|
||||
<span>Stats</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.displayInfo()}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
import Inferno from 'inferno';
|
||||
import Component from 'inferno-component';
|
||||
|
||||
export class SearchBox extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
showFilterOptions () {
|
||||
if (this.props.hasOwnProperty('partsOfSpeech')
|
||||
&& this.props.partsOfSpeech.length > 0) {
|
||||
let filterOptionsJSX = this.props.partsOfSpeech.map((partOfSpeech) => {
|
||||
return (
|
||||
<label key={'filterPartOfSpeech' + Date.now()}
|
||||
className='checkbox'>
|
||||
<input type='checkbox' />
|
||||
{partOfSpeech}
|
||||
</label>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className='field'>
|
||||
<label>Filter</label>
|
||||
<p className='control'>
|
||||
{filterOptionsJSX}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className='message'>
|
||||
<div class="message-header">
|
||||
<span>
|
||||
Search
|
||||
</span>
|
||||
<button class="delete"></button>
|
||||
</div>
|
||||
<div class="message-body">
|
||||
<div className='field'>
|
||||
<div className='control'>
|
||||
<input className='input' type='text' placeholder='Search Term' />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='field is-horizontal'>
|
||||
<div className='field-label'>
|
||||
<label className='label'>
|
||||
Search In
|
||||
</label>
|
||||
</div>
|
||||
<div className='field-body'>
|
||||
<div className='field is-narrow'>
|
||||
<div className='control'>
|
||||
<label className='radio'>
|
||||
<input type='radio' name='member' value='Word' checked />
|
||||
Word
|
||||
</label>
|
||||
<label className='radio'>
|
||||
<input type='radio' name='member' />
|
||||
Definition
|
||||
</label>
|
||||
<label className='radio'>
|
||||
<input type='radio' name='member' />
|
||||
Details
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.showFilterOptions()}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
import Inferno from 'inferno';
|
||||
import Component from 'inferno-component';
|
||||
|
||||
export class WordForm extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className='box'>
|
||||
<div className='field'>
|
||||
<label className='label'>Word</label>
|
||||
<p className='control'>
|
||||
<input className='input' type='text' placeholder='Required' />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='field'>
|
||||
<label className='label'>Pronunciation</label>
|
||||
<p className='control'>
|
||||
<input className='input' type='text' placeholder='[prəˌnʌnsiˈeɪʃən]' />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='field'>
|
||||
<label className='label'>Part of Speech</label>
|
||||
<p className='control'>
|
||||
<span className='select'>
|
||||
<select>
|
||||
<option></option>
|
||||
{this.props.partsOfSpeech.map((partOfSpeech) => {
|
||||
return (
|
||||
<option value={partOfSpeech}>{partOfSpeech}</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='field'>
|
||||
<label className='label'>Definition</label>
|
||||
<p className='control'>
|
||||
<input className='input' type='text' placeholder='Text input' />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='field'>
|
||||
<label className='label'>Details</label>
|
||||
<p className='control'>
|
||||
<textarea className='textarea' placeholder='Textarea' />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
import Inferno from 'inferno';
|
||||
import Component from 'inferno-component';
|
||||
|
||||
export class Footer extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<footer className='footer'>
|
||||
<div className='container'>
|
||||
<div className='level'>
|
||||
<div className='level-left'>
|
||||
<div className='content'>
|
||||
<p>
|
||||
Lexiconga is only guaranteed to work with the most
|
||||
up-to-date <a href='https://whatbrowser.org/' target='_blank'>HTML5 browsers</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='level-right'>
|
||||
<span className='level-item'>
|
||||
<a className='button'>
|
||||
Issues
|
||||
</a>
|
||||
</span>
|
||||
<span className='level-item'>
|
||||
<a className='button'>
|
||||
Updates
|
||||
</a>
|
||||
</span>
|
||||
<span className='level-item'>
|
||||
<a className='button'>
|
||||
Terms
|
||||
</a>
|
||||
</span>
|
||||
<span className='level-item'>
|
||||
<a className='button'>
|
||||
Privacy
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
import Inferno from 'inferno';
|
||||
import Component from 'inferno-component';
|
||||
|
||||
export class Header extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<nav className='nav'>
|
||||
<div className='nav-left'>
|
||||
<a href='/' className='nav-item'>
|
||||
<img src='images/logo.svg' alt='Lexiconga' />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<span class="nav-toggle">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</span>
|
||||
|
||||
<div className='nav-right nav-menu'>
|
||||
<span className='nav-item'>
|
||||
<a className='button'>
|
||||
Login
|
||||
</a>
|
||||
</span>
|
||||
<span className='nav-item'>
|
||||
<a className='button'>
|
||||
About
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import Inferno from 'inferno';
|
||||
import Component from 'inferno-component';
|
||||
|
||||
export class LeftColumn extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className='column is-one-third'>
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import Inferno from 'inferno';
|
||||
import Component from 'inferno-component';
|
||||
|
||||
export class RightColumn extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className='column is-two-thirds'>
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,14 @@ import './sass/main.scss';
|
|||
import Inferno from 'inferno';
|
||||
import Component from 'inferno-component';
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
require('inferno-devtools');
|
||||
}
|
||||
|
||||
import {Header} from './components/structure/Header';
|
||||
import {Lexiconga} from './components/Lexiconga';
|
||||
import {Footer} from './components/structure/Footer';
|
||||
|
||||
class App extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
@ -11,95 +19,11 @@ class App extends Component {
|
|||
render () {
|
||||
return (
|
||||
<div>
|
||||
<nav className='nav'>
|
||||
<div className='nav-left'>
|
||||
<a href='/' className='nav-item'>
|
||||
<img src='images/logo.svg' alt='Lexiconga' />
|
||||
</a>
|
||||
</div>
|
||||
<div className='nav-right'>
|
||||
<a href='/' className='nav-item'>
|
||||
Login
|
||||
</a>
|
||||
<a href='/' className='nav-item'>
|
||||
About
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
<Header />
|
||||
|
||||
<section className='section'>
|
||||
<div className='container'>
|
||||
<div className='columns'>
|
||||
<div className='column is-one-quarter'>
|
||||
<div className='box'>
|
||||
<div className='field'>
|
||||
<label className='label'>Word</label>
|
||||
<p className='control'>
|
||||
<input className='input' type='text' placeholder='Text input' />
|
||||
</p>
|
||||
</div>
|
||||
<div className='field'>
|
||||
<label className='label'>Pronunciation</label>
|
||||
<p className='control'>
|
||||
<input className='input' type='text' placeholder='Text input' />
|
||||
</p>
|
||||
</div>
|
||||
<div className='field'>
|
||||
<label className='label'>Part of Speech</label>
|
||||
<p className='control'>
|
||||
<span className='select'>
|
||||
<select>
|
||||
<option>Select dropdown</option>
|
||||
<option>With options</option>
|
||||
</select>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className='field'>
|
||||
<label className='label'>Definition / Equivalent Word(s)</label>
|
||||
<p className='control'>
|
||||
<input className='input' type='text' placeholder='Text input' />
|
||||
</p>
|
||||
</div>
|
||||
<div className='field'>
|
||||
<label className='label'>Explanation / Long Definition</label>
|
||||
<p className='control'>
|
||||
<textarea className='textarea' placeholder='Textarea' />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='column is-half'>
|
||||
<div className='card'>
|
||||
<header className='card-header'>
|
||||
<p className='card-header-title'>
|
||||
Dictionary Name
|
||||
</p>
|
||||
<a className='card-header-icon button'>
|
||||
Edit Dictionary
|
||||
</a>
|
||||
</header>
|
||||
<div className='card-content'>
|
||||
<div className='content'>
|
||||
Hello
|
||||
</div>
|
||||
</div>
|
||||
<footer className='card-footer'>
|
||||
<a className='card-footer-item'>Save</a>
|
||||
<a className='card-footer-item'>Edit</a>
|
||||
<a className='card-footer-item'>Delete</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='column is-one-quarter'>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<Lexiconga />
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
$radius: 0;
|
||||
$radius-large: 0;
|
|
@ -1,10 +1,13 @@
|
|||
// Set BUILDMODE to 'production' to reduce overhead.
|
||||
const BUILDMODE = 'development';
|
||||
|
||||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
|
||||
const BUILD_DIR = path.resolve(__dirname, 'public');
|
||||
const APP_DIR = path.resolve(__dirname, 'src');
|
||||
|
||||
module.exports = {
|
||||
const webpackConfig = {
|
||||
entry: APP_DIR + '/index.jsx'
|
||||
, output: {
|
||||
path: BUILD_DIR
|
||||
|
@ -13,8 +16,8 @@ module.exports = {
|
|||
, module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.scss$/
|
||||
, exclude: /node_modules/
|
||||
test: (/\.scss$/)
|
||||
, exclude: (/node_modules/)
|
||||
, use: [
|
||||
'style-loader'
|
||||
, 'css-loader'
|
||||
|
@ -29,14 +32,18 @@ module.exports = {
|
|||
]
|
||||
}
|
||||
, {
|
||||
test: /\.jsx?$/
|
||||
, exclude: /node_modules/
|
||||
test: (/\.jsx?$/)
|
||||
, exclude: (/node_modules/)
|
||||
, use: [
|
||||
{
|
||||
loader: 'babel-loader'
|
||||
, options: {
|
||||
presets: ['es2016']
|
||||
, plugins: ['inferno']
|
||||
presets: [
|
||||
'es2016'
|
||||
]
|
||||
, plugins: [
|
||||
'inferno'
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -44,18 +51,31 @@ module.exports = {
|
|||
]
|
||||
}
|
||||
, resolve: {
|
||||
extensions: ['.js', '.jsx']
|
||||
}
|
||||
/*, plugins: [
|
||||
// When you're ready to publish, check this article out.
|
||||
// http://dev.topheman.com/make-your-react-production-minified-version-with-webpack/
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
warnings: false
|
||||
},
|
||||
output: {
|
||||
comments: false
|
||||
extensions: [
|
||||
'.js'
|
||||
, '.jsx'
|
||||
]
|
||||
}
|
||||
, plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
'NODE_ENV': JSON.stringify(BUILDMODE)
|
||||
}
|
||||
})
|
||||
]*/
|
||||
]
|
||||
};
|
||||
|
||||
if (BUILDMODE === 'production') {
|
||||
webpackConfig.plugins.push(
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
mangle: true
|
||||
, compress: {
|
||||
warnings: false
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
webpackConfig.devtool = 'hidden-source-map';
|
||||
}
|
||||
|
||||
module.exports = webpackConfig;
|
||||
|
|
|
@ -1389,6 +1389,15 @@ inferno-component@^1.6.0:
|
|||
inferno-shared "^1.6.0"
|
||||
inferno-vnode-flags "^1.6.0"
|
||||
|
||||
inferno-devtools@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/inferno-devtools/-/inferno-devtools-1.6.0.tgz#869953c1d5a85fa899f9ee8405e5d93d470629d0"
|
||||
dependencies:
|
||||
inferno "^1.6.0"
|
||||
inferno-component "^1.6.0"
|
||||
inferno-shared "^1.6.0"
|
||||
inferno-vnode-flags "^1.6.0"
|
||||
|
||||
inferno-shared@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/inferno-shared/-/inferno-shared-1.6.0.tgz#8b85ec17c7140a2fe1320e556df05accc4af7145"
|
||||
|
|
Loading…
Reference in New Issue