1
0
mirror of https://github.com/mgerb/classic-wow-forums synced 2026-01-10 09:02:50 +00:00

added client things - finished home page

This commit is contained in:
2018-01-07 00:22:53 -06:00
parent 74df75dd77
commit a9e5b185ee
98 changed files with 7303 additions and 7 deletions

2
.gitignore vendored
View File

@@ -16,3 +16,5 @@ erl_crash.dump
/config/*.secret.exs
uploads
/priv/static/*

3
client/.babelrc Normal file
View File

@@ -0,0 +1,3 @@
{
"presets": ["env", "react", "stage-0"]
}

4
client/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
.vscode
node_modules
yarn-error*
dist

6
client/.prettierrc Normal file
View File

@@ -0,0 +1,6 @@
{
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 140
}

4
client/@types/all/index.d.ts vendored Normal file
View File

@@ -0,0 +1,4 @@
// for libraries that don't have types
declare module 'this-is-a-test-module';
declare module '*.gif';
declare module '*.jpg';

17
client/README.md Normal file
View File

@@ -0,0 +1,17 @@
# Starter project for React
- [Typescript](https://www.typescriptlang.org/)
- [React 16](https://reactjs.org/)
- [React Router 4](https://reacttraining.com/react-router/)
- [Webpack 3](https://webpack.js.org/)
- [Yarn](https://yarnpkg.com/lang/en/docs/install/)
## Commands
- yarn install
- yarn start
http://localhost:8080
## Note
There is currently a bug with yarn not updating package.json when upgrading packages.
[See more here](https://github.com/yarnpkg/yarn/issues/2042#issuecomment-269601927).
I added the `update-latest` script in package.json for a temporary fix.

34
client/app/Wrapper.tsx Normal file
View File

@@ -0,0 +1,34 @@
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { Footer, Header } from './components';
import { Home, Realms } from './pages';
// styling
import './scss/index.scss';
interface Props {}
interface State {}
export default class Wrapper extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
}
public render() {
return (
<BrowserRouter>
<div>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/realms" component={Realms} />
{/* <Route component={NotFound} /> */}
</Switch>
<Footer />
</div>
</BrowserRouter>
);
}
}

6
client/app/app.tsx Normal file
View File

@@ -0,0 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Wrapper from './Wrapper';
ReactDOM.render(<Wrapper />, document.getElementById('app'));

BIN
client/app/assets/B.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
client/app/assets/bugs.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1022 B

BIN
client/app/assets/druid.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 958 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
client/app/assets/mage.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1016 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
client/app/assets/pixel.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
client/app/assets/pvp.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 B

BIN
client/app/assets/rogue.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1004 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1009 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -0,0 +1,75 @@
.content-container {
position: relative;
max-width: 766px;
padding: 20px 40px 100px;
margin: 0 auto 50px auto;
}
.border-container {
position: absolute;
background-color: rgba(0, 0, 0, 0.5);
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
}
.border {
height: 100%;
width: 135px;
position: absolute;
&__top {
background-image: url('../../assets/border-top.gif');
background-repeat: repeat-x;
width: 100%;
}
&__top-left {
background-image: url('../../assets/border-top-left.gif');
background-repeat: no-repeat;
}
&__top-right {
background-image: url('../../assets/border-top-right.gif');
background-repeat: no-repeat;
right: 0;
}
&__left {
background-image: url('../../assets/border-left.gif');
background-repeat: repeat-y;
}
&__right {
background-image: url('../../assets/border-right.gif');
background-repeat: repeat-y;
right: 0;
}
&__bottom {
background-image: url('../../assets/border-bot.gif');
background-repeat: repeat-x;
bottom: 0;
height: 62px;
width: 100%;
}
&__bottom-left {
background-image: url('../../assets/border-bot-left.gif');
background-repeat: no-repeat;
bottom: 0;
height: 192px;
width: 100%;
}
&__bottom-right {
background-image: url('../../assets/border-bot-right.gif');
background-repeat: no-repeat;
bottom: 0;
right: 0;
height: 192px;
}
}

View File

@@ -0,0 +1,31 @@
import React from 'react';
import './content-container.scss';
interface Props {}
interface State {}
export class ContentContainer extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
}
render() {
return (
<div className="content-container">
<div className="border-container">
<div className="border border__left"/>
<div className="border border__right"/>
<div className="border border__bottom"/>
<div className="border border__top"/>
<div className="border border__top-left"/>
<div className="border border__top-right"/>
<div className="border border__bottom-left"/>
<div className="border border__bottom-right"/>
</div>
{this.props.children}
</div>
);
}
}

