- {/* Chatbot loads chat history from backend and renders it on UI load */}
- {showBot && initialMessages === null &&
Loading chat...
}
- {showBot && initialMessages !== null && (
-
- )}
+ // React Chatbotify flow configuration
+ const flow = {
+ start: {
+ message: "Welcome to crAPI! How can I assist you today?",
+ transition: { duration: 1000 },
+ path: "check_initialization",
+ },
+ check_initialization: {
+ transition: { duration: 0 },
+ chatDisabled: true,
+ path: async (params: Params) => {
+ // Check if chatbot is already initialized
+ try {
+ const stateUrl = APIService.CHATBOT_SERVICE + "genai/state";
+ const response = await superagent
+ .get(stateUrl)
+ .set("Accept", "application/json")
+ .set("Content-Type", "application/json")
+ .set("Authorization", `Bearer ${props.accessToken}`);
+
+ const isInitialized =
+ response.body.initialized === "true" ||
+ response.body.initialized === true;
+
+ if (isInitialized) {
+ await params.injectMessage(
+ "Chatbot is already initialized! Loading chat history...",
+ );
+
+ // Fetch and display chat history
+ const chatHistory = await fetchChatHistory();
+ console.log("Chat history:", chatHistory);
+ setChatbotState((prev) => ({
+ ...prev,
+ messages: chatHistory,
+ initializationRequired: false,
+ }));
+
+ if (chatHistory.length > 0) {
+ // inject all the messages in the chat history
+ for (const message of chatHistory) {
+ await params.injectMessage(
+ message.content,
+ message.role === "user" ? "user" : "bot",
+ );
+ }
+ await params.injectMessage(
+ `Loaded ${chatHistory.length} previous messages. You can now start chatting!`,
+ );
+ }
+
+ return "chat";
+ } else {
+ await params.injectMessage(
+ "Chatbot is not initialized. Please choose an option:",
+ );
+ return "show_options";
+ }
+ } catch (err) {
+ console.error("Error checking initialization:", err);
+ await params.injectMessage(
+ "Unable to check initialization status. Please choose an option:",
+ );
+ return "show_options";
+ }
+ },
+ renderMarkdown: ["BOT"],
+ },
+ show_options: {
+ message: "What would you like to do?",
+ options: helpOptions,
+ path: "process_options",
+ },
+ process_options: {
+ transition: { duration: 0 },
+ chatDisabled: true,
+ path: async (params: Params) => {
+ switch (params.userInput) {
+ case "Initialize":
+ await params.injectMessage(
+ "Please enter your OpenAI API key to initialize the chatbot:",
+ );
+ return "initialize";
+ case "Clear":
+ await params.injectMessage("Clearing the chat history...");
+ const cleared = await clearChatHistory();
+ if (cleared) {
+ await params.injectMessage("Chat history cleared successfully!");
+ setChatbotState((prev) => ({ ...prev, messages: [] }));
+ } else {
+ await params.injectMessage(
+ "Failed to clear chat history. Please try again.",
+ );
+ }
+ return "show_options";
+ case "Help":
+ await params.injectMessage(`**crAPI Chatbot Help**
+
+**Available Commands:**
+- **Initialize**: Set up the chatbot with your OpenAI API key
+- **Clear**: Clear the chat history
+- **Help**: Show this help message
+
+**Usage:**
+1. First, initialize the chatbot with your OpenAI API key
+2. Once initialized, you can ask questions about crAPI
+3. Use the Clear option to reset your chat history
+
+What would you like to do next?`);
+ return "show_options";
+ default:
+ await params.injectMessage(
+ "Invalid option. Please choose from the available options.",
+ );
+ return "show_options";
+ }
+ },
+ renderMarkdown: ["BOT"],
+ },
+ initialize: {
+ message: "Please paste your OpenAI API key below:",
+ isSensitive: true,
+ function: async (params: Params) => {
+ const apiKey = params.userInput.trim();
+
+ if (!apiKey) {
+ await params.injectMessage(
+ "API key cannot be empty. Please enter a valid OpenAI API key:",
+ );
+ return;
+ }
+
+ await params.injectMessage("Initializing chatbot with your API key...");
+
+ const success = await handleInitialization(apiKey);
+
+ if (success) {
+ await params.injectMessage("✅ Chatbot initialized successfully!");
+
+ // Fetch chat history after successful initialization
+ const chatHistory = await fetchChatHistory();
+ setChatbotState((prev) => ({
+ ...prev,
+ messages: chatHistory,
+ initializationRequired: false,
+ }));
+
+ if (chatHistory.length > 0) {
+ await params.injectMessage(
+ `Loaded ${chatHistory.length} previous messages. You can now start chatting!`,
+ );
+ } else {
+ await params.injectMessage(
+ "Ready to chat! Ask me anything about crAPI.",
+ );
+ }
+ } else {
+ await params.injectMessage(
+ "❌ Failed to initialize chatbot. Please check your API key and try again:",
+ );
+ return;
+ }
+ },
+ path: "chat",
+ renderMarkdown: ["BOT"],
+ },
+ chat: {
+ function: async (params: Params) => {
+ const response = await handleUserMessage(params.userInput);
+ await params.injectMessage(response);
+ },
+ renderMarkdown: ["BOT"],
+ path: "chat",
+ },
+ };
+
+ const plugins = [MarkdownRenderer()];
+ // React Chatbotify settings
+ const settings = {
+ general: {
+ primaryColor: "#8b5cf6",
+ secondaryColor: "#a855f7",
+ fontFamily:
+ "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
+ embedded: false,
+ },
+ chatHistory: {
+ storageKey: `chat_history`,
+ },
+ chatWindow: {
+ showScrollbar: true,
+ showHeader: true,
+ showFooter: true,
+ showChatButton: true,
+ showChatInput: true,
+ showChatHistory: true,
+ showChatWindow: true,
+ },
+ chatInput: {
+ placeholder: "Type your message here...",
+ enabledPlaceholderText: "Type your message here...",
+ showCharacterCount: false,
+ allowNewlines: true,
+ sendButtonStyle: {
+ background: "#10b981",
+ },
+ },
+ botBubble: {
+ showAvatar: true,
+ allowMarkdown: true,
+ animate: true,
+ avatar: "🤖",
+ },
+ header: {
+ title: (
+
+
+ crAPI ChatBot
+
+
+
+ ),
+ },
+ notification: {
+ disabled: true,
+ },
+ audio: {
+ disabled: true,
+ },
+ chatButton: {
+ icon: ChatBotIcon,
+ },
+ userBubble: {
+ animate: true,
+ showAvatar: true,
+ avatar: "👤",
+ },
+ };
+
+ // Initialize component
+ useEffect(() => {
+ console.log("ChatBot component initialized");
+ }, [props.accessToken, props.isLoggedIn]);
+
+ return (
+
+
+
+
+
);
diff --git a/services/web/src/components/bot/MessageParser.tsx b/services/web/src/components/bot/MessageParser.tsx
deleted file mode 100644
index dde0219b..00000000
--- a/services/web/src/components/bot/MessageParser.tsx
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- *
- * Licensed under the Apache License, Version 2.0 (the “License”);
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an “AS IS” BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import { APIService } from "../../constants/APIConstant";
-import request from "superagent";
-
-interface State {
- initializationRequired?: boolean;
- initializing?: boolean;
- modelSelection?: boolean;
- accessToken: string;
- chatHistory: ChatMessage[];
-}
-
-export interface ChatMessage {
- role: string;
- content: string;
- id: number;
- loading?: boolean;
- terminateLoading?: boolean;
-}
-
-interface ActionProvider {
- handleHelp: (initRequired: boolean) => void;
- handleInitialize: (initRequired: boolean) => void;
- handleResetContext: (accessToken: string) => void;
- handleInitialized: (
- message: string,
- accessToken: string,
- chatHistory: ChatMessage[],
- ) => void;
- handleNotInitialized: () => void;
- handleModelSelection: (initRequired: boolean) => void;
- handleModelConfirmation: (message: string, accessToken: string) => void;
- handleChat: (message: string, accessToken: string) => void;
-}
-
-class MessageParser {
- private actionProvider: ActionProvider;
- private state: State;
-
- constructor(actionProvider: ActionProvider, state: State) {
- this.actionProvider = actionProvider;
- this.state = state;
- }
-
- async initializationRequired(): Promise<[boolean, ChatMessage[]]> {
- const stateUrl = APIService.CHATBOT_SERVICE + "genai/state";
- let initRequired = false;
- let chatHistory: ChatMessage[] = [];
- // Wait for the response
- await request
- .get(stateUrl)
- .set("Accept", "application/json")
- .set("Content-Type", "application/json")
- .set("Authorization", `Bearer ${this.state.accessToken}`)
- .then((res) => {
- console.log("I response:", res.body);
- if (res.status === 200) {
- if (res.body?.initialized === "true") {
- initRequired = false;
- if (res.body?.chat_history) {
- chatHistory = res.body?.chat_history;
- }
- } else {
- initRequired = true;
- }
- }
- })
- .catch((err) => {
- console.log("Error prefetch: ", err);
- });
-
- console.log("Initialization required:", initRequired);
- return [initRequired, chatHistory];
- }
-
- async parse(message: string): Promise
{
- console.log("State:", this.state);
- console.log("Message:", message);
- const message_l = message.toLowerCase();
- if (this.state?.initializationRequired === undefined) {
- const [initRequired, chatHistory] = await this.initializationRequired();
- this.state.initializationRequired = initRequired;
- this.state.chatHistory = chatHistory;
- console.log("State check:", this.state);
- }
- if (message_l === "help") {
- const [initRequired, chatHistory] = await this.initializationRequired();
- this.state.initializationRequired = initRequired;
- this.state.chatHistory = chatHistory;
- console.log("State help:", this.state);
- return this.actionProvider.handleHelp(this.state.initializationRequired);
- } else if (message_l === "init" || message_l === "initialize") {
- const [initRequired, chatHistory] = await this.initializationRequired();
- this.state.initializationRequired = initRequired;
- this.state.chatHistory = chatHistory;
- console.log("State init:", this.state);
- return this.actionProvider.handleInitialize(
- this.state.initializationRequired,
- );
- } else if (message_l === "model" || message_l === "models") {
- const [initRequired, chatHistory] = await this.initializationRequired();
- this.state.initializationRequired = initRequired;
- this.state.chatHistory = chatHistory;
- console.log("State help:", this.state);
- return this.actionProvider.handleModelSelection(
- this.state.initializationRequired,
- );
- } else if (
- message_l === "clear" ||
- message_l === "reset" ||
- message_l === "restart"
- ) {
- return this.actionProvider.handleResetContext(this.state.accessToken);
- } else if (this.state.initializing) {
- return this.actionProvider.handleInitialized(
- message,
- this.state.accessToken,
- this.state.chatHistory,
- );
- } else if (this.state.initializationRequired) {
- return this.actionProvider.handleNotInitialized();
- } else if (this.state.modelSelection) {
- return this.actionProvider.handleModelConfirmation(
- message,
- this.state.accessToken,
- );
- }
-
- return this.actionProvider.handleChat(message, this.state.accessToken);
- }
-}
-
-export default MessageParser;
diff --git a/services/web/src/components/bot/chatbot.css b/services/web/src/components/bot/chatbot.css
index 68a9dd16..fdeb5b5d 100644
--- a/services/web/src/components/bot/chatbot.css
+++ b/services/web/src/components/bot/chatbot.css
@@ -1,298 +1,145 @@
.app-chatbot-container {
position: fixed;
- bottom: 0;
- right: -100;
+ bottom: var(--spacing-lg);
+ left: var(--spacing-lg);
display: inline-block;
+ z-index: 1000;
}
-/* .app-chatbot-container.expanded {
- width: 50vw;
- height: 100vh;
- border-radius: 0;
- box-shadow: 2px 0 16px rgba(0,0,0,0.18);
-} */
.expand-chatbot-btn {
- background: #2898ec;
- color: #fff;
border: none;
- border-radius: 50%;
- width: 12px;
- height: 12px;
- font-size: 1.5rem;
- cursor: pointer;
- box-shadow: 0 2px 6px rgba(0,0,0,0.13);
+ outline: none;
+ position: absolute;
+ right: 40px;
+ top: 10px;
+ margin-right: 5px;
+ border-radius: 8px;
+ padding: 8px 12px;
+ color: rgb(232, 234, 237);
+ font-weight: 1000;
+ width: 32px;
+ height: 32px;
+ font-size: 30px;
display: flex;
align-items: center;
justify-content: center;
- transition: background 0.2s;
+ transition: all 0.2s ease;
+ background: transparent;
}
-.toggle-chatbot-btn {
- background: #2898ec;
- color: #fff;
+
+.expand-chatbot-btn:hover {
+ color: #ffffff;
+ transform: scale(1.05);
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ opacity: 1;
+ background-color: rgba(0, 0, 0, 0.1);
+}
+
+.expand-chatbot-btn:focus {
+ outline: none;
border: none;
- border-radius: 50%;
- width: 12px;
- height: 12px;
- font-size: 1.5rem;
- cursor: pointer;
- box-shadow: 0 2px 6px rgba(0,0,0,0.13);
+}
+
+/* Delete chat button */
+.delete-chat-btn {
+ border: none;
+ outline: none;
+ position: absolute;
+ right: 80px;
+ top: 10px;
+ margin-right: 5px;
+ border-radius: 8px;
+ padding: 8px 12px;
+ color: rgb(232, 234, 237);
+ font-weight: 1000;
+ width: 32px;
+ height: 32px;
+ font-size: 30px;
display: flex;
align-items: center;
justify-content: center;
- transition: background 0.2s;
+ transition: all 0.2s ease;
+ background: transparent;
}
-.expand-chatbot-btn:hover {
- background: #1768b3;
+.delete-chat-btn:hover {
+ color: #ffffff;
+ transform: scale(1.05);
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ opacity: 1;
+ background-color: rgba(0, 0, 0, 0.1);
}
-.react-chatbot-kit-user-chat-message-container {
- display: flex;
- margin: 15px 0;
- justify-content: flex-end;
- }
-
- .react-chatbot-kit-user-avatar-container {
- width: 40px;
- height: 40px;
- border-radius: 50%;
- margin-left: 12.5px;
- background-color: #3d4e8d;
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
- .react-chatbot-kit-user-avatar-icon {
- fill: #fff;
- width: 15px;
- height: 15px;
- }
-
- .react-chatbot-kit-chat-bot-avatar-container {
- width: 40px;
- height: 40px;
- border-radius: 50%;
- font-size: 1.2rem;
- background-color: #c1c2c0;
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
- .react-chatbot-kit-bot-avatar-icon {
- fill: #001529;
- width: 15px;
- height: 15px;
- }
-
- .react-chatbot-kit-chat-bot-avatar-letter {
- color: #1d1d1d;
- margin: 0;
- padding: 0;
- }
-
- .react-chatbot-kit-user-chat-message {
- background-color: #f1f1f1;
- padding: 10px;
- border-radius: 5px;
- font-size: 0.9rem;
- color: #585858;
- font-weight: medium;
- position: relative;
- text-align: left;
- }
-
- .react-chatbot-kit-user-chat-message-arrow {
- width: 0;
- height: 0;
- border-top: 8px solid transparent;
- border-bottom: 8px solid transparent;
- border-left: 8px solid #f1f1f1;
- position: absolute;
- right: -7px;
- top: 13px;
- }
-
- .react-chatbot-kit-chat-bot-message-container {
- display: flex;
- margin: 15px 0;
- justify-content: flex-start;
- }
-
- .react-chatbot-kit-chat-bot-message {
- background-color: #ebf1f8;
- padding: 10px;
- border-radius: 5px;
- font-size: 0.9rem;
- color: #691515;
- font-weight: medium;
- position: relative;
- width: 95%;
- margin-left: 12.5px;
- margin-right: 12.5px;
- text-align: left;
- }
-
- .react-chatbot-kit-chat-bot-message-arrow {
- width: 0;
- height: 0;
- border-top: 8px solid transparent;
- border-bottom: 8px solid transparent;
- border-right: 8px solid #ebf1f8;
- position: absolute;
- left: -7px;
- top: 13px;
- }
-
- .react-chatbot-kit-chat-bot-loading-icon-container {
- height: 17px;
- width: 25px;
- }
-
- .chatbot-loader-container {
- display: inline-block;
- width: 20%;
- justify-content: center;
- }
-
- #chatbot-loader #chatbot-loader-dot1 {
- animation: load 1s infinite;
- }
-
- #chatbot-loader #chatbot-loader-dot2 {
- animation: load 1s infinite;
- animation-delay: 0.2s;
- }
-
- #chatbot-loader #chatbot-loader-dot3 {
- animation: load 1s infinite;
- animation-delay: 0.4s;
- }
-
- @keyframes load {
- 0% {
- opacity: 0;
- }
- 50% {
- opacity: 1;
- }
- 100% {
- opacity: 0;
- }
- }
-
- .react-chatbot-kit-chat-container {
- position: absolute;
- bottom: 0;
- width: 30vw;
- z-index: 1;
- }
-
- .app-chatbot-container.expanded .react-chatbot-kit-chat-container {
- width: 50vw;
- }
-
- .react-chatbot-kit-chat-inner-container {
- height: 80vh;
- background-color: #fff;
- border-radius: 3px;
- border-radius: 5px;
- display: flex;
- flex-direction: column;
- overflow: hidden;
- }
-
- .app-chatbot-container.expanded .react-chatbot-kit-chat-inner-container {
- height: 100vh;
- }
-
- .react-chatbot-kit-chat-header {
- border-top-right-radius: 5px;
- border-top-left-radius: 5px;
- background-color: #efefef;
- font-family: Arial;
- display: block;
- align-items: center;
- font-size: 0.85rem;
- color: #514f4f;
- padding: 12.5px;
- font-weight: bold;
- }
-
- .react-chatbot-kit-chat-input-container {
- position: relative;
- width: 100%;
- display: flex;
- flex-shrink: 0;
- }
-
- .react-chatbot-kit-chat-message-container {
- padding: 0 17.5px 10px 17.5px;
- overflow-y: auto;
- flex: 1 1 auto;
- min-height: 0;
- }
+.delete-chat-btn:focus {
+ outline: none;
+ border: none;
+}
- .react-chatbot-kit-chat-input {
- width: 100%;
- padding: 12.5px;
- border: none;
- font-size: 0.85rem;
- border-top: 1px solid #d8d8d8;
- border-bottom-left-radius: 5px;
- }
+.delete-chat-btn:active {
+ transform: scale(0.95);
+}
- .react-chatbot-kit-chat-input-form {
- width: 100%;
- display: flex;
- }
- .react-chatbot-kit-chat-input::placeholder {
- color: #585858;
- }
+.expand-chatbot-btn:after {
+ content: "";
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 0;
+ height: 0;
+ background-color: rgba(0, 0, 0, 0.1);
+ border-radius: 50%;
+ opacity: 0;
+ transition: width 0.2s ease-out, height 0.2s ease-out, opacity 0.2s ease-out;
+}
- .react-chatbot-kit-chat-btn-send {
- background-color: #2898ec;
- width: 100px;
- border: none;
- color: #fff;
- border-bottom-right-radius: 5px;
- }
- .react-chatbot-kit-chat-btn-send-icon {
- fill: #fff;
- width: 15px;
- margin: 0 auto;
- }
+/* Enhanced chatbot trigger button */
+.app-chatbot-button {
+ position: fixed;
+ bottom: var(--spacing-lg);
+ left: var(--spacing-lg);
+ width: 50px;
+ height: 50px;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #8b5cf6, #a855f7);
+ border: none;
+ color: #ffffff;
+ font-size: 24px;
+ cursor: pointer;
+ box-shadow: 0 8px 24px rgba(139, 92, 246, 0.3);
+ transition: all var(--transition-normal);
+ z-index: 999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
- .react-chatbot-kit-error {
- background-color: #fff;
- border-radius: 3px;
- padding: 15px;
- }
+.app-chatbot-button:hover {
+ transform: scale(1.1) rotate(5deg);
+ box-shadow: 0 12px 32px rgba(139, 92, 246, 0.4);
+ background: linear-gradient(135deg, #7c3aed, #9333ea);
+}
- .react-chatbot-kit-error-container {
- width: 260px;
- }
+.app-chatbot-button:active {
+ transform: scale(0.95);
+}
- .react-chatbot-kit-error-header {
- font-size: 1.3rem;
- color: #1d1d1d;
- margin-bottom: 30px;
- }
+/* Expanded chatbot window styling */
+.app-chatbot-container.expanded .rcb-chat-window {
+ width: max(50vw, 500px) !important;
+ height: 90vh !important;
+ min-height: 50vh !important;
+ min-width: 500px !important;
+}
- .react-chatbot-kit-error-docs {
- display: block;
- margin: 25px auto;
- color: rgb(56, 104, 139);
- padding: 8px;
- border: 1px solid rgb(40, 152, 236);
- width: 130px;
- text-align: center;
- text-decoration: none;
- font-size: 1rem;
- }
+.rcb-bot-avatar {
+ background: fixed;
+}
+.rcb-chat-footer-container {
+ display: none;
+}
diff --git a/services/web/src/components/bot/config.tsx b/services/web/src/components/bot/config.tsx
deleted file mode 100644
index 59c9b566..00000000
--- a/services/web/src/components/bot/config.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *
- * Licensed under the Apache License, Version 2.0 (the “License”);
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an “AS IS” BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { createChatBotMessage } from "react-chatbot-kit";
-
-const botName: string = "CrapBot";
-
-interface Config {
- initialMessages: any[];
- botName: string;
- state: Record;
- customStyles: {
- botMessageBox: {
- backgroundColor: string;
- };
- chatButton: {
- backgroundColor: string;
- };
- };
-}
-
-const config: Config = {
- initialMessages: [
- createChatBotMessage(
- `Hi, Welcome to crAPI! I'm ${botName}, and I'm here to be exploited.`,
- {},
- ),
- ],
- botName,
- state: {},
- customStyles: {
- botMessageBox: {
- backgroundColor: "#376B7E",
- },
- chatButton: {
- backgroundColor: "#5ccc9d",
- },
- },
-};
-
-export default config;
diff --git a/services/web/src/components/dashboard/dashboard.css b/services/web/src/components/dashboard/dashboard.css
index 7da104d5..b1329c3b 100644
--- a/services/web/src/components/dashboard/dashboard.css
+++ b/services/web/src/components/dashboard/dashboard.css
@@ -7,8 +7,10 @@
}
.vehicle-desc {
- /* text-align: center; */
- background-color: #f0f0f0;
+ background: var(--bg-component);
+ border-radius: var(--border-radius-lg);
+ box-shadow: var(--shadow-light);
+ border: 1px solid var(--border-light);
}
.vehicle-desc .ant-descriptions-view {
@@ -16,40 +18,163 @@
}
.vehicle-desc .ant-descriptions-item-label {
- background: none;
- width: 30%;
+ background: var(--bg-secondary);
+ width: 35%;
+ font-weight: var(--font-weight-medium);
+ color: var(--text-secondary);
+ border-radius: var(--border-radius-sm) 0 0 var(--border-radius-sm);
}
+.vehicle-desc .ant-descriptions-item-content {
+ background: var(--bg-primary);
+ font-weight: var(--font-weight-medium);
+ color: var(--text-primary);
+ border-radius: 0 var(--border-radius-sm) var(--border-radius-sm) 0;
+}
.dashboard-header {
padding-left: 0;
padding-right: 0;
+ background: var(--bg-component);
+ border-radius: var(--border-radius-xl);
+ box-shadow: var(--shadow-light);
+ margin-bottom: var(--spacing-lg);
+ border: 1px solid var(--border-light);
+}
+
+.dashboard-header .ant-page-header-heading-title {
+ font-size: var(--font-size-xxl);
+ font-weight: var(--font-weight-bold);
+ background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+/* Enhanced vehicle card */
+.vehicle-card {
+ background: var(--bg-component);
+ border-radius: var(--border-radius-xl);
+ box-shadow: var(--shadow-medium);
+ border: 1px solid var(--border-light);
+ overflow: hidden;
+ transition: all var(--transition-normal);
+ position: relative;
+}
+
+.vehicle-card::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 4px;
+ background: linear-gradient(90deg, var(--primary-color), var(--accent-color));
}
+
+.vehicle-card:hover {
+ transform: translateY(-4px);
+ box-shadow: var(--shadow-heavy);
+}
+
+.vehicle-card .ant-card-meta-title {
+ margin-bottom: var(--spacing-md);
+}
+
+.vehicle-card .ant-card-body {
+ padding: var(--spacing-xl);
+}
+
.refresh-loc-btn {
- width: 400px;
- /* left: 30%; */
+ width: 100%;
+ max-width: 400px;
+ height: 48px;
+ border-radius: var(--border-radius-lg);
+ font-weight: var(--font-weight-medium);
+ background: linear-gradient(45deg, var(--accent-color), var(--accent-hover));
+ border: none;
+ color: var(--text-inverse);
+ box-shadow: var(--shadow-medium);
+ transition: all var(--transition-normal);
+ margin-top: var(--spacing-md);
+}
+
+.refresh-loc-btn:hover {
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-heavy);
+ background: linear-gradient(45deg, var(--accent-hover), var(--accent-color));
}
.map-iframe {
border: 0;
+ border-radius: var(--border-radius-lg);
+ box-shadow: var(--shadow-light);
+ transition: all var(--transition-normal);
+}
+
+.map-iframe:hover {
+ box-shadow: var(--shadow-medium);
}
.alert-msg-box {
margin: auto;
text-align: center;
+ padding: var(--spacing-xl);
+}
+
+.alert-msg-box .ant-alert {
+ border-radius: var(--border-radius-xl);
+ border: 2px solid var(--warning-color);
+ background: linear-gradient(135deg, rgba(250, 173, 20, 0.1), rgba(250, 173, 20, 0.05));
+ box-shadow: var(--shadow-medium);
}
.alert-msg-box .btn {
- color: blue;
+ color: var(--primary-color);
background-color: transparent;
border: none;
+ font-weight: var(--font-weight-medium);
+ text-decoration: underline;
+ transition: all var(--transition-normal);
+ padding: var(--spacing-xs) var(--spacing-sm);
+ border-radius: var(--border-radius-sm);
+}
+
+.alert-msg-box .btn:hover {
+ color: var(--primary-hover);
+ background-color: var(--primary-light);
+ transform: translateY(-1px);
}
.alert-header {
- font-size: larger;
- font-weight: bold;
+ font-size: var(--font-size-lg);
+ font-weight: var(--font-weight-bold);
+ color: var(--text-primary);
}
.alert-msg {
- font-size: large;
+ font-size: var(--font-size-md);
+ color: var(--text-secondary);
+ line-height: 1.6;
+}
+
+/* Enhanced button styles for dashboard */
+.dashboard-header .ant-btn {
+ height: 40px;
+ border-radius: var(--border-radius-lg);
+ font-weight: var(--font-weight-medium);
+ border: none;
+ box-shadow: var(--shadow-light);
+ transition: all var(--transition-normal);
+}
+
+.dashboard-header .ant-btn-primary {
+ background: linear-gradient(45deg, var(--primary-color), var(--primary-hover));
+}
+
+.dashboard-header .ant-btn:hover {
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-medium);
}
diff --git a/services/web/src/components/forum/forum.tsx b/services/web/src/components/forum/forum.tsx
index 4efcbb69..75ff2462 100644
--- a/services/web/src/components/forum/forum.tsx
+++ b/services/web/src/components/forum/forum.tsx
@@ -107,15 +107,15 @@ const Forum: React.FC = (props) => {
]}
/>
-
+
{posts.map((post) => (
-
+
handlePostClick(post.id)}>
-
+
{post.author.nickname}
@@ -132,25 +132,29 @@ const Forum: React.FC = (props) => {
))}
-
-
-
+
+
+
+
+
+
+
diff --git a/services/web/src/components/forum/style.css b/services/web/src/components/forum/style.css
index 0c9ac230..67d850b6 100644
--- a/services/web/src/components/forum/style.css
+++ b/services/web/src/components/forum/style.css
@@ -1,3 +1,279 @@
+/* Modern Forum Page Styling */
+.page-header {
+ padding-left: 0;
+ padding-right: 0;
+ background: linear-gradient(135deg, rgba(139, 92, 246, 0.1) 0%, rgba(168, 85, 247, 0.1) 100%);
+ border-radius: var(--border-radius-lg);
+ margin-bottom: var(--spacing-lg);
+ backdrop-filter: blur(10px);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+}
+
+/* Forum Post Cards */
+.ant-card {
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(10px);
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ border-radius: var(--border-radius-xl);
+ box-shadow: var(--shadow-elevation-medium);
+ transition: all 0.3s ease;
+ overflow: hidden;
+ position: relative;
+ margin-bottom: var(--spacing-lg);
+ cursor: pointer;
+}
+
+.ant-card::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 4px;
+ background: linear-gradient(90deg, #8b5cf6, #a855f7, #c084fc);
+ opacity: 0;
+ transition: opacity 0.3s ease;
+}
+
+.ant-card:hover {
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-elevation-high);
+ border-color: rgba(139, 92, 246, 0.3);
+}
+
+.ant-card:hover::before {
+ opacity: 1;
+}
+
+.ant-card .ant-card-body {
+ padding: var(--spacing-xl);
+}
+
+/* Post Meta Information */
+.ant-card-meta {
+ margin-bottom: var(--spacing-lg);
+}
+
+.ant-card-meta .ant-card-meta-title {
+ font-size: 18px !important;
+ font-weight: 700 !important;
+ color: #1f2937 !important;
+ line-height: 1.4 !important;
+ margin-bottom: var(--spacing-sm) !important;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ line-clamp: 2;
+ -webkit-box-orient: vertical;
+ max-height: 2.8em;
+}
+
+.ant-card-meta .ant-card-meta-avatar {
+ margin-right: var(--spacing-md);
+}
+
+.ant-card-meta .ant-avatar {
+ border: 3px solid rgba(255, 255, 255, 0.8);
+ box-shadow: var(--shadow-elevation-medium);
+ transition: all 0.3s ease;
+}
+
+.ant-card:hover .ant-avatar {
+ transform: scale(1.1);
+ box-shadow: var(--shadow-elevation-high);
+}
+
+/* Post Details */
+.ant-descriptions {
+ margin-bottom: var(--spacing-md);
+}
+
+.ant-descriptions-item-label {
+ font-weight: 600 !important;
+ color: #6b7280 !important;
+ font-size: 13px !important;
+}
+
+.ant-descriptions-item-content {
+ font-weight: 500 !important;
+ color: #374151 !important;
+ font-size: 13px !important;
+}
+
+/* Post Content */
.post-content {
- margin-top: 10px;
+ margin-top: var(--spacing-md);
+ color: #4b5563;
+ line-height: 1.6;
+ font-size: 14px;
+}
+
+.post-content .ant-typography {
+ margin-bottom: var(--spacing-sm);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: 4;
+ line-clamp: 4;
+ -webkit-box-orient: vertical;
+ max-height: 6.4em;
+}
+
+.post-content p {
+ margin-bottom: var(--spacing-xs) !important;
+ color: #6b7280;
+}
+
+/* New Post Button */
+.page-header .ant-btn {
+ background: linear-gradient(135deg, #8b5cf6 0%, #a855f7 100%);
+ border: none;
+ border-radius: var(--border-radius-lg);
+ font-weight: 600;
+ font-size: 16px;
+ height: 48px;
+ padding: 0 var(--spacing-xl);
+ box-shadow: var(--shadow-elevation-medium);
+ transition: all 0.3s ease;
+ position: relative;
+ overflow: hidden;
+}
+
+.page-header .ant-btn::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
+ transition: left 0.5s;
+}
+
+.page-header .ant-btn:hover::before {
+ left: 100%;
+}
+
+
+.page-header .ant-btn .anticon {
+ margin-right: var(--spacing-sm);
+}
+
+/* Pagination */
+.ant-row[justify="center"] {
+ margin-top: var(--spacing-xl);
+ gap: var(--spacing-lg);
+}
+
+.ant-row[justify="center"] .ant-btn {
+ height: 48px;
+ padding: 0 var(--spacing-xl);
+ background: linear-gradient(135deg, rgba(139, 92, 246, 0.1) 0%, rgba(168, 85, 247, 0.1) 100%);
+ backdrop-filter: blur(10px);
+ border: 1px solid rgba(139, 92, 246, 0.3);
+ border-radius: var(--border-radius-lg);
+ font-weight: 600;
+ transition: all 0.3s ease;
+ box-shadow: var(--shadow-elevation-low);
+}
+
+.ant-row[justify="center"] .ant-btn:disabled {
+ background: rgba(156, 163, 175, 0.1);
+ border-color: rgba(156, 163, 175, 0.2);
+ color: #9ca3af;
+}
+
+/* Layout Grid - Single Column */
+.ant-row[gutter] .ant-col {
+ width: 100%;
+ max-width: 100%;
+}
+
+/* Single Row Layout Adjustments */
+.ant-card {
+ max-width: 100%;
+ margin: 0 auto;
+}
+
+.ant-card .ant-card-body {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-md);
+}
+
+/* Responsive Design */
+@media (max-width: 1200px) {
+ .ant-card .ant-card-body {
+ padding: var(--spacing-lg);
+ }
+}
+
+@media (max-width: 768px) {
+ .page-header {
+ margin-bottom: var(--spacing-md);
+ }
+
+ .ant-card {
+ margin-bottom: var(--spacing-md);
+ }
+
+ .ant-card .ant-card-body {
+ padding: var(--spacing-md);
+ }
+
+ .ant-card-meta .ant-card-meta-title {
+ font-size: 16px !important;
+ }
+
+ .ant-descriptions-item-label,
+ .ant-descriptions-item-content {
+ font-size: 12px !important;
+ }
+
+ .post-content {
+ font-size: 13px;
+ }
+
+ .page-header .ant-btn {
+ height: 44px;
+ font-size: 15px;
+ padding: 0 var(--spacing-lg);
+ }
+
+ .ant-row[justify="center"] {
+ flex-direction: column;
+ align-items: center;
+ gap: var(--spacing-md);
+ }
+
+ .ant-row[justify="center"] .ant-btn {
+ width: 200px;
+ }
+}
+
+@media (max-width: 576px) {
+ .page-header .ant-page-header-heading-extra {
+ margin-top: var(--spacing-md);
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+
+ .page-header .ant-btn {
+ width: 100%;
+ }
+
+ .ant-card-meta .ant-card-meta-title {
+ font-size: 15px !important;
+ -webkit-line-clamp: 3;
+ line-clamp: 3;
+ max-height: 4.2em;
+ }
+
+ .post-content .ant-typography {
+ -webkit-line-clamp: 3;
+ line-clamp: 3;
+ max-height: 4.8em;
+ }
}
diff --git a/services/web/src/components/layout/layout.css b/services/web/src/components/layout/layout.css
index ccb7acfa..bef8977e 100644
--- a/services/web/src/components/layout/layout.css
+++ b/services/web/src/components/layout/layout.css
@@ -1,5 +1,29 @@
.layout-content {
- padding: 0 50px;
+ padding: var(--spacing-sm) var(--spacing-sm);
+ background: var(--bg-layout);
+ min-height: calc(100vh - 56px);
+ position: relative;
+ min-width: 50vw;
+}
+
+.layout-content::before {
+ content: '';
+ position: fixed;
+ top: 56px;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background:
+ radial-gradient(circle at 20% 50%, rgba(24, 144, 255, 0.03) 0%, transparent 50%),
+ radial-gradient(circle at 80% 20%, rgba(114, 46, 209, 0.03) 0%, transparent 50%),
+ radial-gradient(circle at 40% 80%, rgba(19, 194, 194, 0.03) 0%, transparent 50%);
+ pointer-events: none;
+ z-index: 0;
+}
+
+.layout-content > * {
+ position: relative;
+ z-index: 1;
}
.spinner {
@@ -12,4 +36,25 @@
body > iframe {
display: none;
+}
+
+/* Page container styles */
+.page-container {
+ background: transparent;
+ padding: var(--spacing-lg) 0;
+}
+
+.page-container .ant-page-header-heading-title {
+ padding: 0;
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+.page-container .ant-page-header-heading-extra {
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+.page-container .ant-layout-content {
+ background: transparent;
}
\ No newline at end of file
diff --git a/services/web/src/components/login/login.css b/services/web/src/components/login/login.css
index fe675d93..714bc612 100644
--- a/services/web/src/components/login/login.css
+++ b/services/web/src/components/login/login.css
@@ -1,37 +1,164 @@
.container {
display: flex;
- height: 91vh;
+ align-items: center;
+ justify-content: center;
+ max-height: 100vh;
width: 100%;
+ background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
+ padding: var(--spacing-sm);
+ position: relative;
+}
+
+.container::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: url('data:image/svg+xml,');
+ opacity: 0.3;
}
.alternative-style {
- color: #262c6f;
- font-size: 12px;
+ color: var(--primary-color);
+ font-size: var(--font-size-sm);
cursor: pointer;
- display: flex;
- float: right;
- box-sizing: border-box;
- padding-bottom: 2%;
+ display: inline-block;
+ padding: var(--spacing-sm) 0;
border: none;
background-color: transparent;
+ text-decoration: none;
+ font-weight: var(--font-weight-medium);
+ transition: all var(--transition-normal);
+ border-radius: var(--border-radius-sm);
+}
+
+.alternative-style:hover {
+ color: var(--primary-hover);
+ text-decoration: underline;
+ transform: translateY(-1px);
}
+
.spinner {
max-height: none !important;
}
+
.error-message {
- text-align: left;
- color: red;
- font-size: 12px;
- padding: 15px 0;
+ text-align: center;
+ color: var(--error-color);
+ font-size: var(--font-size-sm);
+ padding: var(--spacing-md) 0;
+ background-color: rgba(255, 77, 79, 0.1);
+ border: 1px solid rgba(255, 77, 79, 0.2);
+ border-radius: var(--border-radius-md);
+ margin: var(--spacing-sm) 0;
}
.form-card {
- border-radius: 5px;
- width: 30%;
+ border-radius: var(--border-radius-xl);
+ width: 100%;
+ max-width: 400px;
margin: auto;
- min-width: 400px;
+ background: var(--bg-primary);
+ box-shadow: var(--shadow-heavy);
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ backdrop-filter: blur(20px);
+ position: relative;
+ z-index: 1;
+ overflow: hidden;
+}
+
+.form-card::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 4px;
+ background: linear-gradient(90deg, var(--primary-color), var(--accent-color), var(--secondary-color));
+}
+
+.form-card .ant-card-head {
+ background: transparent;
+ border-bottom: 1px solid var(--border-light);
+ text-align: center;
+}
+
+.form-card .ant-card-head-title {
+ font-size: var(--font-size-xxl);
+ font-weight: var(--font-weight-bold);
+ color: var(--text-primary);
+ background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.form-card .ant-card-body {
+ padding: var(--spacing-xl);
}
.form-button {
width: 100%;
+ height: 48px;
+ font-size: var(--font-size-md);
+ font-weight: var(--font-weight-medium);
+ border-radius: var(--border-radius-lg);
+ background: linear-gradient(45deg, var(--primary-color), var(--primary-hover));
+ border: none;
+ box-shadow: var(--shadow-medium);
+ transition: all var(--transition-normal);
+}
+
+.form-button:hover {
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-heavy);
+ background: linear-gradient(45deg, var(--primary-hover), var(--primary-active));
+}
+
+.form-button:active {
+ transform: translateY(0);
+}
+
+/* Enhanced form inputs */
+.form-card .ant-input {
+ height: 48px;
+ border-radius: var(--border-radius-lg);
+ border: 2px solid var(--border-light);
+ padding: var(--spacing-sm) var(--spacing-md);
+ font-size: var(--font-size-md);
+ transition: all var(--transition-normal);
+}
+
+.form-card .ant-input:focus,
+.form-card .ant-input-focused {
+ border-color: var(--primary-color);
+ box-shadow: 0 0 0 3px rgba(24, 144, 255, 0.1);
+}
+
+.form-card .ant-input-password {
+ border-radius: var(--border-radius-lg);
+}
+
+.form-card .ant-form-item {
+ margin-bottom: var(--spacing-lg);
+}
+
+.form-card .ant-form-item-label {
+ font-weight: var(--font-weight-medium);
+ color: var(--text-primary);
+}
+
+/* Action buttons container */
+.form-actions {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-md);
+ margin-top: var(--spacing-lg);
+}
+
+.form-actions .alternative-style {
+ text-align: center;
+ padding: var(--spacing-sm);
}
diff --git a/services/web/src/components/login/login.tsx b/services/web/src/components/login/login.tsx
index 177935f0..7d8a9a6e 100644
--- a/services/web/src/components/login/login.tsx
+++ b/services/web/src/components/login/login.tsx
@@ -78,24 +78,28 @@ const Login: React.FC = ({
-
- {hasErrored && {errorMessage}
}
-
-
+
+
+ {hasErrored && (
+
{errorMessage}
+ )}
+
+
+
diff --git a/services/web/src/components/navBar/nav.css b/services/web/src/components/navBar/nav.css
index d6bd546b..c2848774 100644
--- a/services/web/src/components/navBar/nav.css
+++ b/services/web/src/components/navBar/nav.css
@@ -2,42 +2,101 @@
display: flex;
float: right;
align-items: center;
- justify-content: space-between;
- font-weight: 600;
- color: white;
+ gap: var(--spacing-sm);
+ font-weight: var(--font-weight-medium);
+ color: var(--text-inverse);
+ margin-left: auto;
}
.top-nav-left {
display: flex;
float: left;
align-items: center;
- justify-content: space-between;
- font-weight: 600;
- color: white;
+ gap: var(--spacing-xl);
+ font-weight: var(--font-weight-medium);
+ color: var(--text-inverse);
}
.avatar {
- background-color: white;
+ background-color: var(--bg-primary);
cursor: pointer;
+ border: 2px solid var(--primary-light);
+ transition: all var(--transition-normal);
+}
+
+.avatar:hover {
+ border-color: var(--accent-color);
+ transform: scale(1.05);
+}
+
+.profile-dropdown-trigger .avatar {
+ cursor: inherit;
+ border: 2px solid rgba(255, 255, 255, 0.3);
+}
+
+.profile-dropdown-trigger:hover .avatar {
+ border-color: rgba(255, 255, 255, 0.6);
+ transform: scale(1.05);
}
.avatarContainer {
align-items: center;
justify-content: center;
display: flex;
- height: 48px;
- width: 48px;
+ height: 44px;
+ width: 44px;
border-radius: 50%;
- transition: background-color 0.25s;
+ transition: all var(--transition-normal);
+ position: relative;
+ flex-shrink: 0;
+}
+
+.profile-dropdown-trigger .avatarContainer {
+ height: 40px;
+ width: 40px;
+}
+
+.profile-dropdown-trigger .avatarContainer:hover {
+ background-color: transparent;
}
.avatarContainer:hover {
- background-color: #1890ff;
+ background-color: rgba(255, 255, 255, 0.1);
+}
+
+.avatarContainer::before {
+ content: '';
+ position: absolute;
+ top: -2px;
+ left: -2px;
+ right: -2px;
+ bottom: -2px;
+ border-radius: 50%;
+ background: linear-gradient(45deg, var(--primary-color), var(--accent-color));
+ opacity: 0;
+ transition: opacity var(--transition-normal);
+ z-index: -1;
+}
+
+.avatarContainer:hover::before {
+ opacity: 0.3;
}
.logo-text {
- font-size: 15px;
- font-weight: bold;
+ font-size: var(--font-size-xl);
+ font-weight: var(--font-weight-bold);
+ background: linear-gradient(45deg, var(--text-inverse), var(--accent-light));
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ cursor: pointer;
+ transition: all var(--transition-normal);
+ letter-spacing: 0.5px;
+}
+
+.logo-text:hover {
+ transform: scale(1.05);
+ filter: brightness(1.2);
}
.notification {
@@ -85,10 +144,115 @@
cursor: pointer;
}
+/* Enhanced Profile Dropdown Trigger */
+.profile-dropdown-trigger {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+ cursor: pointer;
+ padding: var(--spacing-xs) var(--spacing-md);
+ border-radius: var(--border-radius-lg);
+ transition: all var(--transition-normal);
+ background: rgba(255, 255, 255, 0.08);
+ backdrop-filter: blur(10px);
+ border: 1px solid rgba(255, 255, 255, 0.15);
+ min-width: 120px;
+ position: relative;
+ overflow: hidden;
+}
+
+.profile-dropdown-trigger::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
+ transition: left var(--transition-normal);
+}
+
+.profile-dropdown-trigger:hover::before {
+ left: 100%;
+}
+
+.profile-dropdown-trigger:hover {
+ background: rgba(255, 255, 255, 0.15);
+ border-color: rgba(255, 255, 255, 0.3);
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+}
+
+.profile-dropdown-trigger:active {
+ transform: translateY(0);
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
+}
+
+.dropdown-info {
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+ gap: 2px;
+ flex: 1;
+ min-width: 0;
+}
+
+.user-name {
+ color: var(--text-inverse);
+ font-size: var(--font-size-sm);
+ font-weight: var(--font-weight-medium);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 100px;
+ line-height: 1.2;
+}
+
+.dropdown-arrow {
+ color: var(--text-inverse);
+ font-size: 12px;
+ opacity: 0.8;
+ transition: all var(--transition-normal);
+ margin-left: auto;
+ align-self: center;
+}
+
+.profile-dropdown-trigger:hover .dropdown-arrow {
+ opacity: 1;
+ transform: translateY(-1px);
+}
+
+/* Legacy nav-items for any remaining usage */
.nav-items {
- color: white;
- margin-right: 20px;
- margin-left: 20px;
+ color: var(--text-inverse);
+ margin-right: var(--spacing-lg);
+ margin-left: var(--spacing-lg);
+ cursor: pointer;
+ padding: var(--spacing-sm) var(--spacing-md);
+ border-radius: var(--border-radius-md);
+ transition: all var(--transition-normal);
+ background: rgba(255, 255, 255, 0.1);
+ min-height: 40px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border: 1px solid rgba(255, 255, 255, 0.2);
+}
+
+.nav-items:hover {
+ background-color: rgba(255, 255, 255, 0.2);
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+}
+
+/* Add greeting text styling */
+.greeting-text {
+ font-size: var(--font-size-sm);
+ font-weight: var(--font-weight-medium);
+ background: linear-gradient(45deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.7));
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
}
.card-not-body {
display: flex;
@@ -117,7 +281,125 @@
}
.navbar-button {
- color: #262c6f;
- border: none;
- font-weight: bold;
+ color: var(--text-inverse);
+ border: 2px solid rgba(255, 255, 255, 0.6);
+ font-weight: var(--font-weight-semibold);
+ background: rgba(255, 255, 255, 0.15);
+ backdrop-filter: blur(20px);
+ border-radius: var(--border-radius-lg);
+ padding: 6px var(--spacing-md);
+ transition: all var(--transition-normal);
+ font-size: var(--font-size-sm);
+ min-width: 70px;
+ text-align: center;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ position: relative;
+ overflow: hidden;
+ height: 32px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.navbar-button::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
+ transition: left var(--transition-normal);
+}
+
+.navbar-button:hover::before {
+ left: 100%;
+}
+
+.navbar-button:hover {
+ background: rgba(255, 255, 255, 0.25);
+ border-color: rgba(255, 255, 255, 0.8);
+ transform: scale(1.02);
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
+ color: var(--text-inverse);
+}
+
+.navbar-button:active {
+ transform: scale(0.98);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
+
+.navbar-button:focus {
+ outline: 2px solid rgba(255, 255, 255, 0.7);
+ outline-offset: 2px;
+}
+
+/* Specific styling for Login button */
+.navbar-button:first-of-type {
+ background: rgba(255, 255, 255, 0.2);
+ border-color: rgba(255, 255, 255, 0.7);
+}
+
+.navbar-button:first-of-type:hover {
+ background: rgba(255, 255, 255, 0.3);
+ border-color: rgba(255, 255, 255, 0.9);
+}
+
+/* Specific styling for Signup button */
+.navbar-button:last-of-type {
+ background: linear-gradient(45deg, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.2));
+ border: 2px solid var(--text-inverse);
+ font-weight: var(--font-weight-bold);
+}
+
+.navbar-button:last-of-type:hover {
+ background: linear-gradient(45deg, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.3));
+ border-color: var(--text-inverse);
+ box-shadow: 0 8px 20px rgba(255, 255, 255, 0.1);
+}
+
+/* Enhanced Dropdown Menu Styling */
+.ant-dropdown-menu {
+ background: rgba(255, 255, 255, 0.95) !important;
+ backdrop-filter: blur(20px) !important;
+ border: 1px solid rgba(255, 255, 255, 0.2) !important;
+ border-radius: var(--border-radius-lg) !important;
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.15) !important;
+ padding: var(--spacing-sm) !important;
+ min-width: 200px !important;
+}
+
+.ant-dropdown-menu-item {
+ padding: var(--spacing-sm) var(--spacing-md) !important;
+ margin: 2px 0 !important;
+ border-radius: var(--border-radius-md) !important;
+ transition: all var(--transition-normal) !important;
+ display: flex !important;
+ align-items: center !important;
+ gap: var(--spacing-sm) !important;
+ font-weight: var(--font-weight-medium) !important;
+ min-height: 40px !important;
+ cursor: pointer !important;
+ color: var(--text-primary) !important;
+}
+
+.ant-dropdown-menu-item:hover {
+ background: linear-gradient(135deg, rgba(139, 92, 246, 0.1), rgba(59, 130, 246, 0.05)) !important;
+ color: var(--primary-color) !important;
+ transform: translateX(2px) !important;
+ box-shadow: 0 4px 12px rgba(139, 92, 246, 0.15) !important;
+}
+
+.ant-dropdown-menu-item:active {
+ transform: translateX(2px) !important;
+ box-shadow: 0 2px 6px rgba(139, 92, 246, 0.1) !important;
+}
+
+.ant-dropdown-menu-item .anticon {
+ font-size: 16px !important;
+ color: inherit !important;
+ opacity: 0.8 !important;
+ transition: all var(--transition-normal) !important;
+}
+
+
diff --git a/services/web/src/components/navBar/navBar.tsx b/services/web/src/components/navBar/navBar.tsx
index 39b95e46..6cf8db43 100644
--- a/services/web/src/components/navBar/navBar.tsx
+++ b/services/web/src/components/navBar/navBar.tsx
@@ -122,18 +122,24 @@ const Navbar: React.FC = (props) => {
{isLoggedIn ? (
- {`Good Morning, ${name}!`}
-
-
navigate("/my-profile")}
- />
-
-
-
-
+
{`Good Morning, ${name}!`}
+
+
diff --git a/services/web/src/components/pastOrders/pastOrders.tsx b/services/web/src/components/pastOrders/pastOrders.tsx
index 1db161f1..3074ddef 100644
--- a/services/web/src/components/pastOrders/pastOrders.tsx
+++ b/services/web/src/components/pastOrders/pastOrders.tsx
@@ -66,40 +66,39 @@ const PastOrders: React.FC
= (props) => {
const { pastOrders } = props;
const renderAvatar = (url: string) => (
-
+
);
const renderOrderDescription = (order: Order) => (
- <>
- navigate(`/orders?order_id=${order.id}`)}
- >
- {" "}
- Order Details
- ,
-
- }
- size="middle"
- key="return-order"
- disabled={order.status !== "delivered"}
- onClick={() => props.returnOrder(order.id)}
- >
- {order.status === "delivered" ? "Return" : order.status}
- ,
- ]}
- />
- >
+
+
{order.product.name}
+
+ ${(Number(order.product.price) * order.quantity).toFixed(2)}
+
+
{formatDateFromIso(order.created_on)}
+
+
+ }
+ size="middle"
+ key="return-order"
+ disabled={order.status !== "delivered"}
+ onClick={() => props.returnOrder(order.id)}
+ >
+ {order.status === "delivered" ? "Return" : order.status}
+
+
+
);
return (
@@ -110,12 +109,13 @@ const PastOrders: React.FC = (props) => {
onBack={() => navigate("/shop")}
/>
-
+
{pastOrders.map((order) => (
-
+
@@ -123,26 +123,30 @@ const PastOrders: React.FC = (props) => {
))}
-
-
+
+
+
+
+
+
diff --git a/services/web/src/components/pastOrders/styles.css b/services/web/src/components/pastOrders/styles.css
index 5bedc604..aa433fdb 100644
--- a/services/web/src/components/pastOrders/styles.css
+++ b/services/web/src/components/pastOrders/styles.css
@@ -1,21 +1,286 @@
-.order-desc {
- padding: 0 2%;
+/* Modern Past Orders Page Styling */
+.page-header {
+ padding-left: 0;
+ padding-right: 0;
+ background: linear-gradient(135deg, rgba(139, 92, 246, 0.1) 0%, rgba(168, 85, 247, 0.1) 100%);
+ border-radius: var(--border-radius-lg);
+ margin-bottom: var(--spacing-lg);
+ backdrop-filter: blur(10px);
+ border: 1px solid rgba(255, 255, 255, 0.1);
}
-.order-desc .ant-descriptions-item-label,
-.order-desc .ant-descriptions-item-content {
- font-size: 18px;
+/* Order Cards */
+.order-card {
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(10px);
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ border-radius: var(--border-radius-xl);
+ box-shadow: var(--shadow-elevation-medium);
+ transition: all 0.3s ease;
+ overflow: hidden;
+ position: relative;
+ margin-bottom: var(--spacing-lg);
}
-.return-btn {
- width: 30%;
- margin: 0 35%;
+.order-card::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 4px;
+ background: linear-gradient(90deg, #8b5cf6, #a855f7, #c084fc);
+ opacity: 0;
+ transition: opacity 0.3s ease;
}
-.order-card {
- padding-top: 24px;
+.order-card:hover {
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-elevation-high);
+ border-color: rgba(139, 92, 246, 0.3);
+}
+
+.order-card:hover::before {
+ opacity: 1;
+}
+
+.order-card .ant-card-cover {
+ padding: var(--spacing-lg);
+ background: linear-gradient(135deg, rgba(139, 92, 246, 0.05) 0%, rgba(168, 85, 247, 0.05) 100%);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-height: 280px;
}
+.order-card .ant-card-body {
+ padding: var(--spacing-lg);
+ background: rgba(255, 255, 255, 0.8);
+ backdrop-filter: blur(5px);
+}
+
+/* Order Images */
.order-avatar {
margin: auto;
+ border-radius: var(--border-radius-lg) !important;
+ box-shadow: var(--shadow-elevation-medium);
+ transition: all 0.3s ease;
+ border: 3px solid rgba(255, 255, 255, 0.8);
+ max-width: 100%;
+ height: auto;
+ object-fit: cover;
+}
+
+.order-card:hover .order-avatar {
+ transform: scale(1.05);
+ box-shadow: var(--shadow-elevation-high);
+}
+
+/* Order Information */
+.order-info {
+ text-align: center;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-sm);
+}
+
+.order-product-name {
+ font-size: 16px;
+ font-weight: 700;
+ color: #1f2937;
+ line-height: 1.3;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ letter-spacing: -0.025em;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ max-width: 100%;
+ display: inline-block;
+}
+
+.order-price {
+ font-size: 18px;
+ font-weight: 800;
+ color: #8b5cf6;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ letter-spacing: -0.025em;
+ text-shadow: 0 1px 2px rgba(139, 92, 246, 0.2);
+}
+
+.order-date {
+ font-size: 12px;
+ font-weight: 500;
+ color: #6b7280;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ margin-bottom: var(--spacing-xs);
+}
+
+/* Order Action Buttons */
+.order-actions {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-sm);
+ margin-top: var(--spacing-md);
+}
+
+.order-card .ant-btn {
+ height: 36px;
+ padding: 0 var(--spacing-md);
+ background: linear-gradient(135deg, #8b5cf6 0%, #a855f7 100%);
+ border: none;
+ border-radius: var(--border-radius-lg);
+ font-weight: 600;
+ font-size: 13px;
+ box-shadow: var(--shadow-elevation-medium);
+ transition: all 0.3s ease;
+ position: relative;
+ overflow: hidden;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ letter-spacing: 0.025em;
+ min-width: 120px;
+}
+
+.order-card .ant-btn::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
+ transition: left 0.5s;
+}
+
+.order-card .ant-btn:hover::before {
+ left: 100%;
+}
+
+.order-card .ant-btn:hover:not(:disabled) {
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-elevation-high);
+ background: linear-gradient(135deg, #7c3aed 0%, #9333ea 100%);
+}
+
+.order-card .ant-btn:active {
+ transform: translateY(0);
+}
+
+.order-card .ant-btn:disabled {
+ background: rgba(156, 163, 175, 0.3) !important;
+ color: #9ca3af !important;
+ cursor: not-allowed;
+ transform: none !important;
+}
+
+.order-card .ant-btn[key="return-order"]:disabled {
+ background: linear-gradient(135deg, rgba(16, 185, 129, 0.2) 0%, rgba(5, 150, 105, 0.2) 100%) !important;
+ color: #10b981 !important;
+ font-weight: 700 !important;
+ border: 1px solid rgba(16, 185, 129, 0.3) !important;
+}
+
+.order-card .ant-btn .anticon {
+ margin-right: var(--spacing-xs);
+}
+
+/* Pagination */
+.pagination {
+ margin-top: var(--spacing-xl);
+ gap: var(--spacing-lg);
+}
+
+.pagination .ant-btn {
+ height: 48px;
+ padding: 0 var(--spacing-xl);
+ background: linear-gradient(135deg, rgba(139, 92, 246, 0.1) 0%, rgba(168, 85, 247, 0.1) 100%);
+ backdrop-filter: blur(10px);
+ border: 1px solid rgba(139, 92, 246, 0.3);
+ border-radius: var(--border-radius-lg);
+ font-weight: 600;
+ transition: all 0.3s ease;
+ box-shadow: var(--shadow-elevation-low);
+}
+
+.pagination .ant-btn:hover:not(:disabled) {
+ background: linear-gradient(135deg, #8b5cf6 0%, #a855f7 100%);
+ color: white;
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-elevation-medium);
+}
+
+.pagination .ant-btn:disabled {
+ background: rgba(156, 163, 175, 0.1);
+ border-color: rgba(156, 163, 175, 0.2);
+ color: #9ca3af;
+}
+
+/* Responsive Design */
+@media (max-width: 1200px) {
+ .order-card .ant-card-cover {
+ min-height: 240px;
+ }
+}
+
+@media (max-width: 768px) {
+ .order-card {
+ margin-bottom: var(--spacing-md);
+ }
+
+ .order-card .ant-card-cover {
+ min-height: 200px;
+ padding: var(--spacing-md);
+ }
+
+ .order-card .ant-card-body {
+ padding: var(--spacing-md);
+ }
+
+ .order-product-name {
+ font-size: 14px;
+ }
+
+ .order-price {
+ font-size: 16px;
+ }
+
+ .order-date {
+ font-size: 11px;
+ }
+
+ .order-card .ant-btn {
+ height: 32px;
+ font-size: 12px;
+ min-width: 100px;
+ padding: 0 var(--spacing-sm);
+ }
+
+ .pagination {
+ flex-direction: column;
+ align-items: center;
+ gap: var(--spacing-md);
+ }
+
+ .pagination .ant-btn {
+ width: 200px;
+ }
+}
+
+@media (max-width: 576px) {
+ .page-header .ant-page-header-heading-extra {
+ flex-direction: column;
+ gap: var(--spacing-sm);
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+
+ .page-header .ant-btn {
+ width: 100%;
+ }
+
+ .order-actions {
+ flex-direction: row;
+ justify-content: center;
+ flex-wrap: wrap;
+ }
}
diff --git a/services/web/src/components/post/post.tsx b/services/web/src/components/post/post.tsx
index b77bad96..726c9281 100644
--- a/services/web/src/components/post/post.tsx
+++ b/services/web/src/components/post/post.tsx
@@ -81,108 +81,154 @@ const Posts: React.FC = ({
errorMessage,
}) => {
return (
-
-
-
-
-
-
-
-
-
-
-
-
- {post &&
- post.content.split("\n").map((para) => (
-
- {para}
-
- ))}
-
-
-
+
+
+
+
+
+
+
+
+
{post && post.title}
+
+ {post &&
+ `${post.author.nickname}, ${formatDateFromIso(post.CreatedAt)}`}
+
+
+
+
+
+
+
+
+ {post &&
+ post.content.split("\n").map((para, index) => (
+
+ {para}
+
+ ))}
+
+
+
+
+
+
+
+
Comments
}
size="large"
- key="add-btn"
+ className="add-comment-btn"
onClick={() => setIsCommentFormOpen(true)}
>
Add Comment
- ,
- ]}
- />
- {post &&
- post.comments &&
- post.comments.map((comment) => (
-
-
-
-
-
-
-
-
-
-
- {comment.content.split("\n").map((para) => (
- {para}
- ))}
-
-
-
- ))}
-
+
+
+
+
+ {post &&
+ post.comments &&
+ post.comments.map((comment, index) => (
+
+
+
+
+
+
+
+
+ {`${comment.author.nickname}, ${formatDateFromIso(
+ comment.CreatedAt,
+ )}`}
+
+
+ {comment.content
+ .split("\n")
+ .map((para, paraIndex) => (
+
+ {para}
+
+ ))}
+
+
+
+
+
+ ))}
+
+
💬 New Comment}
+ open={isCommentFormOpen}
footer={null}
onCancel={() => setIsCommentFormOpen(false)}
+ className="comment-modal"
+ centered
>
-
+
-
+
{hasErrored && {errorMessage}
}
-
+
+
+ }
+ >
+ Add Comment
+
+
diff --git a/services/web/src/components/post/style.css b/services/web/src/components/post/style.css
index 74f55686..aa0b0246 100644
--- a/services/web/src/components/post/style.css
+++ b/services/web/src/components/post/style.css
@@ -1,19 +1,516 @@
-.post-header {
- padding-bottom: 0;
+/* ===== POST PAGE MODERN DESIGN ===== */
+
+/* Page Container */
+.post-page {
+ min-height: 100vh;
+ background: linear-gradient(
+ 135deg,
+ rgba(167, 139, 250, 0.1) 0%,
+ rgba(236, 72, 153, 0.1) 50%,
+ rgba(59, 130, 246, 0.1) 100%
+ );
+ padding: var(--spacing-xl) var(--spacing-md);
+}
+
+/* Main Post Card */
+.post-card {
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(20px);
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ border-radius: 24px;
+ box-shadow:
+ 0 20px 40px rgba(0, 0, 0, 0.1),
+ 0 10px 20px rgba(0, 0, 0, 0.05),
+ inset 0 1px 0 rgba(255, 255, 255, 0.8);
+ padding: var(--spacing-xl) calc(var(--spacing-xl) * 1.5);
+ max-width: 1200px;
+ width: 95%;
+ margin: 0 auto;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.post-card:hover {
+ transform: translateY(-2px);
+ box-shadow:
+ 0 25px 50px rgba(0, 0, 0, 0.15),
+ 0 15px 30px rgba(0, 0, 0, 0.08),
+ inset 0 1px 0 rgba(255, 255, 255, 0.9);
+}
+
+/* Post Header Section */
+.post-header-section {
+ margin-bottom: calc(var(--spacing-xl) * 1.5);
+ padding-bottom: var(--spacing-lg);
+ border-bottom: 1px solid rgba(229, 231, 235, 0.3);
+}
+
+.post-avatar-container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 4px;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ border-radius: 50%;
+ transition: all 0.3s ease;
+}
+
+.post-avatar-container:hover {
+ transform: scale(1.05);
+ box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
+}
+
+.post-avatar {
+ border: 3px solid rgba(255, 255, 255, 0.9) !important;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
+}
+
+.post-meta {
+ padding-left: var(--spacing-md);
+}
+
+.post-title {
+ font-size: 28px !important;
+ font-weight: 800 !important;
+ color: #1f2937 !important;
+ margin: 0 0 var(--spacing-sm) 0 !important;
+ line-height: 1.3 !important;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ letter-spacing: -0.025em;
+ background: linear-gradient(135deg, #1f2937 0%, #4b5563 100%);
+ background-clip: text;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
}
.post-subtitle {
- padding: 0;
+ font-size: 16px;
+ font-weight: 600;
+ color: #6b7280;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ margin: 0;
}
-.comment-heading {
- padding-top: 0;
+/* Post Content Section */
+.post-content-section {
+ margin-bottom: calc(var(--spacing-xl) * 1.5);
+ max-width: 900px;
}
-.comment-title {
- padding: 0;
+.post-content {
+ margin: 0;
}
-.comment-row {
+.post-paragraph {
+ font-size: 17px !important;
+ line-height: 1.8 !important;
+ color: #374151 !important;
+ margin-bottom: calc(var(--spacing-md) * 1.2) !important;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ text-align: justify;
+}
+
+.post-paragraph:last-child {
+ margin-bottom: 0 !important;
+}
+
+/* Post Divider */
+.post-divider {
+ background: linear-gradient(
+ 90deg,
+ transparent 0%,
+ rgba(156, 163, 175, 0.3) 20%,
+ rgba(156, 163, 175, 0.6) 50%,
+ rgba(156, 163, 175, 0.3) 80%,
+ transparent 100%
+ );
+ height: 2px;
+ border: none;
+ margin: var(--spacing-xl) 0;
+}
+
+/* Comments Section */
+.comments-section {
+ margin-top: calc(var(--spacing-xl) * 1.5);
+ max-width: 100%;
+}
+
+.comments-header {
+ display: flex;
+ justify-content: space-between;
align-items: center;
+ margin-bottom: var(--spacing-xl);
+ flex-wrap: wrap;
+ gap: var(--spacing-md);
+}
+
+.comments-title {
+ font-size: 24px !important;
+ font-weight: 700 !important;
+ color: #1f2937 !important;
+ margin: 0 !important;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ letter-spacing: -0.025em;
+}
+
+.add-comment-btn {
+ background: linear-gradient(135deg, #8b5cf6 0%, #06b6d4 100%) !important;
+ border: none !important;
+ height: 44px !important;
+ padding: 0 var(--spacing-lg) !important;
+ font-weight: 600 !important;
+ font-size: 14px !important;
+ letter-spacing: 0.5px !important;
+ box-shadow:
+ 0 4px 12px rgba(139, 92, 246, 0.3),
+ inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
+}
+
+.add-comment-btn:hover,
+.add-comment-btn:focus {
+ transform: translateY(-2px) !important;
+ box-shadow:
+ 0 6px 20px rgba(139, 92, 246, 0.4),
+ inset 0 1px 0 rgba(255, 255, 255, 0.3) !important;
+ background: linear-gradient(135deg, #7c3aed 0%, #0891b2 100%) !important;
+}
+
+.add-comment-btn:active {
+ transform: translateY(0) !important;
+}
+
+/* Comments List */
+.comments-list {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-lg);
+}
+
+.comment-item {
+ background: rgba(248, 250, 252, 0.8);
+ backdrop-filter: blur(10px);
+ border: 1px solid rgba(226, 232, 240, 0.6);
+ border-radius: 16px;
+ padding: var(--spacing-lg) calc(var(--spacing-lg) * 1.5);
+ transition: all 0.3s ease;
+ width: 100%;
+}
+
+.comment-item .ant-row {
+ width: 100% !important;
+ align-items: flex-start !important;
+ justify-content: flex-start !important;
+}
+
+.comment-item .ant-col {
+ text-align: left !important;
+}
+
+.comment-item .ant-col[flex="auto"] {
+ flex: 1 1 auto !important;
+ max-width: calc(100% - 70px) !important;
+ width: calc(100% - 70px) !important;
+}
+
+.comment-item:hover {
+ background: rgba(255, 255, 255, 0.9);
+ transform: translateX(2px);
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08);
+}
+
+.comment-avatar-container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 2px;
+ background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
+ border-radius: 50%;
+ transition: all 0.3s ease;
+}
+
+.comment-avatar-container:hover {
+ transform: scale(1.05);
+}
+
+.comment-avatar {
+ border: 2px solid rgba(255, 255, 255, 0.9) !important;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
+}
+
+.comment-content {
+ padding-left: var(--spacing-md);
+ flex: 1 1 auto !important;
+ min-width: 0;
+ width: 100% !important;
+ max-width: 100% !important;
+ display: flex !important;
+ flex-direction: column !important;
+ align-items: flex-start !important;
+ justify-content: flex-start !important;
+}
+
+.comment-meta {
+ font-size: 15px;
+ font-weight: 600;
+ color: #6b7280;
+ margin-bottom: var(--spacing-md);
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ align-self: flex-start !important;
+ width: 100% !important;
+ max-width: 100% !important;
+ display: block !important;
+ text-align: left !important;
+}
+
+.comment-text {
+ margin: 0 !important;
+ width: 100% !important;
+ max-width: 100% !important;
+ align-self: flex-start !important;
+ text-align: left !important;
+ display: block !important;
+ flex: 1 1 auto !important;
+}
+
+.comment-text .ant-typography {
+ margin: 0 !important;
+ text-align: left !important;
+ width: 100% !important;
+ max-width: 100% !important;
+ display: block !important;
+}
+
+.comment-paragraph {
+ font-size: 16px !important;
+ line-height: 1.7 !important;
+ color: #4b5563 !important;
+ margin-bottom: var(--spacing-sm) !important;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ text-align: left !important;
+ width: 100% !important;
+ display: block !important;
+}
+
+.comment-paragraph p {
+ text-align: left !important;
+ margin: 0 !important;
+ width: 100% !important;
+}
+
+.comment-paragraph:last-child {
+ margin-bottom: 0 !important;
+}
+
+/* Modal Styling */
+.comment-modal .ant-modal-content {
+ background: rgba(255, 255, 255, 0.95) !important;
+ backdrop-filter: blur(20px) !important;
+ border: 1px solid rgba(255, 255, 255, 0.2) !important;
+ border-radius: 20px !important;
+ box-shadow:
+ 0 25px 50px rgba(0, 0, 0, 0.15),
+ 0 15px 30px rgba(0, 0, 0, 0.08) !important;
+ overflow: hidden !important;
+}
+
+.comment-modal .ant-modal-header {
+ background: transparent !important;
+ border-bottom: 1px solid rgba(229, 231, 235, 0.6) !important;
+ padding: var(--spacing-lg) var(--spacing-xl) !important;
+}
+
+.comment-modal .ant-modal-body {
+ padding: var(--spacing-xl) !important;
+}
+
+.modal-title {
+ font-size: 20px !important;
+ font-weight: 700 !important;
+ color: #1f2937 !important;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+}
+
+.comment-form .ant-form-item-label > label {
+ font-weight: 600 !important;
+ color: #374151 !important;
+ font-size: 14px !important;
+}
+
+.comment-textarea {
+ border: 2px solid rgba(229, 231, 235, 0.8) !important;
+ border-radius: 12px !important;
+ padding: var(--spacing-md) !important;
+ font-size: 15px !important;
+ line-height: 1.6 !important;
+ transition: all 0.3s ease !important;
+ background: rgba(249, 250, 251, 0.8) !important;
+}
+
+.comment-textarea:focus {
+ border-color: #8b5cf6 !important;
+ box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1) !important;
+ background: rgba(255, 255, 255, 0.9) !important;
+}
+
+.comment-textarea::placeholder {
+ color: #9ca3af !important;
+ font-style: italic;
+}
+
+.form-actions {
+ margin-bottom: 0 !important;
+}
+
+.modal-buttons {
+ display: flex;
+ gap: var(--spacing-md);
+ justify-content: flex-end;
+ margin-top: var(--spacing-lg);
+}
+
+.cancel-btn {
+ height: 40px !important;
+ padding: 0 var(--spacing-lg) !important;
+ font-weight: 600 !important;
+ border: 2px solid rgba(229, 231, 235, 0.8) !important;
+ background: rgba(249, 250, 251, 0.8) !important;
+ color: #6b7280 !important;
+ border-radius: 10px !important;
+ transition: all 0.3s ease !important;
+}
+
+.cancel-btn:hover {
+ border-color: #d1d5db !important;
+ background: rgba(243, 244, 246, 0.9) !important;
+ color: #4b5563 !important;
+ transform: translateY(-1px) !important;
+}
+
+.submit-btn {
+ height: 40px !important;
+ padding: 0 var(--spacing-lg) !important;
+ font-weight: 600 !important;
+ background: linear-gradient(135deg, #8b5cf6 0%, #06b6d4 100%) !important;
+ border: none !important;
+ border-radius: 10px !important;
+ box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3) !important;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
+}
+
+.submit-btn:hover,
+.submit-btn:focus {
+ background: linear-gradient(135deg, #7c3aed 0%, #0891b2 100%) !important;
+ transform: translateY(-2px) !important;
+ box-shadow: 0 6px 20px rgba(139, 92, 246, 0.4) !important;
+}
+
+.submit-btn:active {
+ transform: translateY(0) !important;
+}
+
+.error-message {
+ color: #dc2626;
+ font-size: 14px;
+ font-weight: 500;
+ margin-bottom: var(--spacing-md);
+ padding: var(--spacing-sm) var(--spacing-md);
+ background: rgba(254, 226, 226, 0.8);
+ border: 1px solid rgba(248, 113, 113, 0.3);
+ border-radius: 8px;
+}
+
+/* Responsive Design */
+@media (max-width: 1024px) {
+ .post-card {
+ max-width: 95%;
+ padding: var(--spacing-xl);
+ }
+
+ .post-content-section {
+ max-width: 100%;
+ }
+
+ .comments-section {
+ max-width: 100%;
+ }
+}
+
+@media (max-width: 768px) {
+ .post-page {
+ padding: var(--spacing-lg) var(--spacing-sm);
+ }
+
+ .post-card {
+ padding: var(--spacing-lg);
+ border-radius: 16px;
+ width: 98%;
+ }
+
+ .post-title {
+ font-size: 24px !important;
+ }
+
+ .comments-header {
+ flex-direction: column;
+ align-items: stretch;
+ }
+
+ .add-comment-btn {
+ width: 100%;
+ justify-content: center;
+ }
+
+ .modal-buttons {
+ flex-direction: column;
+ }
+
+ .cancel-btn,
+ .submit-btn {
+ width: 100%;
+ justify-content: center;
+ }
+
+ .comment-item {
+ padding: var(--spacing-md) var(--spacing-lg);
+ }
+
+ .comment-content {
+ padding-left: var(--spacing-sm);
+ }
+
+ .post-meta {
+ padding-left: 0;
+ margin-top: var(--spacing-md);
+ }
+}
+
+@media (max-width: 480px) {
+ .post-card {
+ margin: 0;
+ border-radius: 12px;
+ width: 100%;
+ padding: var(--spacing-md);
+ }
+
+ .post-title {
+ font-size: 20px !important;
+ }
+
+ .comments-title {
+ font-size: 20px !important;
+ }
+
+ .post-paragraph {
+ font-size: 16px !important;
+ text-align: left;
+ }
+
+ .comment-paragraph {
+ font-size: 15px !important;
+ text-align: left;
+ }
+
+ .comment-item {
+ padding: var(--spacing-sm) var(--spacing-md);
+ }
}
diff --git a/services/web/src/components/profile/profile.css b/services/web/src/components/profile/profile.css
index 28f6d083..35e537b9 100644
--- a/services/web/src/components/profile/profile.css
+++ b/services/web/src/components/profile/profile.css
@@ -1,44 +1,521 @@
-.avatar-uploader {
- width: auto;
- margin-left: 10px;
-}
+/* ===== PROFILE PAGE MODERN DESIGN ===== */
-.page-container {
- width: 65%;
- min-width: 900px;
- margin: auto;
+/* Page Container */
+.profile-page {
+ min-height: 100vh;
+ background: linear-gradient(
+ 135deg,
+ rgba(167, 139, 250, 0.1) 0%,
+ rgba(236, 72, 153, 0.1) 50%,
+ rgba(59, 130, 246, 0.1) 100%
+ );
+ padding: var(--spacing-xl) var(--spacing-lg);
}
-.profile-header {
- padding-left: 0;
+.page-container.profile-page {
+ max-width: 1400px;
+ width: 90%;
+ margin: 0 auto;
+ min-width: auto;
}
-.change-email-btn {
- margin-left: 50px;
+/* Profile Header Section */
+.profile-header-section {
+ text-align: center;
+ margin-bottom: calc(var(--spacing-xl) * 1.5);
+ padding-bottom: var(--spacing-xl);
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}
-.change-phone-number-btn {
- margin-left: 50px;
+.profile-title {
+ font-size: 36px !important;
+ font-weight: 800 !important;
+ color: #1f2937 !important;
+ margin: 0 0 var(--spacing-sm) 0 !important;
+ line-height: 1.2 !important;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ letter-spacing: -0.025em;
+ background: linear-gradient(135deg, #1f2937 0%, #4b5563 100%);
+ background-clip: text;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
}
-.profile-video {
- width: 60%;
+.profile-subtitle {
+ font-size: 18px;
+ color: #6b7280;
+ font-weight: 500;
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
-.more-icon {
- color: black;
- font-size: x-large;
+/* Content Wrapper */
+.profile-content-wrapper {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-xl);
}
-.upload-video-button {
+/* Cards */
+.profile-card,
+.video-section-card {
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(20px);
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ border-radius: 24px;
+ box-shadow:
+ 0 20px 40px rgba(0, 0, 0, 0.1),
+ 0 10px 20px rgba(0, 0, 0, 0.05),
+ inset 0 1px 0 rgba(255, 255, 255, 0.8);
+ padding: calc(var(--spacing-xl) * 1.5) calc(var(--spacing-xl) * 2);
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
width: 100%;
- height: 100%;
- min-width: 900px;
+}
+
+.profile-card:hover,
+.video-section-card:hover {
+ transform: translateY(-2px);
+ box-shadow:
+ 0 25px 50px rgba(0, 0, 0, 0.15),
+ 0 15px 30px rgba(0, 0, 0, 0.08),
+ inset 0 1px 0 rgba(255, 255, 255, 0.9);
+}
+
+/* Profile Avatar Section */
+.profile-avatar-section {
+ display: flex;
+ justify-content: center;
align-items: center;
+ position: relative;
+}
+
+.avatar-container {
+ position: relative;
+ display: flex;
justify-content: center;
+ align-items: center;
+ padding: 8px;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ border-radius: 50%;
+ transition: all 0.3s ease;
+}
+
+.avatar-container:hover {
+ transform: scale(1.05);
+ box-shadow: 0 12px 30px rgba(102, 126, 234, 0.3);
+}
+
+.profile-avatar {
+ border: 4px solid rgba(255, 255, 255, 0.9) !important;
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15) !important;
+ transition: all 0.3s ease !important;
+}
+
+.change-pic-btn {
+ background: linear-gradient(135deg, #8b5cf6 0%, #06b6d4 100%) !important;
+ border: none !important;
+ box-shadow:
+ 0 6px 20px rgba(139, 92, 246, 0.4),
+ inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
+ width: 48px !important;
+ height: 48px !important;
+}
+
+.change-pic-btn:hover,
+.change-pic-btn:focus {
+ transform: translateY(-2px) scale(1.05) !important;
+ box-shadow:
+ 0 8px 25px rgba(139, 92, 246, 0.5),
+ inset 0 1px 0 rgba(255, 255, 255, 0.3) !important;
+ background: linear-gradient(135deg, #7c3aed 0%, #0891b2 100%) !important;
+}
+
+/* Profile Information */
+.profile-info {
display: flex;
- margin-top: 40px;
+ flex-direction: column;
+ gap: calc(var(--spacing-lg) * 1.5);
+ width: 100%;
+}
+
+.info-item {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-md);
+ padding: calc(var(--spacing-lg) * 1.2) var(--spacing-xl);
+ background: rgba(248, 250, 252, 0.8);
+ backdrop-filter: blur(10px);
+ border: 1px solid rgba(226, 232, 240, 0.6);
+ border-radius: 16px;
+ transition: all 0.3s ease;
+ width: 100%;
+}
+
+.info-item:hover {
+ background: rgba(255, 255, 255, 0.9);
+ transform: translateX(2px);
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08);
+}
+
+.info-label {
+ font-size: 14px;
+ font-weight: 700;
+ color: #6b7280;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+}
+
+.info-value {
+ font-size: 20px;
+ font-weight: 600;
+ color: #1f2937;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ line-height: 1.4;
+ flex: 1;
+ min-width: 0;
+}
+
+.info-value-with-action {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: var(--spacing-lg);
+ width: 100%;
+}
+
+/* Action Buttons */
+.action-btn {
+ background: linear-gradient(135deg, #8b5cf6 0%, #06b6d4 100%) !important;
+ border: none !important;
+ height: 40px !important;
+ padding: 0 var(--spacing-lg) !important;
+ font-weight: 600 !important;
+ font-size: 14px !important;
+ letter-spacing: 0.5px !important;
+ box-shadow:
+ 0 4px 12px rgba(139, 92, 246, 0.3),
+ inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
+ flex-shrink: 0;
+}
+
+.action-btn:hover,
+.action-btn:focus {
+ transform: translateY(-2px) !important;
+ box-shadow:
+ 0 6px 20px rgba(139, 92, 246, 0.4),
+ inset 0 1px 0 rgba(255, 255, 255, 0.3) !important;
+ background: linear-gradient(135deg, #7c3aed 0%, #0891b2 100%) !important;
+}
+
+.action-btn:active {
+ transform: translateY(0) !important;
+}
+
+/* Video Section */
+.video-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ margin-bottom: var(--spacing-xl);
+ flex-wrap: wrap;
+ gap: var(--spacing-lg);
+}
+
+.video-info {
+ flex: 1;
+ min-width: 0;
+}
+
+.video-title {
+ font-size: 28px !important;
+ font-weight: 700 !important;
+ color: #1f2937 !important;
+ margin: 0 0 var(--spacing-sm) 0 !important;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ letter-spacing: -0.025em;
+}
+
+.video-subtitle {
+ font-size: 16px;
+ color: #6b7280;
+ font-weight: 500;
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+}
+
+.upload-video-btn,
+.video-dropdown-btn {
+ background: linear-gradient(135deg, #8b5cf6 0%, #06b6d4 100%) !important;
+ border: none !important;
+ height: 48px !important;
+ padding: 0 var(--spacing-xl) !important;
+ font-weight: 600 !important;
+ font-size: 16px !important;
+ letter-spacing: 0.5px !important;
+ border-radius: 24px !important;
+ box-shadow:
+ 0 6px 20px rgba(139, 92, 246, 0.4),
+ inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
+}
+
+.video-dropdown-btn .ant-btn {
+ border-radius: 24px 0 0 24px !important;
+}
+
+.video-dropdown-btn .ant-dropdown-trigger {
+ border-radius: 0 24px 24px 0 !important;
+}
+
+.upload-video-btn:hover,
+.upload-video-btn:focus,
+.video-dropdown-btn:hover,
+.video-dropdown-btn:focus {
+ transform: translateY(-2px) !important;
+ box-shadow:
+ 0 8px 25px rgba(139, 92, 246, 0.5),
+ inset 0 1px 0 rgba(255, 255, 255, 0.3) !important;
+ background: linear-gradient(135deg, #7c3aed 0%, #0891b2 100%) !important;
}
-.button {
+
+/* Video Player */
+.video-player-container {
+ margin-top: var(--spacing-xl);
+ padding: calc(var(--spacing-lg) * 1.5);
+ background: rgba(0, 0, 0, 0.05);
+ border-radius: 16px;
+ border: 1px solid rgba(0, 0, 0, 0.08);
+ width: 100%;
+}
+
+.video-container {
+ display: flex;
+ justify-content: center;
align-items: center;
+ width: 100%;
+}
+
+.profile-video {
+ width: 100%;
+ max-width: 1000px;
+ height: auto;
+ border-radius: 12px;
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+ transition: all 0.3s ease;
+}
+
+.profile-video:hover {
+ transform: scale(1.02);
+ box-shadow: 0 12px 35px rgba(0, 0, 0, 0.2);
+}
+
+/* Modal Styling */
+.video-name-modal .ant-modal-content {
+ background: rgba(255, 255, 255, 0.95) !important;
+ backdrop-filter: blur(20px) !important;
+ border: 1px solid rgba(255, 255, 255, 0.2) !important;
+ border-radius: 20px !important;
+ box-shadow:
+ 0 25px 50px rgba(0, 0, 0, 0.15),
+ 0 15px 30px rgba(0, 0, 0, 0.08) !important;
+}
+
+.video-name-modal .ant-modal-header {
+ background: transparent !important;
+ border-bottom: 1px solid rgba(229, 231, 235, 0.6) !important;
+ padding: var(--spacing-lg) var(--spacing-xl) !important;
+}
+
+.video-name-modal .ant-modal-body {
+ padding: var(--spacing-xl) !important;
+}
+
+.modal-title {
+ font-size: 20px !important;
+ font-weight: 700 !important;
+ color: #1f2937 !important;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+}
+
+.video-name-form .ant-form-item-label > label {
+ font-weight: 600 !important;
+ color: #374151 !important;
+ font-size: 14px !important;
+}
+
+.video-name-input {
+ border: 2px solid rgba(229, 231, 235, 0.8) !important;
+ border-radius: 12px !important;
+ padding: var(--spacing-md) !important;
+ font-size: 16px !important;
+ transition: all 0.3s ease !important;
+ background: rgba(249, 250, 251, 0.8) !important;
+}
+
+.video-name-input:focus {
+ border-color: #8b5cf6 !important;
+ box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1) !important;
+ background: rgba(255, 255, 255, 0.9) !important;
+}
+
+.modal-buttons {
+ display: flex;
+ gap: var(--spacing-md);
+ justify-content: flex-end;
+ margin-top: var(--spacing-lg);
+}
+
+.cancel-btn {
+ height: 44px !important;
+ padding: 0 var(--spacing-lg) !important;
+ font-weight: 600 !important;
+ border: 2px solid rgba(229, 231, 235, 0.8) !important;
+ background: rgba(249, 250, 251, 0.8) !important;
+ color: #6b7280 !important;
+ border-radius: 12px !important;
+ transition: all 0.3s ease !important;
+}
+
+.cancel-btn:hover {
+ border-color: #d1d5db !important;
+ background: rgba(243, 244, 246, 0.9) !important;
+ color: #4b5563 !important;
+ transform: translateY(-1px) !important;
+}
+
+.submit-btn {
+ height: 44px !important;
+ padding: 0 var(--spacing-lg) !important;
+ font-weight: 600 !important;
+ background: linear-gradient(135deg, #8b5cf6 0%, #06b6d4 100%) !important;
+ border: none !important;
+ border-radius: 12px !important;
+ box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3) !important;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
+}
+
+.submit-btn:hover,
+.submit-btn:focus {
+ background: linear-gradient(135deg, #7c3aed 0%, #0891b2 100%) !important;
+ transform: translateY(-2px) !important;
+ box-shadow: 0 6px 20px rgba(139, 92, 246, 0.4) !important;
+}
+
+.error-message {
+ color: #dc2626;
+ font-size: 14px;
+ font-weight: 500;
+ margin-bottom: var(--spacing-md);
+ padding: var(--spacing-sm) var(--spacing-md);
+ background: rgba(254, 226, 226, 0.8);
+ border: 1px solid rgba(248, 113, 113, 0.3);
+ border-radius: 8px;
+}
+
+/* Responsive Design */
+@media (max-width: 1440px) {
+ .page-container.profile-page {
+ width: 95%;
+ }
+}
+
+@media (max-width: 1024px) {
+ .profile-page {
+ padding: var(--spacing-lg) var(--spacing-md);
+ }
+
+ .page-container.profile-page {
+ width: 98%;
+ }
+
+ .profile-card,
+ .video-section-card {
+ padding: var(--spacing-xl);
+ border-radius: 16px;
+ }
+
+ .info-item {
+ padding: var(--spacing-lg);
+ }
+}
+
+@media (max-width: 768px) {
+ .profile-title {
+ font-size: 28px !important;
+ }
+
+ .video-title {
+ font-size: 24px !important;
+ }
+
+ .page-container.profile-page {
+ width: 100%;
+ padding: var(--spacing-md);
+ }
+
+ .profile-card,
+ .video-section-card {
+ padding: var(--spacing-lg);
+ margin: 0 -8px;
+ }
+
+ .info-value-with-action {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: var(--spacing-md);
+ }
+
+ .action-btn {
+ width: 100%;
+ justify-content: center;
+ }
+
+ .video-header {
+ flex-direction: column;
+ align-items: stretch;
+ }
+
+ .upload-video-btn,
+ .video-dropdown-btn {
+ width: 100%;
+ justify-content: center;
+ }
+
+ .modal-buttons {
+ flex-direction: column;
+ }
+
+ .cancel-btn,
+ .submit-btn {
+ width: 100%;
+ justify-content: center;
+ }
+
+ .info-item {
+ padding: var(--spacing-md) var(--spacing-lg);
+ }
+}
+
+@media (max-width: 480px) {
+ .profile-card,
+ .video-section-card {
+ padding: var(--spacing-lg);
+ border-radius: 12px;
+ }
+
+ .profile-title {
+ font-size: 24px !important;
+ }
+
+ .video-title {
+ font-size: 20px !important;
+ }
+
+ .info-item {
+ padding: var(--spacing-md);
+ }
}
diff --git a/services/web/src/components/profile/profile.tsx b/services/web/src/components/profile/profile.tsx
index f3a67ea9..5bd47d24 100644
--- a/services/web/src/components/profile/profile.tsx
+++ b/services/web/src/components/profile/profile.tsx
@@ -239,146 +239,199 @@ const Profile: React.FC = (props) => {
const renderChangePicButton = () => (
}
size="large"
+ className="change-pic-btn"
onClick={() => picInputRef.current?.click()}
/>
);
const renderProfileDescription = () => (
-
-
-
-
-
-
-
-
-
- {userData.name}
-
- {userData.email}
- }
- onClick={() => navigate("/change-email")}
- >
- Change email
-
-
-
- {userData.number}
- }
- onClick={() => navigate("/change-phone-number")}
- >
- Change phone number
-
-
-
-
-
+
+
+
+
+
+
+
+
+
Name
+
{userData.name}
+
+
+
+
Email
+
+ {userData.email}
+ }
+ onClick={() => navigate("/change-email")}
+ >
+ Change email
+
+
+
+
+
+
Phone Number
+
+ {userData.number}
+ }
+ onClick={() => navigate("/change-phone-number")}
+ >
+ Change phone number
+
+
+
+
+
+
+
);
const renderVideo = () => (
-
-
- <>
-
- >
-
-
+
+
+
);
return (
-
-
-
-
+
+
+
Your Profile
+
+ Manage your personal information and settings
+
+
+
+
+
-
-
-
- ) : (
- }
- size="large"
- onClick={() => videoInputRef.current?.click()}
- >
- Upload Video
-
- ),
- ]}
- />
-
- {videoData && (
-
-
-
- )}
+
+
+
+
+
My Personal Video
+
Max File Size: 10MB
+
+
+ {videoData ? (
+
+
+ Manage Video
+
+ ) : (
+ }
+ size="large"
+ className="upload-video-btn"
+ onClick={() => videoInputRef.current?.click()}
+ >
+ Upload Video
+
+ )}
+
+
+
+
+
+ {videoData && (
+ {renderVideo()}
+ )}
+
📹 Enter New Video Name}
+ open={isVideoModalOpen}
footer={null}
onCancel={() => setIsVideoModalOpen(false)}
+ className="video-name-modal"
+ centered
>
-
+
-
+
{hasErrored && {errorMessage}
}
-
+
+
+ }
+ >
+ Update Name
+
+
diff --git a/services/web/src/components/shop/shop.tsx b/services/web/src/components/shop/shop.tsx
index ed582d33..5155c574 100644
--- a/services/web/src/components/shop/shop.tsx
+++ b/services/web/src/components/shop/shop.tsx
@@ -74,8 +74,9 @@ const ProductDescription: React.FC<{
product: Product;
onBuyProduct: (product: Product) => void;
}> = ({ product, onBuyProduct }) => (
- <>
-
+
+
{product.name}
+
${Number(product.price).toFixed(2)}
- >
+
);
const Shop: React.FC = (props) => {
@@ -141,7 +142,7 @@ const Shop: React.FC = (props) => {
-
+
{products.map((product) => (