diff --git a/frontend-vue/src/components/chat/MessageItem.vue b/frontend-vue/src/components/chat/MessageItem.vue
index 9546f05..d3e6292 100644
--- a/frontend-vue/src/components/chat/MessageItem.vue
+++ b/frontend-vue/src/components/chat/MessageItem.vue
@@ -152,126 +152,77 @@ const handleKeydown = (event: KeyboardEvent) => {
\ No newline at end of file
diff --git a/frontend-vue/src/components/sidebar/ChannelList.vue b/frontend-vue/src/components/sidebar/ChannelList.vue
index 8a3cba7..a75891e 100644
--- a/frontend-vue/src/components/sidebar/ChannelList.vue
+++ b/frontend-vue/src/components/sidebar/ChannelList.vue
@@ -8,6 +8,7 @@
:is-active="channel.id === currentChannelId"
:unread-count="unreadCounts[channel.id]"
@select="$emit('select-channel', $event)"
+ @info="$emit('channel-info', $event)"
/>
@@ -27,6 +28,7 @@ defineProps()
defineEmits<{
'select-channel': [channelId: number]
+ 'channel-info': [channel: Channel]
}>()
diff --git a/frontend-vue/src/components/sidebar/ChannelListItem.vue b/frontend-vue/src/components/sidebar/ChannelListItem.vue
index 0e5f07b..9a1ee4c 100644
--- a/frontend-vue/src/components/sidebar/ChannelListItem.vue
+++ b/frontend-vue/src/components/sidebar/ChannelListItem.vue
@@ -43,6 +43,7 @@ defineProps()
defineEmits<{
select: [channelId: number]
+ info: [channel: Channel]
}>()
@@ -52,6 +53,12 @@ defineEmits<{
margin: 0;
}
+.channel-wrapper {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
.channel-button {
display: flex;
align-items: center;
@@ -117,6 +124,35 @@ defineEmits<{
color: #3b82f6;
}
+.channel-info-button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 2rem;
+ height: 2rem;
+ padding: 0;
+ background: none;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 1rem;
+ opacity: 0.6;
+ transition: all 0.2s ease;
+ flex-shrink: 0;
+}
+
+.channel-info-button:hover {
+ opacity: 1;
+ background: rgba(0, 0, 0, 0.05);
+}
+
+.channel-info-button:focus {
+ outline: none;
+ background: rgba(59, 130, 246, 0.1);
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
+ opacity: 1;
+}
+
/* Dark mode */
@media (prefers-color-scheme: dark) {
.channel-button {
@@ -142,5 +178,14 @@ defineEmits<{
.channel-item--active .channel-button:hover {
background: #2563eb;
}
+
+ .channel-info-button:hover {
+ background: rgba(255, 255, 255, 0.1);
+ }
+
+ .channel-info-button:focus {
+ background: rgba(96, 165, 250, 0.1);
+ box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.2);
+ }
}
\ No newline at end of file
diff --git a/frontend-vue/src/components/sidebar/Sidebar.vue b/frontend-vue/src/components/sidebar/Sidebar.vue
index 77daab7..a120e34 100644
--- a/frontend-vue/src/components/sidebar/Sidebar.vue
+++ b/frontend-vue/src/components/sidebar/Sidebar.vue
@@ -18,6 +18,7 @@
:current-channel-id="currentChannelId"
:unread-counts="unreadCounts"
@select-channel="$emit('select-channel', $event)"
+ @channel-info="$emit('channel-info', $event)"
/>
@@ -50,6 +51,7 @@ defineProps()
defineEmits<{
'create-channel': []
'select-channel': [channelId: number]
+ 'channel-info': [channel: Channel]
'settings': []
}>()
diff --git a/frontend-vue/src/stores/app.ts b/frontend-vue/src/stores/app.ts
index abb33d2..37e6a43 100644
--- a/frontend-vue/src/stores/app.ts
+++ b/frontend-vue/src/stores/app.ts
@@ -112,7 +112,7 @@ export const useAppStore = defineStore('app', () => {
const updateSettings = async (newSettings: Partial) => {
settings.value = { ...settings.value, ...newSettings }
- await set('app_settings', settings.value)
+ await set('app_settings', JSON.parse(JSON.stringify(settings.value)))
}
const loadState = async () => {
diff --git a/frontend-vue/src/style.css b/frontend-vue/src/style.css
index 72458b6..399a4b2 100644
--- a/frontend-vue/src/style.css
+++ b/frontend-vue/src/style.css
@@ -1,18 +1,4 @@
-:root {
- font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
- line-height: 1.5;
- font-weight: 400;
-
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
-
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
+/* Minimal reset styles only */
* {
box-sizing: border-box;
}
@@ -23,6 +9,13 @@ body {
width: 100vw;
height: 100vh;
overflow: hidden;
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
}
#app {
@@ -33,61 +26,6 @@ body {
overflow: hidden;
}
-/* Button styles */
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
- color: inherit;
- cursor: pointer;
- transition: border-color 0.25s;
- outline: none;
-}
-
-button:hover {
- border-color: #646cff;
-}
-
-button:focus,
-button:focus-visible {
- outline: 2px solid #646cff;
- outline-offset: 2px;
-}
-
-button:disabled {
- opacity: 0.6;
- cursor: not-allowed;
-}
-
-/* Input styles */
-input, textarea {
- border-radius: 8px;
- border: 1px solid #3a3a3a;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-family: inherit;
- background-color: #2a2a2a;
- color: inherit;
- outline: none;
-}
-
-input:focus, textarea:focus {
- border-color: #646cff;
- outline: 2px solid #646cff;
- outline-offset: 2px;
-}
-
-/* List styles */
-ul {
- list-style: none;
- padding: 0;
- margin: 0;
-}
-
/* Accessibility helpers */
.sr-only {
position: absolute;
@@ -99,27 +37,4 @@ ul {
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
-}
-
-/* Focus indicators */
-.focus-visible {
- outline: 2px solid #646cff;
- outline-offset: 2px;
-}
-
-/* Light mode */
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- }
-
- button {
- background-color: #f9f9f9;
- }
-
- input, textarea {
- background-color: #ffffff;
- border-color: #d1d5db;
- }
}
\ No newline at end of file
diff --git a/frontend-vue/src/views/MainView.vue b/frontend-vue/src/views/MainView.vue
index 17af2fd..e1166bb 100644
--- a/frontend-vue/src/views/MainView.vue
+++ b/frontend-vue/src/views/MainView.vue
@@ -7,6 +7,7 @@
:unread-counts="unreadCounts"
@create-channel="showChannelDialog = true"
@select-channel="selectChannel"
+ @channel-info="handleChannelInfo"
@settings="showSettings = true"
/>
@@ -80,6 +81,14 @@
@sent="handleCameraSent"
/>
+
+
+
+
@@ -108,9 +117,10 @@ import SearchDialog from '@/components/dialogs/SearchDialog.vue'
import FileUploadDialog from '@/components/dialogs/FileUploadDialog.vue'
import VoiceRecordingDialog from '@/components/dialogs/VoiceRecordingDialog.vue'
import CameraCaptureDialog from '@/components/dialogs/CameraCaptureDialog.vue'
+import ChannelInfoDialog from '@/components/dialogs/ChannelInfoDialog.vue'
// Types
-import type { ExtendedMessage } from '@/types'
+import type { ExtendedMessage, Channel } from '@/types'
const router = useRouter()
const appStore = useAppStore()
@@ -130,12 +140,16 @@ const messageInput = ref()
// Dialog states
const showChannelDialog = ref(false)
+const showChannelInfoDialog = ref(false)
const showSettings = ref(false)
const showSearchDialog = ref(false)
const showFileDialog = ref(false)
const showVoiceDialog = ref(false)
const showCameraDialog = ref(false)
+// Channel info state
+const selectedChannelForInfo = ref(null)
+
// Mock unread counts (implement real logic later)
const unreadCounts = ref>({})
@@ -362,6 +376,11 @@ const handleChannelCreated = async (channelId: number) => {
await selectChannel(channelId)
}
+const handleChannelInfo = (channel: Channel) => {
+ selectedChannelForInfo.value = channel
+ showChannelInfoDialog.value = true
+}
+
const isUnsentMessage = (messageId: string | number): boolean => {
return typeof messageId === 'string' && messageId.startsWith('unsent_')
}