View File

@@ -0,0 +1,8 @@
.bottom-bg {
background-image: url('../../assets/bottom-bg.gif');
background-repeat: repeat-x;
height: 46px;
display: flex;
justify-content: center;
overflow: hidden;
}

View File

@@ -0,0 +1,24 @@
import React from 'react';
import bottom_blizzlogo from '../../assets/bottom-blizzlogo.gif';
import './footer.scss';
interface Props {}
interface State {}
export class Footer extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
}
render() {
return (
<div className="bottom-bg">
<img src={bottom_blizzlogo}/>
</div>
);
}
}

View File

@@ -0,0 +1,103 @@
@import '../../scss/mixins';
$topbg_height: 100px;
.wowlogo2 {
position: absolute;
top: 8;
width: 100%;
text-align: center;
z-index: 1;
@include breakpoint(smallOrLess) {
img {
height: 80px;
}
}
}
.gold-bg {
height: 29px;
background-image: url('../../assets/gold-bg.gif');
background-repeat: repeat-x;
}
.topbg {
margin-top: -29px;
width: 50%;
height: $topbg_height;
background-repeat: repeat-x;
display: inline-block;
position: relative;
&__left {
background-image: url('../../assets/topbg-left.gif');
}
&__right {
background-image: url('../../assets/topbg-right.gif');
}
}
.gryph {
background-repeat: no-repeat;
position: absolute;
height: 100%;
width: 68px;;
top: 0;
&__left {
left: 0;
background-image: url('../../assets/gryph-left.gif');
}
&__right {
right: 0;
background-image: url('../../assets/gryph-right.gif');
}
}
.gold-border {
height: 19px;
background-image: url('../../assets/gold-border.gif');
display: flex;
justify-content: space-between;
}
.finger {
width: 97px;
height: 19px;
&__left {
background-image: url('../../assets/left-finger.gif');
background-repeat: no-repeat;
}
&__right {
background-image: url('../../assets/right-finger.gif');
background-repeat: no-repeat;
}
}
.linksbar {
height: 53px;
background-image: url('../../assets/linksbar-bg.gif');
background-repeat: repeat-x;
display: flex;
justify-content: space-between;
align-items: center;
}
.linksbar-image {
height: 53px;
width: 106px;
&__left {
background-image: url('../../assets/linksbar-left.gif');
background-repeat: no-repeat;
}
&__right {
background-image: url('../../assets/linksbar-right.gif');
background-repeat: no-repeat;
}
}

View File

@@ -0,0 +1,53 @@
import React from 'react';
import { Link } from 'react-router-dom';
import './header.scss';
import wowlogo2 from '../../assets/wowlogo2.gif';
interface Props {}
interface State {}
export class Header extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
}
render() {
return (
<div>
<div className="wowlogo2">
<Link to="/">
<img src={wowlogo2}/>
</Link>
</div>
<div style={{ height: '80px' }}>
<div className="gold-bg"/>
<div className="topbg topbg__left">
<div className="gryph gryph__left"/>
</div>
<div className="topbg topbg__right">
<div className="gryph gryph__right"/>
</div>
</div>
<div className="gold-border">
<div className="finger finger__left"/>
<div className="finger finger__right"/>
</div>
<div className="linksbar">
<div className="linksbar-image linksbar-image__left"/>
<span className="grey">
<a href="#">News</a> | <a href="#">Game Info</a> | <a href="#">Forums</a> | <a href="#">Links/Files</a> | <a href="#">Support</a>
</span>
<div className="linksbar-image linksbar-image__right"/>
</div>
</div>
);
}
}

View File

@@ -0,0 +1,3 @@
export * from './footer/footer';
export * from './header/header';
export * from './content-container/content-container';

View File

@@ -0,0 +1,62 @@
@import '../../scss/mixins';
.topic-container {
max-width: 650px;
margin-right: auto;
margin-left: auto;
}
.topic-row {
display: flex;
@include breakpoint(smallOrLess) {
flex-wrap: wrap;
}
&__classes {
flex-wrap: wrap;
}
}
.topic-item {
display: flex;
padding-left: 10px;
padding-right: 10px;
flex: 1;
margin-top: 30px;
@include breakpoint(smallOrLess) {
padding: 0;
flex: initial;
}
&__classes {
flex: 1;
display: block;
padding-right: 0;
margin-top: 0;
}
}
.classes-container {
margin-left: 15;
@include breakpoint(smallOrLess) {
margin: 0;
}
}
.item-row {
display: flex;
margin-top: 30px;
&__class {
margin-top: 15px;
}
}
.topic-item-icon {
padding-right: 5px;
height: 35;
width: auto;
}

