+ {visibleReactions.map((reaction, index) => {
+ const hasUserReacted = reaction.users.some(u => u.id === user.currentUser?.id);
+ const isAnimating = animatingReactions.has(reaction.emoji);
+
+ return (
+ onReactionClick(reaction.emoji)}
+ title={reaction.users.map(u => u.username).join(", ")}
+ >
+ {reaction.emoji}
+ {reaction.count}
+
+ );
+ })}
+
+ );
+}
+
interface MessageProps {
message: MessageType;
@@ -375,7 +489,7 @@ export function Message({ message, isAuthor, onProfileClick, onContextMenu, onRe
)}
- onReactionClick?.(message.id, emoji)}
messageId={message.id}
diff --git a/frontend/src/pages/app/ui/components/chat/MessageContextMenu.tsx b/frontend/src/pages/chat/ui/right/MessageContextMenu.tsx
similarity index 99%
rename from frontend/src/pages/app/ui/components/chat/MessageContextMenu.tsx
rename to frontend/src/pages/chat/ui/right/MessageContextMenu.tsx
index 81fe39a..8405aa5 100644
--- a/frontend/src/pages/app/ui/components/chat/MessageContextMenu.tsx
+++ b/frontend/src/pages/chat/ui/right/MessageContextMenu.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect, useRef } from "react";
-import type { Message, Size2D } from "../../../core/types";
+import type { Message, Size2D } from "@/core/types";
import { EmojiMenu } from "./EmojiMenu";
interface MessageContextMenuProps {
@@ -274,7 +274,7 @@ export function MessageContextMenu({
className={`context-menu-reaction-bar ${reactionBarPosition} ${isEmojiMenuExpanded ? "expanded" : ""} ${expandUpward ? "expand-upward" : ""}`}
style={isEmojiMenuExpanded && !expandUpward ? {
position: 'fixed',
- top: `${(-(contextMenuHeight || 0) + 5)}px`,
+ top: `${(-(contextMenuHeight || 0) + 95)}px`,
width: '320px',
height: '400px',
zIndex: 1001
diff --git a/frontend/src/pages/app/ui/components/chat/MessagePanelRenderer.tsx b/frontend/src/pages/chat/ui/right/MessagePanelRenderer.tsx
similarity index 96%
rename from frontend/src/pages/app/ui/components/chat/MessagePanelRenderer.tsx
rename to frontend/src/pages/chat/ui/right/MessagePanelRenderer.tsx
index da64a2f..c9bb259 100644
--- a/frontend/src/pages/app/ui/components/chat/MessagePanelRenderer.tsx
+++ b/frontend/src/pages/chat/ui/right/MessagePanelRenderer.tsx
@@ -1,13 +1,13 @@
import { useState, useEffect, useRef } from "react";
-import { useAppState } from "../../state";
-import { MessagePanel, type MessagePanelState } from "../../panels/MessagePanel";
+import { useAppState } from "@/pages/chat/state";
+import { MessagePanel, type MessagePanelState } from "./panels/MessagePanel";
import { ChatMessages } from "./ChatMessages";
import { ChatInputWrapper } from "./ChatInputWrapper";
-import { setGlobalMessageHandler } from "../../../core/websocket";
-import type { Message, WebSocketMessage } from "../../../core/types";
-import defaultAvatar from "../../../resources/images/default-avatar.png";
-import AnimatedOpacity from "../core/animations/AnimatedOpacity";
-import type { DMPanel } from "../../panels/DMPanel";
+import { setGlobalMessageHandler } from "@/core/websocket";
+import type { Message, WebSocketMessage } from "@/core/types";
+import defaultAvatar from "@/images/default-avatar.png";
+import AnimatedOpacity from "@/core/components/animations/AnimatedOpacity";
+import type { DMPanel } from "./panels/DMPanel";
interface MessagePanelRendererProps {
panel: MessagePanel | null;
diff --git a/frontend/src/pages/app/ui/components/chat/RightPanel.tsx b/frontend/src/pages/chat/ui/right/RightPanel.tsx
similarity index 79%
rename from frontend/src/pages/app/ui/components/chat/RightPanel.tsx
rename to frontend/src/pages/chat/ui/right/RightPanel.tsx
index 05c0d46..278b091 100644
--- a/frontend/src/pages/app/ui/components/chat/RightPanel.tsx
+++ b/frontend/src/pages/chat/ui/right/RightPanel.tsx
@@ -1,4 +1,4 @@
-import { useAppState } from "../../state";
+import { useAppState } from "@/pages/chat/state";
import { MessagePanelRenderer } from "./MessagePanelRenderer";
export function RightPanel() {
diff --git a/frontend/src/pages/app/ui/components/chat/UserProfileDialog.tsx b/frontend/src/pages/chat/ui/right/UserProfileDialog.tsx
similarity index 90%
rename from frontend/src/pages/app/ui/components/chat/UserProfileDialog.tsx
rename to frontend/src/pages/chat/ui/right/UserProfileDialog.tsx
index 1f3b8eb..2e890f9 100644
--- a/frontend/src/pages/app/ui/components/chat/UserProfileDialog.tsx
+++ b/frontend/src/pages/chat/ui/right/UserProfileDialog.tsx
@@ -1,8 +1,8 @@
-import type { DialogProps } from "../../../core/types";
-import type { UserProfile } from "../../../core/types";
-import { MaterialDialog } from "../core/Dialog";
-import { formatTime } from "../../../utils/utils";
-import defaultAvatar from "../../../resources/images/default-avatar.png";
+import type { DialogProps } from "@/core/types";
+import type { UserProfile } from "@/core/types";
+import { MaterialDialog } from "@/core/components/Dialog";
+import { formatTime } from "@/utils/utils";
+import defaultAvatar from "@/images/default-avatar.png";
interface UserProfileDialogProps extends DialogProps {
userProfile: UserProfile | null;
diff --git a/frontend/src/pages/app/ui/components/chat/emojiData.ts b/frontend/src/pages/chat/ui/right/emojiData.ts
similarity index 100%
rename from frontend/src/pages/app/ui/components/chat/emojiData.ts
rename to frontend/src/pages/chat/ui/right/emojiData.ts
diff --git a/frontend/src/pages/app/ui/panels/DMPanel.ts b/frontend/src/pages/chat/ui/right/panels/DMPanel.ts
similarity index 98%
rename from frontend/src/pages/app/ui/panels/DMPanel.ts
rename to frontend/src/pages/chat/ui/right/panels/DMPanel.ts
index b528138..bfc7b47 100644
--- a/frontend/src/pages/app/ui/panels/DMPanel.ts
+++ b/frontend/src/pages/chat/ui/right/panels/DMPanel.ts
@@ -6,9 +6,9 @@ import {
sendDmWithFiles,
editDmEnvelope,
deleteDmEnvelope
-} from "../../api/dmApi";
-import type { DmEncryptedJSON, DmEnvelope, DMWebSocketMessage, EncryptedMessageJson, Message } from "../../core/types";
-import type { UserState } from "../state";
+} from "../../../../../core/api/dmApi";
+import type { DmEncryptedJSON, DmEnvelope, DMWebSocketMessage, EncryptedMessageJson, Message } from "@/core/types";
+import type { UserState } from "@/pages/chat/state";
export interface DMPanelData {
userId: number;
diff --git a/frontend/src/pages/app/ui/panels/MessagePanel.ts b/frontend/src/pages/chat/ui/right/panels/MessagePanel.ts
similarity index 99%
rename from frontend/src/pages/app/ui/panels/MessagePanel.ts
rename to frontend/src/pages/chat/ui/right/panels/MessagePanel.ts
index 53d4872..5357e16 100644
--- a/frontend/src/pages/app/ui/panels/MessagePanel.ts
+++ b/frontend/src/pages/chat/ui/right/panels/MessagePanel.ts
@@ -1,5 +1,5 @@
-import type { Message, WebSocketMessage } from "../../core/types";
-import type { UserState } from "../state";
+import type { Message, WebSocketMessage } from "@/core/types";
+import type { UserState } from "@/pages/chat/state";
export interface MessagePanelState {
id: string;
diff --git a/frontend/src/pages/app/ui/panels/PublicChatPanel.ts b/frontend/src/pages/chat/ui/right/panels/PublicChatPanel.ts
similarity index 96%
rename from frontend/src/pages/app/ui/panels/PublicChatPanel.ts
rename to frontend/src/pages/chat/ui/right/panels/PublicChatPanel.ts
index 9d3d29a..86da1d2 100644
--- a/frontend/src/pages/app/ui/panels/PublicChatPanel.ts
+++ b/frontend/src/pages/chat/ui/right/panels/PublicChatPanel.ts
@@ -1,9 +1,9 @@
import { MessagePanel } from "./MessagePanel";
-import { API_BASE_URL } from "../../core/config";
-import { getAuthHeaders } from "../../auth/api";
-import { request } from "../../core/websocket";
-import type { ChatWebSocketMessage, Message, SendMessageRequest, ReactionUpdateWebSocketMessage } from "../../core/types";
-import type { UserState } from "../state";
+import { API_BASE_URL } from "@/core/config";
+import { getAuthHeaders } from "@/core/api/authApi";
+import { request } from "@/core/websocket";
+import type { ChatWebSocketMessage, Message, SendMessageRequest, ReactionUpdateWebSocketMessage } from "@/core/types";
+import type { UserState } from "@/pages/chat/state";
export class PublicChatPanel extends MessagePanel {
private messagesLoaded: boolean = false;
diff --git a/frontend/src/pages/DownloadAppPage.tsx b/frontend/src/pages/download-app/DownloadAppPage.tsx
similarity index 97%
rename from frontend/src/pages/DownloadAppPage.tsx
rename to frontend/src/pages/download-app/DownloadAppPage.tsx
index 3e8ec2e..95f2cd3 100644
--- a/frontend/src/pages/DownloadAppPage.tsx
+++ b/frontend/src/pages/download-app/DownloadAppPage.tsx
@@ -1,3 +1,5 @@
+import "./download-app.scss";
+
export default function DownloadAppPage() {
return (
diff --git a/frontend/src/pages/app/resources/css/_download-app.scss b/frontend/src/pages/download-app/download-app.scss
similarity index 100%
rename from frontend/src/pages/app/resources/css/_download-app.scss
rename to frontend/src/pages/download-app/download-app.scss
diff --git a/frontend/src/pages/HomePage.tsx b/frontend/src/pages/home/HomePage.tsx
similarity index 99%
rename from frontend/src/pages/HomePage.tsx
rename to frontend/src/pages/home/HomePage.tsx
index 76632df..9ed2c3c 100644
--- a/frontend/src/pages/HomePage.tsx
+++ b/frontend/src/pages/home/HomePage.tsx
@@ -1,6 +1,7 @@
import { Navigate, useNavigate } from "react-router-dom";
-import { useAppState } from "./app/ui/state";
-import { isElectron } from "./app/electron/electron";
+import { useAppState } from "@/pages/chat/state";
+import { isElectron } from "@/core/electron/electron";
+import "./home.scss";
function GitHubLink({ children }: { children: React.ReactNode }) {
return (
diff --git a/frontend/src/pages/app/resources/css/_homepage.scss b/frontend/src/pages/home/home.scss
similarity index 99%
rename from frontend/src/pages/app/resources/css/_homepage.scss
rename to frontend/src/pages/home/home.scss
index 15aee92..9cd545a 100644
--- a/frontend/src/pages/app/resources/css/_homepage.scss
+++ b/frontend/src/pages/home/home.scss
@@ -1,4 +1,4 @@
-@use "common/material" as *;
+@use "../../css/material" as *;
.homepage {
min-height: 100vh;
diff --git a/frontend/src/pages/NotFoundPage.tsx b/frontend/src/pages/not-found/NotFoundPage.tsx
similarity index 98%
rename from frontend/src/pages/NotFoundPage.tsx
rename to frontend/src/pages/not-found/NotFoundPage.tsx
index 907119f..1b06839 100644
--- a/frontend/src/pages/NotFoundPage.tsx
+++ b/frontend/src/pages/not-found/NotFoundPage.tsx
@@ -1,4 +1,5 @@
import { useNavigate } from "react-router-dom";
+import "./not-found.scss";
export default function NotFoundPage() {
const navigate = useNavigate();
diff --git a/frontend/src/pages/app/resources/css/_404.scss b/frontend/src/pages/not-found/not-found.scss
similarity index 100%
rename from frontend/src/pages/app/resources/css/_404.scss
rename to frontend/src/pages/not-found/not-found.scss
diff --git a/frontend/src/pages/app/utils/crypto/asymmetric.ts b/frontend/src/utils/crypto/asymmetric.ts
similarity index 100%
rename from frontend/src/pages/app/utils/crypto/asymmetric.ts
rename to frontend/src/utils/crypto/asymmetric.ts
diff --git a/frontend/src/pages/app/utils/crypto/backup.ts b/frontend/src/utils/crypto/backup.ts
similarity index 100%
rename from frontend/src/pages/app/utils/crypto/backup.ts
rename to frontend/src/utils/crypto/backup.ts
diff --git a/frontend/src/pages/app/utils/crypto/kdf.ts b/frontend/src/utils/crypto/kdf.ts
similarity index 100%
rename from frontend/src/pages/app/utils/crypto/kdf.ts
rename to frontend/src/utils/crypto/kdf.ts
diff --git a/frontend/src/pages/app/utils/crypto/symmetric.ts b/frontend/src/utils/crypto/symmetric.ts
similarity index 100%
rename from frontend/src/pages/app/utils/crypto/symmetric.ts
rename to frontend/src/utils/crypto/symmetric.ts
diff --git a/frontend/src/pages/app/utils/material.ts b/frontend/src/utils/material.ts
similarity index 97%
rename from frontend/src/pages/app/utils/material.ts
rename to frontend/src/utils/material.ts
index a5cdb5e..7ab2607 100644
--- a/frontend/src/pages/app/utils/material.ts
+++ b/frontend/src/utils/material.ts
@@ -21,6 +21,7 @@ import 'mdui/components/top-app-bar';
import 'mdui/components/top-app-bar-title';
import 'mdui/components/switch';
import 'mdui/components/chip';
+import "mdui/mdui.css";
import { setColorScheme } from 'mdui/functions/setColorScheme.js';
diff --git a/frontend/src/pages/app/utils/notification.ts b/frontend/src/utils/notification.ts
similarity index 100%
rename from frontend/src/pages/app/utils/notification.ts
rename to frontend/src/utils/notification.ts
diff --git a/frontend/src/pages/app/utils/utils.ts b/frontend/src/utils/utils.ts
similarity index 100%
rename from frontend/src/pages/app/utils/utils.ts
rename to frontend/src/utils/utils.ts
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
index ad5ff1c..4189505 100644
--- a/frontend/tsconfig.json
+++ b/frontend/tsconfig.json
@@ -13,6 +13,12 @@
"moduleDetection": "force",
"noEmit": true,
+ /* Path mapping */
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["src/*"]
+ },
+
/* Linting */
"strict": true,
"erasableSyntaxOnly": true,
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
index bb5d989..6548add 100644
--- a/frontend/vite.config.ts
+++ b/frontend/vite.config.ts
@@ -3,6 +3,10 @@ import { createHtmlPlugin } from "vite-plugin-html";
import autoprefixer from "autoprefixer";
import electron from "vite-plugin-electron/simple";
import react from "@vitejs/plugin-react";
+import path from "path";
+import { visualizer } from 'rollup-plugin-visualizer';
+
+const outDir = process.env.VITE_ELECTRON ? "build/electron/dist" : "build/normal/dist";
const plugins: PluginOption[] = [
react(),
@@ -17,6 +21,11 @@ const plugins: PluginOption[] = [
minifyCSS: true,
minifyJS: true
}
+ }),
+ visualizer({
+ filename: `${outDir}/stats.html`,
+ open: true,
+ gzipSize: true
})
]
@@ -46,6 +55,11 @@ if (process.env.VITE_ELECTRON) {
export default defineConfig({
plugins: plugins,
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src")
+ }
+ },
server: {
host: '0.0.0.0',
port: 8301,
@@ -79,7 +93,7 @@ export default defineConfig({
},
cssMinify: true,
assetsInlineLimit: 0,
- outDir: process.env.VITE_ELECTRON ? "build/electron/dist" : "build/normal/dist",
+ outDir: outDir,
chunkSizeWarningLimit: 1024
}
});
\ No newline at end of file
diff --git a/package.json b/package.json
index 4fb02cb..c52d0e9 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "name": "FromChat",
+ "name": "fromchat",
"private": true,
"version": "0.0.0",
"type": "module",
@@ -53,6 +53,7 @@
"electron": "^38.1.2",
"husky": "^9.1.7",
"postcss": "^8.5.6",
+ "rollup-plugin-visualizer": "^6.0.4",
"sass-embedded": "^1.93.0",
"terser": "^5.44.0",
"typescript": "~5.9.2",