Add global mini-player and improve configuration
- Add global activeRoom store for persistent WebSocket connection - Add MiniPlayer component for playback controls across pages - Add chunked S3 streaming with 64KB chunks and Range support - Add queue item removal button - Move DB credentials to environment variables - Update .env.example with DB configuration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2,28 +2,22 @@
|
||||
<div class="room-page" v-if="room">
|
||||
<div class="room-header">
|
||||
<h1>{{ room.name }}</h1>
|
||||
<button class="btn-secondary" @click="leaveAndGoHome">Выйти из комнаты</button>
|
||||
</div>
|
||||
|
||||
<div class="room-layout">
|
||||
<div class="main-section">
|
||||
<AudioPlayer
|
||||
:ws="websocket"
|
||||
@player-action="handlePlayerAction"
|
||||
/>
|
||||
|
||||
<div class="queue-section card">
|
||||
<div class="queue-header">
|
||||
<h3>Очередь</h3>
|
||||
<button class="btn-secondary" @click="showAddTrack = true">Добавить</button>
|
||||
</div>
|
||||
<Queue :queue="roomStore.queue" @play-track="playTrack" />
|
||||
<Queue :queue="roomStore.queue" @play-track="playTrack" @remove-track="removeFromQueue" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="side-section">
|
||||
<ParticipantsList :participants="roomStore.participants" />
|
||||
<ChatWindow :room-id="roomId" :ws="websocket" />
|
||||
<ChatWindow :room-id="roomId" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,14 +33,11 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useRoomStore } from '../stores/room'
|
||||
import { useTracksStore } from '../stores/tracks'
|
||||
import { usePlayerStore } from '../stores/player'
|
||||
import { useWebSocket } from '../composables/useWebSocket'
|
||||
import { usePlayer } from '../composables/usePlayer'
|
||||
import AudioPlayer from '../components/player/AudioPlayer.vue'
|
||||
import { useActiveRoomStore } from '../stores/activeRoom'
|
||||
import Queue from '../components/room/Queue.vue'
|
||||
import ParticipantsList from '../components/room/ParticipantsList.vue'
|
||||
import ChatWindow from '../components/chat/ChatWindow.vue'
|
||||
@@ -54,45 +45,14 @@ import TrackList from '../components/tracks/TrackList.vue'
|
||||
import Modal from '../components/common/Modal.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const roomStore = useRoomStore()
|
||||
const tracksStore = useTracksStore()
|
||||
const playerStore = usePlayerStore()
|
||||
const activeRoomStore = useActiveRoomStore()
|
||||
|
||||
const roomId = route.params.id
|
||||
const room = ref(null)
|
||||
const showAddTrack = ref(false)
|
||||
|
||||
const { syncToState, setOnTrackEnded } = usePlayer()
|
||||
|
||||
function handleTrackEnded() {
|
||||
sendPlayerAction('next')
|
||||
}
|
||||
|
||||
function handleWsMessage(msg) {
|
||||
switch (msg.type) {
|
||||
case 'player_state':
|
||||
case 'sync_state':
|
||||
// Call syncToState BEFORE updating store so it can detect URL changes
|
||||
syncToState(msg)
|
||||
playerStore.setPlayerState(msg)
|
||||
break
|
||||
case 'user_joined':
|
||||
roomStore.addParticipant(msg.user)
|
||||
break
|
||||
case 'user_left':
|
||||
roomStore.removeParticipant(msg.user_id)
|
||||
break
|
||||
case 'queue_updated':
|
||||
roomStore.fetchQueue(roomId)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const { connect, disconnect, sendPlayerAction, connected } = useWebSocket(roomId, handleWsMessage)
|
||||
|
||||
const websocket = { sendPlayerAction, connected }
|
||||
|
||||
onMounted(async () => {
|
||||
await roomStore.fetchRoom(roomId)
|
||||
room.value = roomStore.currentRoom
|
||||
@@ -101,22 +61,12 @@ onMounted(async () => {
|
||||
await roomStore.fetchQueue(roomId)
|
||||
await tracksStore.fetchTracks()
|
||||
|
||||
// Set callback for when track ends
|
||||
setOnTrackEnded(handleTrackEnded)
|
||||
|
||||
connect()
|
||||
// Connect to room via global store
|
||||
activeRoomStore.connect(roomId, room.value.name)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
disconnect()
|
||||
})
|
||||
|
||||
function handlePlayerAction(action, position) {
|
||||
sendPlayerAction(action, position)
|
||||
}
|
||||
|
||||
function playTrack(track) {
|
||||
sendPlayerAction('set_track', null, track.id)
|
||||
activeRoomStore.sendPlayerAction('set_track', null, track.id)
|
||||
}
|
||||
|
||||
async function addTrackToQueue(track) {
|
||||
@@ -124,9 +74,8 @@ async function addTrackToQueue(track) {
|
||||
showAddTrack.value = false
|
||||
}
|
||||
|
||||
async function leaveAndGoHome() {
|
||||
await roomStore.leaveRoom(roomId)
|
||||
router.push('/')
|
||||
async function removeFromQueue(track) {
|
||||
await roomStore.removeFromQueue(roomId, track.id)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user