View File

@@ -0,0 +1,174 @@
import React from 'react';
import { Link, RouteComponentProps } from 'react-router-dom';
import { ContentContainer } from '../../components';
import './home.scss';
import header_forms from '../../assets/header-forums.gif';
import support from '../../assets/support.gif';
import serverstatus from '../../assets/serverstatus.gif';
import uicustomizations from '../../assets/uicustomizations.gif';
import bugs from '../../assets/bugs.gif';
import realms from '../../assets/realms.gif';
import offtopic from '../../assets/offtopic.gif';
import suggestions from '../../assets/suggestions.gif';
import guilds from '../../assets/guilds.gif';
import roleplaying from '../../assets/roleplaying.gif';
import general from '../../assets/general.gif';
import dungeons from '../../assets/dungeons.gif';
import bullet from '../../assets/bullet.gif';
// classes
import druid from '../../assets/druid.gif';
import rogue from '../../assets/rogue.gif';
import priest from '../../assets/priest.gif';
import hunter from '../../assets/hunter.gif';
import shaman from '../../assets/shaman.gif';
import warrior from '../../assets/warrior.gif';
import mage from '../../assets/mage.gif';
import paladin from '../../assets/paladin.gif';
import warlock from '../../assets/warlock.gif';
import professions from '../../assets/professions.gif';
import pvp from '../../assets/pvp.gif';
import quests from '../../assets/quests.gif';
interface Props extends RouteComponentProps<any> {}
interface State {}
export class Home extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
}
private renderTopic(link: string, title: string, icon: any, text: string): any {
return (
<div className="topic-item">
<img className="topic-item-icon" src={icon}/>
<div>
<Link to={link}>{title}</Link>
<div>{text}</div>
</div>
</div>
);
}
private renderClass(title: string, url: string, icon: any): any {
return (
<div className="flex flex--center" style={{ flex: 1 }}>
<img className="topic-item-icon" src={icon}/>
<a href={url}>{title}</a>
</div>
);
}
private renderClasses(): any {
return (
<div className="classes-container">
<div className="item-row item-row__class">
{this.renderClass('Druid', '#', druid)}
{this.renderClass('Rogue', '#', rogue)}
{this.renderClass('Priest', '#', priest)}
</div>
<div className="item-row item-row__class">
{this.renderClass('Hunter', '#', hunter)}
{this.renderClass('Shaman', '#', shaman)}
{this.renderClass('Warrior', '#', warrior)}
</div>
<div className="item-row item-row__class">
{this.renderClass('Mage', '#', mage)}
{this.renderClass('Paladin', '#', paladin)}
{this.renderClass('Warlock', '#', warlock)}
</div>
</div>
);
}
render() {
return (
<ContentContainer>
<img src={header_forms} />
<div>
<b>Welcome to the World of Warcraft community forums!</b>
</div>
<p>
Blizzard provides the World of Warcraft community forums for its player to chat, exchange ideas, and submit feedback. Posting on
the World of Warcraft community forums requires a World of Warcraft account. Only customers are allowed to post on these forums,
but anyone can read them. Please note that you must adhere to the Forum Guidelines if you wish to post on the forums.
</p>
<div className="topic-container">
<div className="topic-row">
{this.renderTopic('#', 'Technical Support', support, `If you're experiencing technical problems playing World of Warcraft, post here for assistance.`)}
{this.renderTopic('#', 'Realm Status', serverstatus, `Collection of important messages regarding the status of the Realms.`)}
</div>
<div className="topic-row">
{this.renderTopic('#', 'UI & Macros Forum', uicustomizations, `Work with other players to create your own special custom interfaces and macros.`)}
{this.renderTopic('#', 'Bug Report Forum', bugs, `Found a bug in the game? Help us squash it by reporting it here!`)}
</div>
<hr/>
<div className="topic-row topic-row__classes">
<div className="topic-item topic-item__classes">
<div className="flex" style={{ marginBottom: '10px' }}>
<img className="topic-item-icon" src={bullet}/>
<div>
<b>Classes</b>
<div>Discuss your favorite class:</div>
</div>
</div>
{this.renderClasses()}
</div>
<div className="topic-item topic-item__classes">
<div className="item-row" style={{ minWidth: '250px' }}>
<img className="topic-item-icon" src={professions}/>
<div>
<a href="#">Professions</a>
<div>Discuss professions in detail.</div>
</div>
</div>
<div className="item-row">
<img className="topic-item-icon" src={pvp}/>
<div>
<a href="#">PvP Discussion</a>
<div>Discuss player versus player combat.</div>
</div>
</div>
<div className="item-row">
<img className="topic-item-icon" src={quests}/>
<div>
<a href="#">Quest Discussion</a>
<div>Talk about and get help with the countless quests in World of Warcraft.</div>
</div>
</div>
</div>
</div>
<div className="topic-row">
{this.renderTopic('/realms', 'Realm Forums', realms, `Discuss topics related to World of Warcraft with players on your specific Realm.`)}
{this.renderTopic('#', 'Off-topic', offtopic, `Off-topic posts of interest to the World of Warcraft community.`)}
</div>
<div className="topic-row">
{this.renderTopic('#', 'Suggestions', suggestions, `Have a suggestion for World of Warcraft? Please post it here.`)}
{this.renderTopic('#', 'Guild Recruitment', guilds, `Searching for a guild, or do you want to advertise your guild?`)}
</div>
<div className="topic-row">
{this.renderTopic('#', 'Role-Playing', roleplaying, `Pull up a chair, drink a mug of ale, meet new friends, tell stories, and role-play in this forum.`)}
{this.renderTopic('#', 'General Discussion.', general, `Discuss World of Warcraft.`)}
</div>
<div className="topic-row">
{this.renderTopic('#', 'Raid and Dungeon Discussion', dungeons, `Discuss the instance dungeons and end-game raid encounters in World of Warcraft.`)}
</div>
</div>
<hr/>
</ContentContainer>
);
}
}

