feat: Add MembersList component, configure Electron frontend with Vite, and establish Gitea release workflow.
Some checks failed
Build and Release / build-and-release (push) Failing after 7m35s
Some checks failed
Build and Release / build-and-release (push) Failing after 7m35s
This commit is contained in:
@@ -44,7 +44,8 @@ jobs:
|
||||
run: |
|
||||
cd Frontend/Electron
|
||||
npm run build
|
||||
xvfb-run npx electron-builder --linux --win
|
||||
npx electron-builder --linux
|
||||
xvfb-run npx electron-builder --win
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CI_TOKEN }}
|
||||
WINEDEBUG: "-all"
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
"name": "discord",
|
||||
"private": true,
|
||||
"version": "1.0.3",
|
||||
"description": "A Discord clone built with Convex, React, and Electron",
|
||||
"author": "Moyettes",
|
||||
"type": "module",
|
||||
"main": "main.cjs",
|
||||
"homepage": "./",
|
||||
|
||||
@@ -23,6 +23,7 @@ import EmojiesGreyscale from './emojies_greyscale.png';
|
||||
import TypingIcon from './typing.svg';
|
||||
import DMIcon from './dm.svg';
|
||||
import SpoilerIcon from './spoiler.svg';
|
||||
import CrownIcon from './crown.svg';
|
||||
|
||||
export {
|
||||
AddIcon,
|
||||
@@ -49,7 +50,8 @@ export {
|
||||
PinIcon,
|
||||
TypingIcon,
|
||||
DMIcon,
|
||||
SpoilerIcon
|
||||
SpoilerIcon,
|
||||
CrownIcon
|
||||
};
|
||||
|
||||
export const Icons = {
|
||||
@@ -77,5 +79,6 @@ export const Icons = {
|
||||
Pin: PinIcon,
|
||||
Typing: TypingIcon,
|
||||
DM: DMIcon,
|
||||
Spoiler: SpoilerIcon
|
||||
Spoiler: SpoilerIcon,
|
||||
Crown: CrownIcon
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { useQuery } from 'convex/react';
|
||||
import { api } from '../../../../convex/_generated/api';
|
||||
import { useOnlineUsers } from '../contexts/PresenceContext';
|
||||
import { CrownIcon } from '../assets/icons';
|
||||
|
||||
const USER_COLORS = ['#5865F2', '#EBA7CD', '#57F287', '#FEE75C', '#EB459E', '#ED4245'];
|
||||
|
||||
@@ -13,6 +14,12 @@ function getUserColor(name) {
|
||||
return USER_COLORS[Math.abs(hash) % USER_COLORS.length];
|
||||
}
|
||||
|
||||
const ColoredIcon = ({ src, color, size = '24px', style = {} }) => (
|
||||
<div style={{ width: size, height: size, overflow: 'hidden', display: 'flex', alignItems: 'center', justifyContent: 'center', ...style }}>
|
||||
<img src={src} alt="" style={color ? { width: size, height: size, transform: 'translateX(-1000px)', filter: `drop-shadow(1000px 0 0 ${color})` } : { width: size, height: size, objectFit: 'contain' }} />
|
||||
</div>
|
||||
);
|
||||
|
||||
const STATUS_COLORS = {
|
||||
online: '#3ba55c',
|
||||
idle: '#faa61a',
|
||||
@@ -38,7 +45,7 @@ const MembersList = ({ channelId, visible, onMemberClick }) => {
|
||||
const ungrouped = [];
|
||||
|
||||
onlineMembers.forEach(member => {
|
||||
const hoistedRole = member.roles.find(r => r.isHoist && r.name !== '@everyone');
|
||||
const hoistedRole = member.roles.find(r => r.isHoist && r.name !== '@everyone' && r.name !== 'Owner');
|
||||
if (hoistedRole) {
|
||||
const key = `${hoistedRole.position}_${hoistedRole.name}`;
|
||||
if (!roleGroups[key]) {
|
||||
@@ -54,8 +61,9 @@ const MembersList = ({ channelId, visible, onMemberClick }) => {
|
||||
const sortedGroups = Object.values(roleGroups).sort((a, b) => b.role.position - a.role.position);
|
||||
|
||||
const renderMember = (member) => {
|
||||
const topRole = member.roles.length > 0 ? member.roles[0] : null;
|
||||
const nameColor = topRole && topRole.name !== '@everyone' ? topRole.color : '#fff';
|
||||
const displayRole = member.roles.find(r => r.name !== '@everyone' && r.name !== 'Owner') || null;
|
||||
const nameColor = displayRole ? displayRole.color : '#fff';
|
||||
const isOwner = member.roles.some(r => r.name === 'Owner');
|
||||
const effectiveStatus = resolveStatus(member.status, member.id);
|
||||
|
||||
return (
|
||||
@@ -87,8 +95,9 @@ const MembersList = ({ channelId, visible, onMemberClick }) => {
|
||||
/>
|
||||
</div>
|
||||
<div className="member-info">
|
||||
<span className="member-name" style={{ color: nameColor }}>
|
||||
<span className="member-name" style={{ color: nameColor, display: 'flex', alignItems: 'center', gap: '4px' }}>
|
||||
{member.username}
|
||||
{isOwner && <ColoredIcon src={CrownIcon} color="var(--text-feedback-warning)" size="14px" />}
|
||||
</span>
|
||||
{member.customStatus && (
|
||||
<div style={{ fontSize: '12px', color: 'var(--text-muted)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
|
||||
@@ -11,5 +11,6 @@ export default defineConfig({
|
||||
},
|
||||
build: {
|
||||
outDir: 'dist-react',
|
||||
chunkSizeWarningLimit: 1000,
|
||||
},
|
||||
})
|
||||
|
||||
6
TODO.md
6
TODO.md
@@ -1,4 +1,4 @@
|
||||
When i scroll up one time with my scroll wheel and move my mouse it scrolls down to the start.
|
||||
|
||||
|
||||
- 955px
|
||||
|
||||
|
||||
- I want to give users the choice to update the app. Can we make updating work 2 ways. One, optional updates, i want to somehow make some updates marked as optional, where techinically older versions will still work so we dont care if they are on a older version. And some updates non optional, where we will require users to update to the latest version to continue using the app. So for example when they launch the app we will check if their is a update but we dont update the app right away. We will show a download icon like discord in the header, that will be the update.svg icon. Make the icon use this color "hsl(138.353 calc(1*38.117%) 56.275% /1);"
|
||||
Reference in New Issue
Block a user