diff options
author | Dessalines <tyhou13@gmx.com> | 2019-04-08 14:46:09 -0700 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2019-04-08 14:46:09 -0700 |
commit | 70ff6381039eba97a63035392f87056a023ea36b (patch) | |
tree | 62f4c367b3644ffa166c0a980ae2ec5fdb5bde95 | |
parent | 7194289f14f2a4bb7d4419ae49541786425b5aa1 (diff) |
Loading indicators.
- Fixes #10
- Adding SVG symbols component
-rw-r--r-- | ui/src/components/communities.tsx | 80 | ||||
-rw-r--r-- | ui/src/components/community-form.tsx | 23 | ||||
-rw-r--r-- | ui/src/components/community.tsx | 16 | ||||
-rw-r--r-- | ui/src/components/login.tsx | 30 | ||||
-rw-r--r-- | ui/src/components/main.tsx | 32 | ||||
-rw-r--r-- | ui/src/components/post-form.tsx | 23 | ||||
-rw-r--r-- | ui/src/components/post-listings.tsx | 30 | ||||
-rw-r--r-- | ui/src/components/post.tsx | 10 | ||||
-rw-r--r-- | ui/src/components/symbols.tsx | 80 | ||||
-rw-r--r-- | ui/src/index.tsx | 59 | ||||
-rw-r--r-- | ui/src/main.css | 12 |
11 files changed, 255 insertions, 140 deletions
diff --git a/ui/src/components/communities.tsx b/ui/src/components/communities.tsx index b81b11cd..cf42238e 100644 --- a/ui/src/components/communities.tsx +++ b/ui/src/components/communities.tsx @@ -10,24 +10,26 @@ declare const Sortable: any; interface CommunitiesState { communities: Array<Community>; + loading: boolean; } export class Communities extends Component<any, CommunitiesState> { private subscription: Subscription; private emptyState: CommunitiesState = { - communities: [] + communities: [], + loading: true } constructor(props: any, context: any) { super(props, context); this.state = this.emptyState; this.subscription = WebSocketService.Instance.subject - .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) - .subscribe( - (msg) => this.parseMessage(msg), + .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) + .subscribe( + (msg) => this.parseMessage(msg), (err) => console.error(err), () => console.log('complete') - ); + ); WebSocketService.Instance.listCommunities(); } @@ -44,40 +46,45 @@ export class Communities extends Component<any, CommunitiesState> { render() { return ( <div class="container-fluid"> - <h4>Communities</h4> - <div class="table-responsive"> - <table id="community_table" class="table table-sm table-hover"> - <thead class="pointer"> - <tr> - <th>Name</th> - <th>Title</th> - <th>Category</th> - <th class="text-right">Subscribers</th> - <th class="text-right">Posts</th> - <th class="text-right">Comments</th> - <th></th> - </tr> - </thead> - <tbody> - {this.state.communities.map(community => + {this.state.loading ? + <h4 class=""><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h4> : + <div> + <h4>Communities</h4> + <div class="table-responsive"> + <table id="community_table" class="table table-sm table-hover"> + <thead class="pointer"> <tr> - <td><Link to={`/community/${community.id}`}>{community.name}</Link></td> - <td>{community.title}</td> - <td>{community.category_name}</td> - <td class="text-right">{community.number_of_subscribers}</td> - <td class="text-right">{community.number_of_posts}</td> - <td class="text-right">{community.number_of_comments}</td> - <td class="text-right"> - {community.subscribed - ? <button class="btn btn-sm btn-secondary" onClick={linkEvent(community.id, this.handleUnsubscribe)}>Unsubscribe</button> - : <button class="btn btn-sm btn-secondary" onClick={linkEvent(community.id, this.handleSubscribe)}>Subscribe</button> - } - </td> + <th>Name</th> + <th>Title</th> + <th>Category</th> + <th class="text-right">Subscribers</th> + <th class="text-right">Posts</th> + <th class="text-right">Comments</th> + <th></th> </tr> - )} - </tbody> - </table> + </thead> + <tbody> + {this.state.communities.map(community => + <tr> + <td><Link to={`/community/${community.id}`}>{community.name}</Link></td> + <td>{community.title}</td> + <td>{community.category_name}</td> + <td class="text-right">{community.number_of_subscribers}</td> + <td class="text-right">{community.number_of_posts}</td> + <td class="text-right">{community.number_of_comments}</td> + <td class="text-right"> + {community.subscribed ? + <button class="btn btn-sm btn-secondary" onClick={linkEvent(community.id, this.handleUnsubscribe)}>Unsubscribe</button> : + <button class="btn btn-sm btn-secondary" onClick={linkEvent(community.id, this.handleSubscribe)}>Subscribe</button> + } + </td> + </tr> + )} + </tbody> + </table> + </div> </div> + } </div> ); } @@ -109,6 +116,7 @@ export class Communities extends Component<any, CommunitiesState> { let res: ListCommunitiesResponse = msg; this.state.communities = res.communities; this.state.communities.sort((a, b) => b.number_of_subscribers - a.number_of_subscribers); + this.state.loading = false; this.setState(this.state); } else if (op == UserOperation.FollowCommunity) { let res: CommunityResponse = msg; diff --git a/ui/src/components/community-form.tsx b/ui/src/components/community-form.tsx index 6250ef9c..b5b222c6 100644 --- a/ui/src/components/community-form.tsx +++ b/ui/src/components/community-form.tsx @@ -4,6 +4,7 @@ import { retryWhen, delay, take } from 'rxjs/operators'; import { CommunityForm as CommunityFormI, UserOperation, Category, ListCategoriesResponse, CommunityResponse } from '../interfaces'; import { WebSocketService } from '../services'; import { msgOp } from '../utils'; +import * as autosize from 'autosize'; import { Community } from '../interfaces'; @@ -17,6 +18,7 @@ interface CommunityFormProps { interface CommunityFormState { communityForm: CommunityFormI; categories: Array<Category>; + loading: boolean; } export class CommunityForm extends Component<CommunityFormProps, CommunityFormState> { @@ -28,7 +30,8 @@ export class CommunityForm extends Component<CommunityFormProps, CommunityFormSt title: null, category_id: null }, - categories: [] + categories: [], + loading: false } constructor(props: any, context: any) { @@ -58,6 +61,10 @@ export class CommunityForm extends Component<CommunityFormProps, CommunityFormSt WebSocketService.Instance.listCategories(); } + componentDidMount() { + autosize(document.querySelectorAll('textarea')); + } + componentWillUnmount() { this.subscription.unsubscribe(); } @@ -81,7 +88,7 @@ export class CommunityForm extends Component<CommunityFormProps, CommunityFormSt <div class="form-group row"> <label class="col-12 col-form-label">Sidebar</label> <div class="col-12"> - <textarea value={this.state.communityForm.description} onInput={linkEvent(this, this.handleCommunityDescriptionChange)} class="form-control" rows={6} /> + <textarea value={this.state.communityForm.description} onInput={linkEvent(this, this.handleCommunityDescriptionChange)} class="form-control" rows={3} /> </div> </div> <div class="form-group row"> @@ -96,8 +103,11 @@ export class CommunityForm extends Component<CommunityFormProps, CommunityFormSt </div> <div class="form-group row"> <div class="col-12"> - <button type="submit" class="btn btn-secondary mr-2">{this.props.community ? 'Save' : 'Create'}</button> - {this.props.community && <button type="button" class="btn btn-secondary" onClick={linkEvent(this, this.handleCancel)}>Cancel</button>} + <button type="submit" class="btn btn-secondary mr-2"> + {this.state.loading ? + <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : + this.props.community ? 'Save' : 'Create'}</button> + {this.props.community && <button type="button" class="btn btn-secondary" onClick={linkEvent(this, this.handleCancel)}>Cancel</button>} </div> </div> </form> @@ -106,11 +116,13 @@ export class CommunityForm extends Component<CommunityFormProps, CommunityFormSt handleCreateCommunitySubmit(i: CommunityForm, event: any) { event.preventDefault(); + i.state.loading = true; if (i.props.community) { WebSocketService.Instance.editCommunity(i.state.communityForm); } else { WebSocketService.Instance.createCommunity(i.state.communityForm); } + i.setState(i.state); } handleCommunityNameChange(i: CommunityForm, event: any) { @@ -142,6 +154,7 @@ export class CommunityForm extends Component<CommunityFormProps, CommunityFormSt console.log(msg); if (msg.error) { alert(msg.error); + this.state.loading = false; return; } else if (op == UserOperation.ListCategories){ let res: ListCategoriesResponse = msg; @@ -150,9 +163,11 @@ export class CommunityForm extends Component<CommunityFormProps, CommunityFormSt this.setState(this.state); } else if (op == UserOperation.CreateCommunity) { let res: CommunityResponse = msg; + this.state.loading = false; this.props.onCreate(res.community.id); } else if (op == UserOperation.EditCommunity) { let res: CommunityResponse = msg; + this.state.loading = false; this.props.onEdit(res.community); } } diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx index ed693c55..1ca9a8af 100644 --- a/ui/src/components/community.tsx +++ b/ui/src/components/community.tsx @@ -11,6 +11,7 @@ interface State { community: CommunityI; communityId: number; moderators: Array<CommunityUser>; + loading: boolean; } export class Community extends Component<any, State> { @@ -31,7 +32,8 @@ export class Community extends Component<any, State> { published: null }, moderators: [], - communityId: Number(this.props.match.params.id) + communityId: Number(this.props.match.params.id), + loading: true } constructor(props: any, context: any) { @@ -40,12 +42,12 @@ export class Community extends Component<any, State> { this.state = this.emptyState; this.subscription = WebSocketService.Instance.subject - .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) - .subscribe( - (msg) => this.parseMessage(msg), + .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) + .subscribe( + (msg) => this.parseMessage(msg), (err) => console.error(err), () => console.log('complete') - ); + ); WebSocketService.Instance.getCommunity(this.state.communityId); } @@ -57,6 +59,8 @@ export class Community extends Component<any, State> { render() { return ( <div class="container"> + {this.state.loading ? + <h4><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h4> : <div class="row"> <div class="col-12 col-lg-9"> <h4>/f/{this.state.community.name}</h4> @@ -66,6 +70,7 @@ export class Community extends Component<any, State> { <Sidebar community={this.state.community} moderators={this.state.moderators} /> </div> </div> + } </div> ) } @@ -81,6 +86,7 @@ export class Community extends Component<any, State> { let res: GetCommunityResponse = msg; this.state.community = res.community; this.state.moderators = res.moderators; + this.state.loading = false; this.setState(this.state); } else if (op == UserOperation.EditCommunity) { let res: CommunityResponse = msg; diff --git a/ui/src/components/login.tsx b/ui/src/components/login.tsx index 0cb02616..2443369e 100644 --- a/ui/src/components/login.tsx +++ b/ui/src/components/login.tsx @@ -8,6 +8,8 @@ import { msgOp } from '../utils'; interface State { loginForm: LoginForm; registerForm: RegisterForm; + loginLoading: boolean; + registerLoading: boolean; } let emptyState: State = { @@ -19,7 +21,9 @@ let emptyState: State = { username: undefined, password: undefined, password_verify: undefined - } + }, + loginLoading: false, + registerLoading: false } export class Login extends Component<any, State> { @@ -31,12 +35,12 @@ export class Login extends Component<any, State> { this.state = emptyState; this.subscription = WebSocketService.Instance.subject - .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) - .subscribe( - (msg) => this.parseMessage(msg), + .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) + .subscribe( + (msg) => this.parseMessage(msg), (err) => console.error(err), () => console.log("complete") - ); + ); } componentWillUnmount() { @@ -77,7 +81,8 @@ export class Login extends Component<any, State> { </div> <div class="form-group row"> <div class="col-sm-10"> - <button type="submit" class="btn btn-secondary">Login</button> + <button type="submit" class="btn btn-secondary">{this.state.loginLoading ? + <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : 'Login'}</button> </div> </div> </form> @@ -115,7 +120,9 @@ export class Login extends Component<any, State> { </div> <div class="form-group row"> <div class="col-sm-10"> - <button type="submit" class="btn btn-secondary">Sign Up</button> + <button type="submit" class="btn btn-secondary">{this.state.registerLoading ? + <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : 'Sign Up'}</button> + </div> </div> </form> @@ -124,6 +131,8 @@ export class Login extends Component<any, State> { handleLoginSubmit(i: Login, event: any) { event.preventDefault(); + i.state.loginLoading = true; + i.setState(i.state); WebSocketService.Instance.login(i.state.loginForm); } @@ -138,6 +147,8 @@ export class Login extends Component<any, State> { } handleRegisterSubmit(i: Login, event: any) { + i.state.registerLoading = true; + i.setState(i.state); event.preventDefault(); WebSocketService.Instance.register(i.state.registerForm); } @@ -166,9 +177,14 @@ export class Login extends Component<any, State> { let op: UserOperation = msgOp(msg); if (msg.error) { alert(msg.error); + this.state.loginLoading = false; + this.state.registerLoading = false; + this.setState(this.state); return; } else { if (op == UserOperation.Register || op == UserOperation.Login) { + this.state.loginLoading = false; + this.state.registerLoading = false; let res: LoginResponse = msg; UserService.Instance.login(res); this.props.history.push('/'); diff --git a/ui/src/components/main.tsx b/ui/src/components/main.tsx index aa3c3a8c..54f185e2 100644 --- a/ui/src/components/main.tsx +++ b/ui/src/components/main.tsx @@ -9,13 +9,15 @@ import { msgOp } from '../utils'; interface State { subscribedCommunities: Array<CommunityUser>; + loading: boolean; } export class Main extends Component<any, State> { private subscription: Subscription; private emptyState: State = { - subscribedCommunities: [] + subscribedCommunities: [], + loading: true } constructor(props: any, context: any) { @@ -24,12 +26,12 @@ export class Main extends Component<any, State> { this.state = this.emptyState; this.subscription = WebSocketService.Instance.subject - .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) - .subscribe( - (msg) => this.parseMessage(msg), + .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) + .subscribe( + (msg) => this.parseMessage(msg), (err) => console.error(err), () => console.log('complete') - ); + ); if (UserService.Instance.loggedIn) { WebSocketService.Instance.getFollowedCommunities(); @@ -51,13 +53,18 @@ export class Main extends Component<any, State> { <h4>A Landing message</h4> {UserService.Instance.loggedIn && <div> - <hr /> - <h4>Subscribed forums</h4> - <ul class="list-unstyled"> - {this.state.subscribedCommunities.map(community => - <li><Link to={`/community/${community.community_id}`}>{community.community_name}</Link></li> - )} - </ul> + {this.state.loading ? + <h4 class="mt-3"><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h4> : + <div> + <hr /> + <h4>Subscribed forums</h4> + <ul class="list-unstyled"> + {this.state.subscribedCommunities.map(community => + <li><Link to={`/community/${community.community_id}`}>{community.community_name}</Link></li> + )} + </ul> + </div> + } </div> } </div> @@ -76,6 +83,7 @@ export class Main extends Component<any, State> { } else if (op == UserOperation.GetFollowedCommunities) { let res: GetFollowedCommunitiesResponse = msg; this.state.subscribedCommunities = res.communities; + this.state.loading = false; this.setState(this.state); } } diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx index 1f23cae0..9845a1b1 100644 --- a/ui/src/components/post-form.tsx +++ b/ui/src/components/post-form.tsx @@ -4,6 +4,7 @@ import { retryWhen, delay, take } from 'rxjs/operators'; import { PostForm as PostFormI, Post, PostResponse, UserOperation, Community, ListCommunitiesResponse } from '../interfaces'; import { WebSocketService } from '../services'; import { msgOp } from '../utils'; +import * as autosize from 'autosize'; interface PostFormProps { post?: Post; // If a post is given, that means this is an edit @@ -15,6 +16,7 @@ interface PostFormProps { interface PostFormState { postForm: PostFormI; communities: Array<Community>; + loading: boolean; } export class PostForm extends Component<PostFormProps, PostFormState> { @@ -26,7 +28,8 @@ export class PostForm extends Component<PostFormProps, PostFormState> { auth: null, community_id: null }, - communities: [] + communities: [], + loading: false } constructor(props: any, context: any) { @@ -56,6 +59,10 @@ export class PostForm extends Component<PostFormProps, PostFormState> { WebSocketService.Instance.listCommunities(); } + componentDidMount() { + autosize(document.querySelectorAll('textarea')); + } + componentWillUnmount() { this.subscription.unsubscribe(); } @@ -73,13 +80,13 @@ export class PostForm extends Component<PostFormProps, PostFormState> { <div class="form-group row"> <label class="col-sm-2 col-form-label">Title</label> <div class="col-sm-10"> - <textarea value={this.state.postForm.name} onInput={linkEvent(this, this.handlePostNameChange)} class="form-control" required rows={3} /> + <textarea value={this.state.postForm.name} onInput={linkEvent(this, this.handlePostNameChange)} class="form-control" required rows={2} /> </div> </div> <div class="form-group row"> <label class="col-sm-2 col-form-label">Body</label> <div class="col-sm-10"> - <textarea value={this.state.postForm.body} onInput={linkEvent(this, this.handlePostBodyChange)} class="form-control" rows={6} /> + <textarea value={this.state.postForm.body} onInput={linkEvent(this, this.handlePostBodyChange)} class="form-control" rows={4} /> </div> </div> <div class="form-group row"> @@ -94,7 +101,10 @@ export class PostForm extends Component<PostFormProps, PostFormState> { </div> <div class="form-group row"> <div class="col-sm-10"> - <button type="submit" class="btn btn-secondary mr-2">{this.props.post ? 'Save' : 'Create'}</button> + <button type="submit" class="btn btn-secondary mr-2"> + {this.state.loading ? + <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : + this.props.post ? 'Save' : 'Create'}</button> {this.props.post && <button type="button" class="btn btn-secondary" onClick={linkEvent(this, this.handleCancel)}>Cancel</button>} </div> </div> @@ -110,6 +120,8 @@ export class PostForm extends Component<PostFormProps, PostFormState> { } else { WebSocketService.Instance.createPost(i.state.postForm); } + i.state.loading = true; + i.setState(i.state); } handlePostUrlChange(i: PostForm, event: any) { @@ -139,6 +151,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> { parseMessage(msg: any) { let op: UserOperation = msgOp(msg); if (msg.error) { + this.state.loading = false; return; } else if (op == UserOperation.ListCommunities) { let res: ListCommunitiesResponse = msg; @@ -150,9 +163,11 @@ export class PostForm extends Component<PostFormProps, PostFormState> { } this.setState(this.state); } else if (op == UserOperation.CreatePost) { + this.state.loading = false; let res: PostResponse = msg; this.props.onCreate(res.post.id); } else if (op == UserOperation.EditPost) { + this.state.loading = false; let res: PostResponse = msg; this.props.onEdit(res.post); } diff --git a/ui/src/components/post-listings.tsx b/ui/src/components/post-listings.tsx index bb36cabc..ce7833b2 100644 --- a/ui/src/components/post-listings.tsx +++ b/ui/src/components/post-listings.tsx @@ -18,6 +18,7 @@ interface PostListingsState { posts: Array<Post>; sortType: SortType; type_: ListingType; + loading: boolean; } export class PostListings extends Component<PostListingsProps, PostListingsState> { @@ -44,7 +45,8 @@ export class PostListings extends Component<PostListingsProps, PostListingsState ? ListingType.Community : UserService.Instance.loggedIn ? ListingType.Subscribed - : ListingType.All + : ListingType.All, + loading: true } constructor(props: any, context: any) { @@ -77,11 +79,16 @@ export class PostListings extends Component<PostListingsProps, PostListingsState render() { return ( <div> - <div>{this.selects()}</div> - {this.state.posts.length > 0 - ? this.state.posts.map(post => - <PostListing post={post} showCommunity={!this.props.communityId}/>) - : <div>No Listings. Subscribe to some <Link to="/communities">forums</Link>.</div> + {this.state.loading ? + <h4><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h4> : + <div> + <div>{this.selects()}</div> + {this.state.posts.length > 0 + ? this.state.posts.map(post => + <PostListing post={post} showCommunity={!this.props.communityId}/>) + : <div>No Listings. Subscribe to some <Link to="/communities">forums</Link>.</div> + } + </div> } </div> ) @@ -103,11 +110,11 @@ export class PostListings extends Component<PostListingsProps, PostListingsState </select> {!this.props.communityId && UserService.Instance.loggedIn && - <select value={this.state.type_} onChange={linkEvent(this, this.handleTypeChange)} class="ml-2 custom-select w-auto"> - <option disabled>Type</option> - <option value={ListingType.All}>All</option> - <option value={ListingType.Subscribed}>Subscribed</option> - </select> + <select value={this.state.type_} onChange={linkEvent(this, this.handleTypeChange)} class="ml-2 custom-select w-auto"> + <option disabled>Type</option> + <option value={ListingType.All}>All</option> + <option value={ListingType.Subscribed}>Subscribed</option> + </select> } </div> @@ -149,6 +156,7 @@ export class PostListings extends Component<PostListingsProps, PostListingsState } else if (op == UserOperation.GetPosts) { let res: GetPostsResponse = msg; this.state.posts = res.posts; + this.state.loading = false; this.setState(this.state); } else if (op == UserOperation.CreatePostLike) { let res: CreatePostLikeResponse = msg; diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx index e8308561..f36893f6 100644 --- a/ui/src/components/post.tsx +++ b/ui/src/components/post.tsx @@ -19,6 +19,7 @@ interface PostState { moderators: Array<CommunityUser>; scrolled?: boolean; scrolled_comment_id?: number; + loading: boolean; } export class Post extends Component<any, PostState> { @@ -30,7 +31,8 @@ export class Post extends Component<any, PostState> { commentSort: CommentSortType.Hot, community: null, moderators: [], - scrolled: false + scrolled: false, + loading: true } constructor(props: any, context: any) { @@ -74,8 +76,9 @@ export class Post extends Component<any, PostState> { render() { return ( <div class="container"> - {this.state.post && - <div class="row"> + {this.state.loading ? + <h4><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h4> : + <div class="row"> <div class="col-12 col-sm-8 col-lg-7 mb-3"> <PostListing post={this.state.post} showBody showCommunity editable /> <div className="mb-2" /> @@ -202,6 +205,7 @@ export class Post extends Component<any, PostState> { this.state.comments = res.comments; this.state.community = res.community; this.state.moderators = res.moderators; + this.state.loading = false; this.setState(this.state); } else if (op == UserOperation.CreateComment) { let res: CommentResponse = msg; diff --git a/ui/src/components/symbols.tsx b/ui/src/components/symbols.tsx new file mode 100644 index 00000000..4f757dbb --- /dev/null +++ b/ui/src/components/symbols.tsx @@ -0,0 +1,80 @@ +import { Component } from 'inferno'; + +export class Symbols extends Component<any, any> { + + constructor(props: any, context: any) { + super(props, context); + } + + render() { + return ( + <svg aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <symbol id="icon-mouse" version="1.1" x="0px" y="0px" + viewBox="0 0 512 512"> + <g> + <g> + <path d="M499.059,323.505l-7.52-32.532l-70.047,16.19c1.513-11.983,2.297-24.042,2.297-36.037c0-18.334-1.801-35.785-5.316-52.19 + c29.365-12.101,55.143-28.885,69.372-45.529c17.524-20.498,25.985-46.568,23.822-73.406 + c-2.163-26.862-14.706-51.268-35.316-68.724C433.879-4.694,369.917,0.439,333.774,42.718 + c-9.546,11.168-18.318,27.381-25.379,46.649c-16.512-5.419-34.132-8.243-52.395-8.243s-35.885,2.824-52.395,8.243 + c-7.06-19.267-15.832-35.481-25.379-46.649C142.082,0.44,78.123-4.695,35.648,31.277C15.038,48.733,2.494,73.141,0.332,100.001 + c-2.161,26.838,6.297,52.907,23.822,73.406c14.229,16.644,40.006,33.427,69.372,45.529c-3.515,16.405-5.316,33.856-5.316,52.189 + c0,11.995,0.785,24.053,2.297,36.037l-70.047-16.19l-7.52,32.532l84.337,19.492c4.349,17.217,10.201,33.953,17.421,49.752 + L12.941,416.27l7.52,32.532l110.634-25.57c1.38,2.197,2.779,4.373,4.218,6.509c32.548,48.323,75.409,74.934,120.687,74.934 + c45.278,0,88.138-26.612,120.687-74.934c1.439-2.136,2.839-4.313,4.218-6.509l110.634,25.57l7.52-32.532l-101.758-23.519 + c7.221-15.799,13.072-32.535,17.421-49.752L499.059,323.505z M183.578,220.372c0-11.41,9.189-20.65,20.482-20.65 + c11.306,0,20.494,9.24,20.494,20.65c0,11.408-9.188,20.656-20.494,20.656C192.768,241.028,183.578,231.78,183.578,220.372z + M256,413.29c-29.895,0-54.216-19.471-54.216-43.403c0-23.932,24.322-43.403,54.216-43.403s54.216,19.471,54.216,43.403 + C310.216,393.819,285.895,413.29,256,413.29z M307.785,241.183c-11.402,0-20.65-9.317-20.65-20.81 + c0-11.494,9.248-20.81,20.65-20.81c11.387,0,20.635,9.317,20.635,20.81C328.422,231.866,319.173,241.183,307.785,241.183z"/> + </g> + </g> + <g> + </g> + <g> + </g> + <g> + </g> + <g> + </g> + <g> + </g> + <g> + </g> + <g> + </g> + <g> + </g> + <g> + </g> + <g> + </g> + <g> + </g> + <g> + </g> + <g> + </g> + <g> + </g> + <g> + </g> + </symbol> + <symbol id="icon-search" viewBox="0 0 32 32"> + <title>search</title> + <path d="M31.008 27.231l-7.58-6.447c-0.784-0.705-1.622-1.029-2.299-0.998 1.789-2.096 2.87-4.815 2.87-7.787 0-6.627-5.373-12-12-12s-12 5.373-12 12 5.373 12 12 12c2.972 0 5.691-1.081 7.787-2.87-0.031 0.677 0.293 1.515 0.998 2.299l6.447 7.58c1.104 1.226 2.907 1.33 4.007 0.23s0.997-2.903-0.23-4.007zM12 20c-4.418 0-8-3.582-8-8s3.582-8 8-8 8 3.582 8 8-3.582 8-8 8z"></path> + </symbol> + <symbol id="icon-github" viewBox="0 0 32 32"> + <title>github</title> + <path d="M16 0.395c-8.836 0-16 7.163-16 16 0 7.069 4.585 13.067 10.942 15.182 0.8 0.148 1.094-0.347 1.094-0.77 0-0.381-0.015-1.642-0.022-2.979-4.452 0.968-5.391-1.888-5.391-1.888-0.728-1.849-1.776-2.341-1.776-2.341-1.452-0.993 0.11-0.973 0.11-0.973 1.606 0.113 2.452 1.649 2.452 1.649 1.427 2.446 3.743 1.739 4.656 1.33 0.143-1.034 0.558-1.74 1.016-2.14-3.554-0.404-7.29-1.777-7.29-7.907 0-1.747 0.625-3.174 1.649-4.295-0.166-0.403-0.714-2.030 0.155-4.234 0 0 1.344-0.43 4.401 1.64 1.276-0.355 2.645-0.532 4.005-0.539 1.359 0.006 2.729 0.184 4.008 0.539 3.054-2.070 4.395-1.64 4.395-1.64 0.871 2.204 0.323 3.831 0.157 4.234 1.026 1.12 1.647 2.548 1.647 4.295 0 6.145-3.743 7.498-7.306 7.895 0.574 0.497 1.085 1.47 1.085 2.963 0 2.141-0.019 3.864-0.019 4.391 0 0.426 0.288 0.925 1.099 0.768 6.354-2.118 10.933-8.113 10.933-15.18 0-8.837-7.164-16-16-16z"></path> + </symbol> + <symbol id="icon-spinner" viewBox="0 0 32 32"> + <title>spinner</title> + <path d="M16 32c-4.274 0-8.292-1.664-11.314-4.686s-4.686-7.040-4.686-11.314c0-3.026 0.849-5.973 2.456-8.522 1.563-2.478 3.771-4.48 6.386-5.791l1.344 2.682c-2.126 1.065-3.922 2.693-5.192 4.708-1.305 2.069-1.994 4.462-1.994 6.922 0 7.168 5.832 13 13 13s13-5.832 13-13c0-2.459-0.69-4.853-1.994-6.922-1.271-2.015-3.066-3.643-5.192-4.708l1.344-2.682c2.615 1.31 4.824 3.313 6.386 5.791 1.607 2.549 2.456 5.495 2.456 8.522 0 4.274-1.664 8.292-4.686 11.314s-7.040 4.686-11.314 4.686z"></path> + </symbol> + </defs> + </svg> + ); + } +} diff --git a/ui/src/index.tsx b/ui/src/index.tsx index 45bae0f7..608e487a 100644 --- a/ui/src/index.tsx +++ b/ui/src/index.tsx @@ -10,6 +10,7 @@ import { Post } from './components/post'; import { Community } from './components/community'; import { Communities } from './components/communities'; import { User } from './components/user'; +import { Symbols } from './components/symbols'; import './main.css'; @@ -42,68 +43,12 @@ class Index extends Component<any, any> { <Route path={`/user/:id/:heading`} component={User} /> <Route path={`/user/:id`} component={User} /> </Switch> - {this.symbols()} + <Symbols /> </div> </HashRouter> ); } - symbols() { - return( - <symbol id="icon-mouse" version="1.1" x="0px" y="0px" - viewBox="0 0 512 512"> - <g> - <g> - <path d="M499.059,323.505l-7.52-32.532l-70.047,16.19c1.513-11.983,2.297-24.042,2.297-36.037c0-18.334-1.801-35.785-5.316-52.19 - c29.365-12.101,55.143-28.885,69.372-45.529c17.524-20.498,25.985-46.568,23.822-73.406 - c-2.163-26.862-14.706-51.268-35.316-68.724C433.879-4.694,369.917,0.439,333.774,42.718 - c-9.546,11.168-18.318,27.381-25.379,46.649c-16.512-5.419-34.132-8.243-52.395-8.243s-35.885,2.824-52.395,8.243 - c-7.06-19.267-15.832-35.481-25.379-46.649C142.082,0.44,78.123-4.695,35.648,31.277C15.038,48.733,2.494,73.141,0.332,100.001 - c-2.161,26.838,6.297,52.907,23.822,73.406c14.229,16.644,40.006,33.427,69.372,45.529c-3.515,16.405-5.316,33.856-5.316,52.189 - c0,11.995,0.785,24.053,2.297,36.037l-70.047-16.19l-7.52,32.532l84.337,19.492c4.349,17.217,10.201,33.953,17.421,49.752 - L12.941,416.27l7.52,32.532l110.634-25.57c1.38,2.197,2.779,4.373,4.218,6.509c32.548,48.323,75.409,74.934,120.687,74.934 - c45.278,0,88.138-26.612,120.687-74.934c1.439-2.136,2.839-4.313,4.218-6.509l110.634,25.57l7.52-32.532l-101.758-23.519 - c7.221-15.799,13.072-32.535,17.421-49.752L499.059,323.505z M183.578,220.372c0-11.41,9.189-20.65,20.482-20.65 - c11.306,0,20.494,9.24,20.494,20.65c0,11.408-9.188,20.656-20.494,20.656C192.768,241.028,183.578,231.78,183.578,220.372z - M256,413.29c-29.895,0-54.216-19.471-54.216-43.403c0-23.932,24.322-43.403,54.216-43.403s54.216,19.471,54.216,43.403 |