View File

@@ -0,0 +1,2 @@
export * from './home/home';
export * from './realms/realms';

View File

@@ -0,0 +1,20 @@
import React from 'react';
import { ContentContainer } from '../../components';
interface Props {}
interface State {}
export class Realms extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
}
render() {
return (
<ContentContainer>
{/* TODO: */}
</ContentContainer>
);
}
}

View File

@@ -0,0 +1,8 @@
@mixin breakpoint($point) {
@if $point == smallOrLess {
@media (max-width: 420px) { @content ; }
}
@else if $point == mediumOrLess {
@media (max-width: 540px) { @content ; }
}
}

View File

@@ -0,0 +1,4 @@
@import '~font-awesome/css/font-awesome.css';
@import '~normalize.css/normalize.css';
@import './variables.scss';
@import './style.scss';

View File

@@ -0,0 +1,57 @@
html {
font-family: Arial,Helvetica,Sans-Serif;
font-size: 10pt;
color: #cccccc;
}
b {
color: #ffffff;
}
body {
background-color: black;
background-image: url('../assets/forum-bg.jpg');
background-repeat: repeat-x;
}
a {
color: #FFB019;
font-weight: bold;
font-size: 9pt;
&:hover {
color: white;
}
&:visited {
color: #B1B1B1;
}
}
hr {
background: rgb(71, 71, 71);
width: 80%;
height: 0.5px;
border: 0;
margin: 25px auto;
display: block;
clear: both;
}
.inline-block {
display: inline-block;
}
.flex {
display: flex;
}
.flex--center {
align-items: center;
}
span.grey {
font-family: Arial,Helvetica,Sans-Serif;
color: #A0A1A3;
font-size: 9pt;
}

View File

BIN
client/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

13
client/index.html Normal file
View File

@@ -0,0 +1,13 @@
<html>
<head>
<title>Classic WoW Forums</title>
<link href="https://fonts.googleapis.com/css?family=Roboto:100" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<div id="app"></div>
</body>
</html>

50
client/package.json Normal file
View File

