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

client - thread page work

This commit is contained in:
2018-01-10 23:45:02 -06:00
parent 8eb31b984e
commit 991e1bfe5a
45 changed files with 367 additions and 120 deletions

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -0,0 +1,6 @@
.forum-nav {
display: inline-block;
padding-left: 5px;
position: relative;
bottom: 10;
}

View 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>
);
}
}

View File

@@ -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';

View File

@@ -0,0 +1,9 @@
.portrait {
position: relative;
&__level-circle {
position: absolute;
top: 8px;
left: 8px;
}
}

View 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>
);
}
}

View 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;
}
}

View File

@@ -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;

View File

@@ -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>
);
}

View File

@@ -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>
);
}
}

View File

@@ -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>
);
}
}

View 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;
}

View File

@@ -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>
);
}
}