client - thread page work
BIN
client/app/assets/Tyren.gif
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
client/app/assets/avatars/Blood_elf_female.gif
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
client/app/assets/avatars/Blood_elf_male.gif
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
client/app/assets/avatars/Draenei_female.gif
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
client/app/assets/avatars/Draenei_male.gif
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
client/app/assets/avatars/Dwarf_female.gif
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
client/app/assets/avatars/Dwarf_male.gif
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
client/app/assets/avatars/Gnome_female.gif
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
client/app/assets/avatars/Gnome_male.gif
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
client/app/assets/avatars/Human_female.gif
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
client/app/assets/avatars/Human_male.gif
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
client/app/assets/avatars/Night_elf_female.gif
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
client/app/assets/avatars/Night_elf_male.gif
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
client/app/assets/avatars/Orc_female.gif
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
client/app/assets/avatars/Orc_male.gif
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
client/app/assets/avatars/Tauren_female.gif
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
client/app/assets/avatars/Tauren_male.gif
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
client/app/assets/avatars/Troll_female.gif
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
client/app/assets/avatars/Troll_male.gif
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
client/app/assets/avatars/Undead_female.gif
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
client/app/assets/avatars/Undead_male.gif
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
client/app/assets/blizz.gif
Normal file
|
After Width: | Height: | Size: 314 B |
BIN
client/app/assets/forum-index-bot.gif
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
client/app/assets/forum-index.gif
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
client/app/assets/level-circle.gif
Normal file
|
After Width: | Height: | Size: 371 B |
BIN
client/app/assets/paging-bg.gif
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
client/app/assets/portrait-bot.gif
Normal file
|
After Width: | Height: | Size: 464 B |
BIN
client/app/assets/portrait-left.gif
Normal file
|
After Width: | Height: | Size: 313 B |
BIN
client/app/assets/portrait-right.gif
Normal file
|
After Width: | Height: | Size: 401 B |
BIN
client/app/assets/portrait-top.gif
Normal file
|
After Width: | Height: | Size: 373 B |
BIN
client/app/assets/quote-button.gif
Normal file
|
After Width: | Height: | Size: 749 B |
BIN
client/app/assets/reply-button.gif
Normal file
|
After Width: | Height: | Size: 687 B |
BIN
client/app/assets/topic-bg.gif
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
6
client/app/components/forum-nav/forum-nav.scss
Normal file
@@ -0,0 +1,6 @@
|
||||
.forum-nav {
|
||||
display: inline-block;
|
||||
padding-left: 5px;
|
||||
position: relative;
|
||||
bottom: 10;
|
||||
}
|
||||
20
client/app/components/forum-nav/forum-nav.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import React from 'react';
|
||||
import './forum-nav.scss';
|
||||
|
||||
interface Props {}
|
||||
|
||||
interface State {}
|
||||
|
||||
export class ForumNav extends React.Component<Props, State> {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<img src={require('../../assets/wow-base-general.gif')}/>
|
||||
<div className="forum-nav">
|
||||
<small>Forum Nav:</small><select style={{ minWidth: '194px' }}></select>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
export * from './content-container/content-container';
|
||||
export * from './footer/footer';
|
||||
export * from './forum-nav/forum-nav';
|
||||
export * from './header/header';
|
||||
export * from './login-button/login-button';
|
||||
export * from './portrait/portrait';
|
||||
export * from './scroll-to-top/scroll-to-top';
|
||||
|
||||
9
client/app/components/portrait/portrait.scss
Normal file
@@ -0,0 +1,9 @@
|
||||
.portrait {
|
||||
position: relative;
|
||||
|
||||
&__level-circle {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
}
|
||||
}
|
||||
29
client/app/components/portrait/portrait.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import './portrait.scss';
|
||||
|
||||
interface Props {
|
||||
imageSrc: any;
|
||||
}
|
||||
|
||||
interface State {
|
||||
}
|
||||
|
||||
export class Portrait extends React.Component<Props, State> {
|
||||
|
||||
componentDidMount() {}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="portrait">
|
||||
<img src={require('../../assets/portrait-top.gif')}/>
|
||||
<div>
|
||||
<img src={require('../../assets/level-circle.gif')} className="portrait__level-circle"/>
|
||||
<img src={require('../../assets/portrait-left.gif')}/>
|
||||
<img src={this.props.imageSrc}/>
|
||||
<img src={require('../../assets/portrait-right.gif')}/>
|
||||
</div>
|
||||
<img src={require('../../assets/portrait-bot.gif')}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
15
client/app/components/scroll-to-top/scroll-to-top.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
|
||||
export class ScrollToTop extends React.Component<any, any> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
@@ -8,13 +8,6 @@ $grey2: #161616;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.forum-nav {
|
||||
display: inline-block;
|
||||
padding-left: 5px;
|
||||
position: relative;
|
||||
bottom: 10;
|
||||
}
|
||||
|
||||
.forum-body {
|
||||
min-height: 500px;
|
||||
margin-bottom: 100px;
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { Link, RouteComponentProps } from 'react-router-dom';
|
||||
import { get } from 'lodash';
|
||||
import { ThreadService } from '../../services';
|
||||
import { LoginButton } from '../../components';
|
||||
import { ForumNav, LoginButton, ScrollToTop } from '../../components';
|
||||
import { ThreadModel } from '../../model';
|
||||
import './forum.scss';
|
||||
|
||||
@@ -32,12 +32,7 @@ export class Forum extends React.Component<Props, State> {
|
||||
renderHeader() {
|
||||
return (
|
||||
<div className="forum-header">
|
||||
<div>
|
||||
<img src={require('../../assets/wow-base-general.gif')}/>
|
||||
<div className="forum-nav">
|
||||
<small>Forum Nav:</small><select style={{ minWidth: '194px' }}></select>
|
||||
</div>
|
||||
</div>
|
||||
<ForumNav />
|
||||
<div style={{ height: '100%' }}>
|
||||
<LoginButton/>
|
||||
</div>
|
||||
@@ -115,10 +110,10 @@ export class Forum extends React.Component<Props, State> {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<ScrollToTop>
|
||||
{this.renderHeader()}
|
||||
{this.renderBody()}
|
||||
</div>
|
||||
</ScrollToTop>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Link, RouteComponentProps } from 'react-router-dom';
|
||||
import { ContentContainer } from '../../components';
|
||||
import { ContentContainer, ScrollToTop } from '../../components';
|
||||
|
||||
import './home.scss';
|
||||
|
||||
@@ -87,6 +87,7 @@ export class Home extends React.Component<Props, State> {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ScrollToTop>
|
||||
<ContentContainer>
|
||||
<img src={header_forms} />
|
||||
<div>
|
||||
@@ -169,6 +170,7 @@ export class Home extends React.Component<Props, State> {
|
||||
<hr/>
|
||||
|
||||
</ContentContainer>
|
||||
</ScrollToTop>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { chain } from 'lodash';
|
||||
import { Link, RouteComponentProps } from 'react-router-dom';
|
||||
import { CategoryService } from '../../services';
|
||||
import { CategoryModel } from '../../model';
|
||||
import { ContentContainer } from '../../components';
|
||||
import { ContentContainer, ScrollToTop } from '../../components';
|
||||
import './realms.scss';
|
||||
import header_realmforums from '../../assets/header-realmforums.gif';
|
||||
import realms_large from '../../assets/realms-large.gif';
|
||||
@@ -49,6 +49,10 @@ export class Realms extends React.Component<Props, State> {
|
||||
render() {
|
||||
const { realms } = this.state;
|
||||
|
||||
if (realms.length === 0) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
// copy list so we don't modify state
|
||||
const realmsCopy = realms.slice();
|
||||
// split realms into 3 lists
|
||||
@@ -56,7 +60,8 @@ export class Realms extends React.Component<Props, State> {
|
||||
const list2 = realmsCopy.splice(0, realmsCopy.length / 2);
|
||||
const list3 = realmsCopy;
|
||||
|
||||
return realms.length === 0 ? <div></div> : (
|
||||
return (
|
||||
<ScrollToTop>
|
||||
<ContentContainer>
|
||||
<div className="flex flex--center">
|
||||
<img src={realms_large}/>
|
||||
@@ -82,6 +87,7 @@ export class Realms extends React.Component<Props, State> {
|
||||
</ul>
|
||||
</div>
|
||||
</ContentContainer>
|
||||
</ScrollToTop>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
88
client/app/pages/thread/thread.scss
Normal file
@@ -0,0 +1,88 @@
|
||||
.topic-bg {
|
||||
background-image: url('../../assets/topic-bg.gif');
|
||||
background-repeat: repeat-x;
|
||||
height: 41px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.threadTopic-container {
|
||||
background-color: #0C0C0C;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #8C8E89 #8C8E89 #0C0C0C #0C0C0C;
|
||||
padding: 2px 10px 0 5px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.threadTopic {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.paging-bg {
|
||||
background-image: url('../../assets/paging-bg.gif');
|
||||
background-repeat: repeat-x;
|
||||
height: 25px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.reply-body {
|
||||
background-color: #000000;
|
||||
padding: 0 6px 4px 6px;
|
||||
}
|
||||
|
||||
.reply-container {
|
||||
background-color: #000000;
|
||||
padding: 2px;
|
||||
border: 1px solid #343434;
|
||||
|
||||
& + & {
|
||||
margin-top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.reply {
|
||||
display: flex;
|
||||
background-color: rgb(22, 22, 22);
|
||||
// border: 1px solid #343434;
|
||||
|
||||
&__user-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
padding: 4px;
|
||||
width: 150px;
|
||||
border-right: 1px solid #000000;
|
||||
}
|
||||
|
||||
&__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 26px;
|
||||
border-bottom: 1px solid #000000;
|
||||
padding: 0 6px;
|
||||
color: white;
|
||||
|
||||
&__button {
|
||||
cursor: pointer;
|
||||
|
||||
& + & {
|
||||
margin-left: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.forumliner-bot-bg {
|
||||
background-image: url('../../assets/forumliner-bot-bg.gif');
|
||||
background-repeat: repeat-x;
|
||||
width: 100%;
|
||||
height: 15px;
|
||||
}
|
||||
@@ -1,25 +1,106 @@
|
||||
import React from 'react';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { get } from 'lodash';
|
||||
import { ThreadService } from '../../services';
|
||||
import { ForumNav, Portrait, ScrollToTop } from '../../components';
|
||||
import { ThreadModel } from '../../model';
|
||||
import './thread.scss';
|
||||
|
||||
interface Props extends RouteComponentProps<any> {}
|
||||
|
||||
interface State {}
|
||||
interface State {
|
||||
thread?: ThreadModel;
|
||||
}
|
||||
|
||||
export class Thread extends React.Component<Props, State> {
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getThreads();
|
||||
}
|
||||
|
||||
private async getThreads() {
|
||||
const thread = await ThreadService.getThread(this.props.match.params['id']);
|
||||
console.log(thread);
|
||||
thread.replies = [thread as any, ...thread.replies]; // add the thread topic to the front of the list
|
||||
this.setState({ thread });
|
||||
}
|
||||
|
||||
renderReplies(): any {
|
||||
return this.state.thread!.replies.map((reply, index) => {
|
||||
return (
|
||||
<div className="reply-container" key={index}>
|
||||
<div className="reply">
|
||||
<div className="reply__user-container">
|
||||
<Portrait imageSrc={require('../../assets/Tyren.gif')}/>
|
||||
<div>Tyren</div>
|
||||
<div>Blizzard Poster</div>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="reply__title">
|
||||
<div>
|
||||
<b>{`${index + 1}. `}{this.state.thread!.title}</b>
|
||||
<small style={{ paddingLeft: '5px' }}>| {reply.inserted_at}</small>
|
||||
</div>
|
||||
<div>
|
||||
<img src={require('../../assets/quote-button.gif')} className="reply__title__button"/>
|
||||
<img src={require('../../assets/reply-button.gif')} className="reply__title__button"/>
|
||||
</div>
|
||||
</div>
|
||||
{/* TODO: xss sanitization */}
|
||||
<div className="reply__content">{reply.content}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private navigateForumIndex() {
|
||||
this.props.history.push(`/f/${this.state.thread!.category_id}`);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const replies = get(this.state, 'thread.replies');
|
||||
|
||||
return (
|
||||
<div></div>
|
||||
<ScrollToTop {...this.props}>
|
||||
|
||||
<div style={{ padding: '16px 0 12px 0' }}>
|
||||
<ForumNav/>
|
||||
</div>
|
||||
|
||||
<div className="topic-bg">
|
||||
<div className="threadTopic-container">
|
||||
<div className="threadTopic">
|
||||
<img src={require('../../assets/sticky.gif')} style={{ marginRight: '5px' }}/>
|
||||
<b>Topic: </b><small style={{ paddingLeft: '15px', color: 'white' }}>| 12/20/2005 1:11:44 AM PST</small>
|
||||
</div>
|
||||
</div>
|
||||
<img src={require('../../assets/forum-index.gif')}
|
||||
onClick={() => this.navigateForumIndex()}
|
||||
style={{ cursor: 'pointer' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="paging-bg"/>
|
||||
<div className="reply-body">
|
||||
{replies && this.renderReplies()}
|
||||
</div>
|
||||
<div className="paging-bg"/>
|
||||
<div className="forumliner-bot-bg"/>
|
||||
<img src={require('../../assets/forum-index-bot.gif')}
|
||||
onClick={() => this.navigateForumIndex()}
|
||||
style={{ cursor: 'pointer', float: 'right' }}
|
||||
/>
|
||||
|
||||
<div style={{ height: '200px' }}/>
|
||||
</ScrollToTop>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||