add icons, tidy code, and add simple user page
This commit is contained in:
parent
92fd25265e
commit
e43030a57c
12 changed files with 117 additions and 50 deletions
|
@ -1,5 +1,6 @@
|
|||
import Message from "../Messages/Message";
|
||||
import { useRef, useEffect } from 'react';
|
||||
import { CommentDiscussionIcon } from "@primer/octicons-react";
|
||||
|
||||
export default function ChannelMessageView({messages}) {
|
||||
const invisibleBottomMessageRef = useRef();
|
||||
|
@ -11,7 +12,8 @@ export default function ChannelMessageView({messages}) {
|
|||
let messagesView = messages.map((message) => (<Message key={message._id} message={message} />));
|
||||
if (messagesView === undefined || messagesView.length <= 0)
|
||||
messagesView = (<div className='no-messages-warning'>
|
||||
<span>No messages yet...</span>
|
||||
<CommentDiscussionIcon size={64} />
|
||||
<span style={{ margin: "12px" }}>No messages yet...</span>
|
||||
</div>);
|
||||
|
||||
return <div className="message-list-card">
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
import ProfileLink from '../UI/ProfileLink'
|
||||
export default function ChannelProfileLink({ channel, size }) {
|
||||
let picture = null;
|
||||
|
||||
if (size !== "0") {
|
||||
if (channel.picture) picture = <img className={ `profile-picture profile-picture-${size}` } src={ channel.picture } alt="Profile"></img>
|
||||
else picture = <div className="profile-picture default-channel" alt="Profile">
|
||||
<span className="default-channel-styled-text">#</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
// TODO: Stop using this component and just use the ProfileLink component
|
||||
export default function ChannelProfile({ channel, size, offset=false }) {
|
||||
return (
|
||||
<ProfileLink object={ channel } size={ size } type="channel" offset={ offset } />
|
||||
<div className="profile-link">
|
||||
{ picture }
|
||||
<span className="profile-username">{ channel.title }</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -35,7 +35,10 @@ function App({ user }) {
|
|||
<Switch>
|
||||
<Route path="/login" component={ Login } />
|
||||
<Route path="/create" component={ Create } />
|
||||
<Route path="/channels/:id"
|
||||
<Route path="/channels/:channelId"
|
||||
render={() => <LoggedInMount />}
|
||||
/>
|
||||
<Route path="/user/:userId"
|
||||
render={() => <LoggedInMount />}
|
||||
/>
|
||||
|
||||
|
|
|
@ -2,15 +2,17 @@ import { useParams } from "react-router-dom";
|
|||
import Sidebar from "../UI/Sidebar";
|
||||
import ChannelView from "../Channels/ChannelView";
|
||||
import GradientBanner from "../UI/GradientBanner";
|
||||
import UserView from "../Users/UserView";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
function LoggedInMount({ gradientBannerNotificationText }) {
|
||||
const { id: channelId } = useParams();
|
||||
const { channelId, userId } = useParams();
|
||||
return <>
|
||||
<Sidebar />
|
||||
<div className="col-flex-card">
|
||||
<GradientBanner text={ gradientBannerNotificationText }/>
|
||||
{ (channelId) && <ChannelView channelId={ channelId } /> }
|
||||
{ (userId) && <UserView userId={ userId } /> }
|
||||
</div>
|
||||
</>;
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
// TODO: This is an actual, horrible mess
|
||||
export default function ProfileLink({ object, size, type, offset=true, children=null, hideName=false }) {
|
||||
let picture;
|
||||
|
||||
if (size !== "0") {
|
||||
// TODO: Make a debug error message for then the size does not exist
|
||||
const pictureClass = `profile-picture profile-picture-${size}`;
|
||||
|
||||
if (object.picture) {
|
||||
// Not actually implemented on the server and can be unsafe, this is just futureproofing
|
||||
picture = <img className={ pictureClass } src={ object.picture } alt="Profile"></img>
|
||||
} else {
|
||||
picture = <div className={`profile-picture default-${type}`} alt="Profile">
|
||||
<span className={`default-${type}-styled-text`}>{ (type === "user") ? "@" : "#" }</span>
|
||||
</div>
|
||||
}
|
||||
} else {
|
||||
picture = null;
|
||||
}
|
||||
|
||||
let classes = offset ? 'profile-link profile-link-offset-text' : 'profile-link';
|
||||
if (type === "user") classes += " darker-text";
|
||||
const title = type === 'channel' ? object.title : object.username;
|
||||
const bottomInfo = offset ? children : null;
|
||||
|
||||
return (
|
||||
<div className={ classes }>
|
||||
{ picture }
|
||||
<span className={ hideName ? "profile-username hidden" : "profile-username" }>{ title }</span>
|
||||
{ bottomInfo }
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -1,8 +1,17 @@
|
|||
import ProfileLink from '../UI/ProfileLink'
|
||||
export default function UserProfileLink({ user, size }) {
|
||||
let picture = null;
|
||||
|
||||
if (size !== "0") {
|
||||
if (user.picture) picture = <img className={ `profile-picture profile-picture-${size}` } src={ user.picture } alt="Profile"></img>
|
||||
else picture = <div className="profile-picture default-user" alt="Profile">
|
||||
<span className="default-user-styled-text">@</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
// TODO: Stop using this component and just use the ProfileLink component
|
||||
export default function UserProfile({ user, size, subtext, hideName }) {
|
||||
return (
|
||||
<ProfileLink hideName={ hideName } object={ user } size={ size } type="user" offset={ subtext !== undefined } children={ (subtext) && (<span>{ subtext }</span>) } />
|
||||
<div className="profile-link">
|
||||
{ picture }
|
||||
<span className="profile-username">{ user.username }</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
43
bfrontend/src/Components/Users/UserView.js
Normal file
43
bfrontend/src/Components/Users/UserView.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { PersonIcon, ShieldCheckIcon } from "@primer/octicons-react";
|
||||
import APIRequest from "../../API/APIRequest";
|
||||
import UserProfile from "./UserProfileLink";
|
||||
import ProfileLinkLoader from "../UI/ProfileLinkLoader";
|
||||
|
||||
export default function UserView({ userId }) {
|
||||
const [userObject, setUserObject] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
APIRequest.authenticated(`/api/v1/users/user/${userId}/info`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
}
|
||||
}).then(({ isOK, json }) => {
|
||||
if (isOK) {
|
||||
setUserObject(json.user);
|
||||
}
|
||||
});
|
||||
}, [userId]);
|
||||
|
||||
let view = null;
|
||||
if (userObject) {
|
||||
view = <>
|
||||
<UserProfile user={ userObject } size="32" />
|
||||
{(userObject.role === "ADMIN") && <ShieldCheckIcon size={24} className="profile-badge" />}
|
||||
{(userObject.role === "USER") && <PersonIcon size={24} className="profile-badge" />}
|
||||
</>
|
||||
} else {
|
||||
view = <>
|
||||
<ProfileLinkLoader />
|
||||
</>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="center grow">
|
||||
<div className="user-view center">
|
||||
{view}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -65,3 +65,16 @@
|
|||
white-space: nowrap;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.elevated-modal {
|
||||
@extend .elevated-2;
|
||||
|
||||
background-color: var(--card-accent-color-dark);
|
||||
padding: 16px;
|
||||
margin: 6px;
|
||||
border-radius: var(--elevated-modal-border-radius);
|
||||
}
|
||||
|
||||
.user-view {
|
||||
@extend .elevated-modal;
|
||||
}
|
|
@ -54,3 +54,17 @@
|
|||
height: 18px;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.profile-badge {
|
||||
margin: 16px;
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
.profile-picture {
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
margin: 5px;
|
||||
margin: 6px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-right: 6px;
|
||||
|
||||
&.default-channel {
|
||||
border-radius: 12px;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
.elevated {
|
||||
box-shadow: var(--elevation-box-shadow);
|
||||
}
|
||||
|
||||
.elevated-2 {
|
||||
box-shadow: rgba(0, 0, 0, 0.50) 0px 25px 50px -4px;
|
||||
}
|
|
@ -2,8 +2,8 @@
|
|||
--background-color: hsl(230, 12%, 15%);
|
||||
--card-accent-color: hsl(230, 12%, 18%);
|
||||
--card-accent-color-dark: hsl(230, 12%, 12%);
|
||||
--default-text-color: hsl(0, 0%, 79%);
|
||||
--darker-text-color: hsl(0, 0%, 53%);
|
||||
--default-text-color: hsl(0, 0%, 80%);
|
||||
--darker-text-color: hsl(0, 0%, 65%);
|
||||
|
||||
--default-user-background: linear-gradient(
|
||||
to bottom right,
|
||||
|
@ -18,6 +18,8 @@
|
|||
hsl(225, 35%, 40%)
|
||||
);
|
||||
|
||||
--elevated-modal-border-radius: 10px;
|
||||
|
||||
--default-scrollbar-color: var(--card-accent-color);
|
||||
--default-scrollbar-color-track: var(--background-color);
|
||||
--default-scrollbar-width: 1px;
|
||||
|
|
Loading…
Reference in a new issue