@@ -0,0 +1,50 @@
{
"name": "react_starter",
"version": "1.0.0",
"description": "A seed for a simple react application with typescript.",
"scripts": {
"build": "webpack -p --progress --colors",
"dev": "webpack --progress --colors --watch",
"c9": "webpack-dev-server --host 0.0.0.0 --port 8080 --inline --history-api-fallback",
"start": "webpack-dev-server --inline --history-api-fallback",
"update-latest": "rm -rf node_modules && rm yarn.lock && ncu --upgrade --upgradeAll && yarn install"
},
"author": "Mitchell Gerber",
"license": "MIT",
"dependencies": {
"@types/react": "^16.0.34",
"@types/react-dom": "^16.0.3",
"@types/react-router-dom": "^4.2.3",
"autoprefixer": "^7.2.4",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"clean-webpack-plugin": "^0.1.17",
"css-loader": "^0.28.7",
"extract-text-webpack-plugin": "3.0.2",
"favicons-webpack-plugin": "^0.0.7",
"file-loader": "^1.1.6",
"font-awesome": "^4.7.0",
"html-webpack-plugin": "^2.30.1",
"node-sass": "^4.7.2",
"normalize.css": "^7.0.0",
"postcss-loader": "^2.0.9",
"prettier": "^1.9.2",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-router-dom": "^4.2.2",
"resolve-url-loader": "^2.2.1",
"sass-loader": "^6.0.6",
"style-loader": "^0.19.1",
"ts-loader": "^3.2.0",
"tslint": "^5.8.0",
"tslint-config-airbnb": "^5.4.2",
"typescript": "^2.6.2",
"url-loader": "^0.6.2",
"webpack": "3.10.0",
"webpack-dev-server": "2.9.7"
}
}

10
client/postcss.config.js Normal file
View File

@@ -0,0 +1,10 @@
const browserList = [
'last 3 versions',
'> 1%'
];
module.exports = {
plugins: [
require('autoprefixer')(browserList)
]
};

38
client/tsconfig.json Normal file
View File

@@ -0,0 +1,38 @@
{
"compilerOptions": {
"target": "es2015",
"module": "es2015",
"moduleResolution": "node",
"jsx": "react",
"allowSyntheticDefaultImports": true,
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"preserveConstEnums": true,
"allowJs": false,
"sourceMap": true,
"noImplicitReturns": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"alwaysStrict": true,
"typeRoots": [
"./node_modules/@types",
"./@types"
]
},
"filesGlob": [
"typings/index.d.ts",
"src/**/*.ts",
"src/**/*.tsx"
],
"include": [
"app"
],
"exclude": [
"android",
"ios",
"build",
"node_modules"
],
"compileOnSave": false
}

7
client/tslint.json Normal file
View File

@@ -0,0 +1,7 @@
{
"extends": "tslint-config-airbnb",
"rules": {
"import-name": false,
"max-line-length": 140
}
}

77
client/webpack.config.js Normal file
View File

@@ -0,0 +1,77 @@
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
const FaciconsWebpackPlugin = require('favicons-webpack-plugin');
module.exports = {
entry: {
app: './app/app.tsx',
vendor: ['react', 'react-dom'],
},
output: {
path: path.resolve(__dirname, '../priv/static'),
filename: '[name].[hash].js',
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: ['babel-loader'],
},
{
test: /\.ts(x)?$/,
use: ['babel-loader', 'ts-loader'],
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'postcss-loader', 'sass-loader'],
}),
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader'],
}),
},
{
test: /\.woff2?$|\.ttf$|\.eot$|\.svg$|\.gif$|\.jpg$/,
use: [
{
loader: 'file-loader',
options: {
name: 'assets/[name].[hash].[ext]',
}
},
],
},
],
},
plugins: [
new CleanWebpackPlugin(['dist'], {
verbose: true,
}),
new ExtractTextPlugin({
filename: '[name].[hash].css',
disable: false,
allChunks: true
}),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './index.html',
}),
new webpack.optimize.CommonsChunkPlugin({
name: ['vendor', 'manifest'],
minChunks: 'Infinity',
}),
new webpack.HotModuleReplacementPlugin(),
new FaciconsWebpackPlugin('./favicon.png'),
],
};

6400
client/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,7 @@ use Mix.Config
# watchers to your application. For example, we use it
# with brunch.io to recompile .js and .css sources.
config :myapp, MyAppWeb.Endpoint,
host: "0.0.0.0",
http: [port: 8080],
debug_errors: true,
code_reloader: true,

View File

@@ -5,8 +5,13 @@ defmodule MyAppWeb.PageController do
@spec index(map, map) :: any
def index(conn, _params) do
# cache index.html if prod
file = case Mix.env do
:dev -> File.read!("./priv/static/index.html")
_ ->
file = Cachex.get(:myapp, "index.html")
|> get_file
end
conn
|> html(file)

View File

@@ -1,5 +0,0 @@
<html>
<body>
Test 123
</body>
</html>