fix: move companion indicator into sidebar, inline design
Move CompanionIndicator from global App.vue overlay to DashboardSidebar next to ControllerIndicator. Redesigned as inline sidebar element with Tailwind classes — shows muted 'Relay' when idle, orange 'Companion' with pulse dot when actively receiving input. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,9 +37,6 @@
|
||||
<!-- PWA Install Prompt (Install app, not just Add to Home Screen) -->
|
||||
<PWAInstallPrompt />
|
||||
|
||||
<!-- Companion app connected indicator -->
|
||||
<CompanionIndicator />
|
||||
|
||||
<!-- Toast notifications - top right, glass style, any page -->
|
||||
<Teleport to="body">
|
||||
<Transition name="toast">
|
||||
@@ -78,7 +75,7 @@ import AppLauncherOverlay from './components/AppLauncherOverlay.vue'
|
||||
import ToastStack from './components/ToastStack.vue'
|
||||
import Screensaver from './components/Screensaver.vue'
|
||||
import HelpGuideModal from './components/HelpGuideModal.vue'
|
||||
import CompanionIndicator from './components/CompanionIndicator.vue'
|
||||
|
||||
import { useControllerNav } from '@/composables/useControllerNav'
|
||||
import { playKeyboardTypingSound } from '@/composables/useLoginSounds'
|
||||
import { useSpotlightStore } from '@/stores/spotlight'
|
||||
|
||||
@@ -1,28 +1,36 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="relayConnected"
|
||||
class="companion-indicator"
|
||||
:title="companionActive ? 'Companion app sending input' : 'Relay ready — waiting for companion'"
|
||||
>
|
||||
<!-- Wire going down off-screen -->
|
||||
<div class="companion-wire" :class="{ active: companionActive }" />
|
||||
|
||||
<!-- Gamepad body -->
|
||||
<div class="companion-pad" :class="{ connected: companionActive, 'input-flash': companionInputActive }">
|
||||
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<!-- Controller body -->
|
||||
<rect x="3" y="7" width="18" height="11" rx="3" stroke="currentColor" stroke-width="1.5" />
|
||||
<!-- D-pad vertical -->
|
||||
<Transition name="companion-slide">
|
||||
<div
|
||||
v-if="relayConnected"
|
||||
class="flex items-center gap-2 px-3 py-2 rounded-lg transition-all duration-300"
|
||||
:class="companionActive
|
||||
? 'bg-orange-500/10 border border-orange-500/20'
|
||||
: 'bg-white/5 border border-white/10'"
|
||||
:title="companionActive ? 'Companion app connected' : 'Remote relay ready'"
|
||||
>
|
||||
<svg
|
||||
class="w-5 h-5 flex-shrink-0 transition-colors duration-200"
|
||||
:class="companionActive
|
||||
? (companionInputActive ? 'text-orange-400' : 'text-orange-400/70')
|
||||
: 'text-white/20'"
|
||||
fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"
|
||||
>
|
||||
<rect x="3" y="7" width="18" height="11" rx="3" stroke-width="1.5" />
|
||||
<rect x="7.5" y="10" width="2" height="5" rx="0.5" fill="currentColor" />
|
||||
<!-- D-pad horizontal -->
|
||||
<rect x="6" y="11.5" width="5" height="2" rx="0.5" fill="currentColor" />
|
||||
<!-- A button -->
|
||||
<circle cx="16" cy="11" r="1.2" fill="currentColor" />
|
||||
<!-- B button -->
|
||||
<circle cx="14" cy="13.5" r="1.2" fill="currentColor" />
|
||||
</svg>
|
||||
<span
|
||||
class="text-xs hidden sm:inline transition-colors duration-200"
|
||||
:class="companionActive ? 'text-orange-400/80' : 'text-white/30'"
|
||||
>{{ companionActive ? 'Companion' : 'Relay' }}</span>
|
||||
<span
|
||||
v-if="companionInputActive"
|
||||
class="ml-auto w-1.5 h-1.5 rounded-full bg-orange-400 animate-pulse"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -30,57 +38,8 @@ import { relayConnected, companionActive, companionInputActive } from '@/api/rem
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.companion-indicator {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 24px;
|
||||
z-index: 9998;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.4s ease;
|
||||
}
|
||||
|
||||
/* Idle state — subtle, muted */
|
||||
.companion-pad {
|
||||
color: rgba(255, 255, 255, 0.15);
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
border-bottom: none;
|
||||
border-radius: 8px 8px 0 0;
|
||||
padding: 6px 10px 4px;
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
transition: color 0.3s, border-color 0.3s, box-shadow 0.3s, background 0.3s;
|
||||
order: 0;
|
||||
}
|
||||
|
||||
/* Companion actively sending */
|
||||
.companion-pad.connected {
|
||||
color: rgba(247, 147, 26, 0.7);
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
border-color: rgba(247, 147, 26, 0.3);
|
||||
}
|
||||
|
||||
/* Input flash — brightens on each event */
|
||||
.companion-pad.input-flash {
|
||||
color: rgba(247, 147, 26, 1);
|
||||
border-color: rgba(247, 147, 26, 0.6);
|
||||
box-shadow: 0 0 12px rgba(247, 147, 26, 0.25);
|
||||
}
|
||||
|
||||
/* Wire */
|
||||
.companion-wire {
|
||||
width: 2px;
|
||||
height: 20px;
|
||||
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));
|
||||
border-radius: 1px;
|
||||
order: 1;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.companion-wire.active {
|
||||
background: linear-gradient(to bottom, rgba(247, 147, 26, 0.5), rgba(247, 147, 26, 0.15));
|
||||
}
|
||||
.companion-slide-enter-active { transition: opacity 0.3s ease, max-height 0.3s ease; }
|
||||
.companion-slide-leave-active { transition: opacity 0.2s ease, max-height 0.2s ease; }
|
||||
.companion-slide-enter-from,
|
||||
.companion-slide-leave-to { opacity: 0; max-height: 0; }
|
||||
</style>
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
|
||||
<div class="sidebar-controller px-6 pb-2 shrink-0">
|
||||
<ControllerIndicator />
|
||||
<CompanionIndicator />
|
||||
</div>
|
||||
|
||||
<!-- Online status -->
|
||||
@@ -106,6 +107,7 @@ import { useMeshStore } from '@/stores/mesh'
|
||||
import AnimatedLogo from '@/components/AnimatedLogo.vue'
|
||||
import OnlineStatusPill from '@/components/OnlineStatusPill.vue'
|
||||
import ControllerIndicator from '@/components/ControllerIndicator.vue'
|
||||
import CompanionIndicator from '@/components/CompanionIndicator.vue'
|
||||
import ModeSwitcher from '@/components/ModeSwitcher.vue'
|
||||
|
||||
interface NavItem {
|
||||
|
||||
Reference in New Issue
Block a user