Skip to content

Commit

Permalink
✨ Added guild channel list and channel messages
Browse files Browse the repository at this point in the history
  • Loading branch information
ZickZenni committed Aug 29, 2024
1 parent 72b4b98 commit 51d1cad
Show file tree
Hide file tree
Showing 5 changed files with 327 additions and 4 deletions.
15 changes: 12 additions & 3 deletions src/renderer/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { MemoryRouter as Router, Routes, Route } from 'react-router-dom';
import Loading from './components/Loading';

// Styles
import './styles/global.css';
import './styles/vars.css';

// Components
import Titlebar from './components/Titlebar';
import HomePage from './pages/Home';
import Serverbar from './components/Serverbar';
import Loading from './components/Loading';

// Pages
import HomePage from './pages/Home';
import GuildPage from './pages/Guild';
import ChannelPage from './pages/Guild/Channel';

export default function App() {
return (
Expand All @@ -16,7 +23,9 @@ export default function App() {
<div className="app__content">
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/guild/:id" element={<GuildPage />} />
<Route path="/guild/:id" element={<GuildPage />}>
<Route path="channel/:channelId" element={<ChannelPage />} />
</Route>
</Routes>
</div>
</Router>
Expand Down
58 changes: 58 additions & 0 deletions src/renderer/pages/Guild/Channel/Channel.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.channel_page__container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}

.channel_page__chat {
width: 100%;
height: calc(100% - 130px);
}

.channel_page__messages {
display: flex;
flex-direction: column-reverse;
overflow-y: auto;
width: 100%;
height: calc(100% - 40px);
gap: 8px;
padding: 20px;
}

.channel_page__header {
width: calc(100% - 40px);
height: 90px;
background: var(--background);
padding: 20px;
flex-shrink: 0;
}

.channel_page__message {
display: flex;
gap: 7px;
width: 100%;
min-height: 64px;
}

.channel_page__message_author {
display: flex;
height: 54px;
}

.channel_page__message_avatar {
border-radius: 50%;
aspect-ratio: 1/1;
height: 100%;
filter: drop-shadow(0px 3px 1px #00000077);
}

.channel_page__message_author_name {
margin-top: 6px;
margin-bottom: 4px;
font-weight: 600;
}

.channel_page__message_content {
font-size: large;
}
83 changes: 83 additions & 0 deletions src/renderer/pages/Guild/Channel/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import Channel, { ChannelMessage } from '../../../../common/discord/channel';
import './Channel.css';

export default function ChannelPage() {
const params = useParams();
const channelId = params.channelId ?? '';
const [channel, setChannel] = useState<Channel | null>(null);
const [messages, setMessages] = useState<ChannelMessage[]>([]);

useEffect(() => {
if (channelId.length === 0) return;

const messageList = document.getElementById('channel_page_message_list');
if (messageList) {
messageList.scrollTop = messageList.scrollHeight;
}

window.electron.ipcRenderer
.invoke('DISCORD_LOAD_CHANNEL', channelId)
.then(async (data: Channel | null) => {
setChannel(data);

if (data)
setMessages(
await window.electron.ipcRenderer.invoke(
'DISCORD_GET_MESSAGES',
channelId,
),
);

return true;
})
.catch((err) => console.error(err));

window.electron.ipcRenderer.sendMessage(
'DISCORD_SET_LAST_VISITED_GUILD_CHANNEL',
channelId,
);
}, [channelId]);

if (channelId.length === 0 || channel === null) return null;

return (
<div className="channel_page__container">
<div className="channel_page__header">
<h1># {channel.name}</h1>
</div>
<div className="channel_page__chat">
<div
className="channel_page__messages hidden_scrollbar"
id="channel_page_message_list"
>
{messages.map((message) => {
return (
<div
className="channel_page__message"
key={`Message:${message.id}`}
>
<div className="channel_page__message_author">
<img
className="channel_page__message_avatar"
src={`https://cdn.discordapp.com/avatars/${message.author.id}/${message.author.avatar}.png`}
alt="Avatar Icon"
/>
</div>
<div className="channel_page__message_wrapper">
<p className="channel_page__message_author_name">
{message.author.global_name}
</p>
<p className="channel_page__message_content">
{message.content}
</p>
</div>
</div>
);
})}
</div>
</div>
</div>
);
}
51 changes: 51 additions & 0 deletions src/renderer/pages/Guild/Guild.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.guild_page__container {
width: 100%;
height: 100%;
display: flex;
}

.guild_page__channel_list {
flex-shrink: 0;
display: flex;
flex-direction: column;
width: 300px;
overflow: hidden;
height: 100%;
background: var(--background);
overflow-y: auto;
}

.guild_page__content {
width: calc(100% - 270px - 300px);
height: 100%;
}

.guild_page__member_list {
flex-shrink: 0;
display: flex;
flex-direction: column;
width: 270px;
height: 100%;
background: var(--background);
overflow-y: auto;
}

.guild_page__channel {
display: flex;
width: 100%;
height: 28px;
padding: 12px 18px;
gap: 18px;
user-select: none;
text-decoration: none;
color: var(--text);
}

.guild_page__channel:hover {
background: var(--background-bright);
}

.guild_page__channel_icon {
filter: invert(57%) sepia(0%) saturate(256%) hue-rotate(170deg)
brightness(101%) contrast(84%);
}
124 changes: 123 additions & 1 deletion src/renderer/pages/Guild/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,125 @@
import { Link, Outlet, useNavigate, useParams } from 'react-router-dom';
import { ReactNode, useEffect, useState } from 'react';

// Channel Icons
import TextChannelIcon from '../../../../assets/app/icons/channel/text-icon.svg';
import VoiceChannelIcon from '../../../../assets/app/icons/channel/volume-2.svg';
import AnnouncementChannelIcon from '../../../../assets/app/icons/channel/tv.svg';
import StageChannelIcon from '../../../../assets/app/icons/channel/radio.svg';

import './Guild.css';
import { Guild } from '../../../common/discord/guild';
import Channel, { ChannelType } from '../../../common/discord/channel';

function ChannelWrapper({
children,
channel,
}: {
children: ReactNode[];
channel: Channel;
}) {
if (channel.type !== ChannelType.GuildVoice) {
return (
<Link
to={`/guild/${channel.guildId}/channel/${channel.id}`}
key={`GuildPageChannel:${channel.id}`}
className="guild_page__channel"
>
{children}
</Link>
);
}

return (
<div key={`GuildPageChannel:${channel.id}`} className="guild_page__channel">
{children}
</div>
);
}

export default function GuildPage() {
return <div>Guild</div>;
const navigate = useNavigate();
const params = useParams();
const guildId = params.id ?? '';

// States
const [guild, setGuild] = useState<Guild | null | undefined>(undefined);

useEffect(() => {
if (guild === undefined || (guild && guild.id !== guildId)) {
// Load guild if guild id is not invalid
if (guildId.length !== 0) {
window.electron.ipcRenderer
.invoke('DISCORD_LOAD_GUILD', guildId)
.then((data) => {
setGuild(data);
return true;
})
.catch((err) => window.logger.error(err));

window.electron.ipcRenderer
.invoke('DISCORD_GET_LAST_VISITED_GUILD_CHANNEL', guildId)
.then((channel: Channel | null) => {
if (channel !== null) {
navigate(`/guild/${guildId}/channel/${channel.id}`);
}
return true;
})
.catch((err) => window.logger.error(err));
}
}

return () => {
if (guild && guildId !== guild.id) setGuild(undefined);
};
}, [guild, guildId, navigate]);

if (guildId.length === 0) return null;

// Either the guild does not exist or we are not on this guild
if (guild === null)
return <p>Server does not exist or you are not in this server!</p>;

return (
<div className="guild_page__container">
<div className="guild_page__channel_list app__item_list hidden_scrollbar">
{guild?.channels.map((channel) => {
const getIcon = () => {
switch (channel.type) {
case ChannelType.GuildVoice:
return VoiceChannelIcon;
case ChannelType.GuildAnnouncement:
return AnnouncementChannelIcon;
case ChannelType.GuildStageVoice:
return StageChannelIcon;
default:
return TextChannelIcon;
}
};
return (
<ChannelWrapper channel={channel}>
<img
className="guild_page__channel_icon"
src={getIcon()}
alt="Text Channel Icon"
/>
<p>{channel.name}</p>
</ChannelWrapper>
);
})}
</div>
<div className="guild_page__content">
<Outlet />
</div>
<div className="guild_page__member_list">
{guild?.members.map((member) => {
return (
<div key={`GuildPage:Member:${member.user_id}`}>
{member.user_id}
</div>
);
})}
</div>
</div>
);
}

0 comments on commit 51d1cad

Please sign in to comment.