feat: mobile-responsive dashboard v2
This commit is contained in:
@@ -168,4 +168,24 @@ defineEmits<{
|
|||||||
.blk:hover {
|
.blk:hover {
|
||||||
background: rgba(251,113,133,.22);
|
background: rgba(251,113,133,.22);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.alertbar {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seg {
|
||||||
|
flex: 0 0 calc(50% - 4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sep {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blk {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -288,12 +288,12 @@ function handleReset() {
|
|||||||
@click="handleReset"
|
@click="handleReset"
|
||||||
>
|
>
|
||||||
<span class="btn-icon" v-html="icons.flow || ''"></span>
|
<span class="btn-icon" v-html="icons.flow || ''"></span>
|
||||||
Reset
|
<span class="reset-label">Reset</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="add-btn" @click="emit('add')">
|
<button class="add-btn" @click="emit('add')" title="Agent hinzufügen">
|
||||||
<span class="btn-icon" v-html="icons.plus || ''"></span>
|
<span class="btn-icon" v-html="icons.plus || ''"></span>
|
||||||
Agent hinzufügen
|
<span class="add-label">Agent hinzufügen</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -481,4 +481,28 @@ function handleReset() {
|
|||||||
:deep(.node.dragging) {
|
:deep(.node.dragging) {
|
||||||
cursor: grabbing;
|
cursor: grabbing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.add-label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reset-label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn {
|
||||||
|
width: 34px;
|
||||||
|
padding: 0;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reset-btn {
|
||||||
|
width: 30px;
|
||||||
|
padding: 0;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -251,6 +251,22 @@ watch(
|
|||||||
|
|
||||||
@keyframes blink { 50% { opacity: 0; } }
|
@keyframes blink { 50% { opacity: 0; } }
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.iris-panel {
|
||||||
|
width: 100%;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
max-height: 45vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-scroll {
|
||||||
|
max-height: 30vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand-btn {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Input ───────────────────────────────────── */
|
/* ── Input ───────────────────────────────────── */
|
||||||
.chat-in {
|
.chat-in {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
|
|||||||
@@ -146,4 +146,20 @@ function statusLabel(s: TaskItem['status']): string {
|
|||||||
padding: 12px;
|
padding: 12px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.tstrip {
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tstrip::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tcard {
|
||||||
|
flex: 0 0 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -6,6 +6,14 @@ import { useAgentStore } from '../../stores/agents'
|
|||||||
import { useTaskStore } from '../../stores/tasks'
|
import { useTaskStore } from '../../stores/tasks'
|
||||||
import { navigation, icons } from '../../composables/icons'
|
import { navigation, icons } from '../../composables/icons'
|
||||||
import type { NavGroupDef } from '../../composables/icons'
|
import type { NavGroupDef } from '../../composables/icons'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
mobileOpen?: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
close: []
|
||||||
|
}>()
|
||||||
import NavGroup from './NavGroup.vue'
|
import NavGroup from './NavGroup.vue'
|
||||||
import { initials } from '../../utils/format'
|
import { initials } from '../../utils/format'
|
||||||
|
|
||||||
@@ -63,7 +71,8 @@ const dynamicNavigation = computed<NavGroupDef[]>(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<aside class="sidebar">
|
<aside :class="['sidebar', { open: mobileOpen }]">
|
||||||
|
<button class="sidebar-close" @click="$emit('close')" v-html="icons.chevron_left || ''"></button>
|
||||||
<!-- Brand -->
|
<!-- Brand -->
|
||||||
<div class="side-top">
|
<div class="side-top">
|
||||||
<div class="brand-mark" v-html="icons.command || ''"></div>
|
<div class="brand-mark" v-html="icons.command || ''"></div>
|
||||||
@@ -171,6 +180,54 @@ const dynamicNavigation = computed<NavGroupDef[]>(() => {
|
|||||||
background: rgba(124,108,255,.06);
|
background: rgba(124,108,255,.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-close {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.sidebar {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
height: 100vh;
|
||||||
|
width: 280px;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
transition: transform 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar.open {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-close {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: absolute;
|
||||||
|
top: 18px;
|
||||||
|
right: 12px;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--tx-2);
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-close:hover {
|
||||||
|
background: rgba(124,108,255,.1);
|
||||||
|
color: var(--tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-close :deep(svg) {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
width: 34px;
|
width: 34px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
|
|||||||
@@ -4,10 +4,17 @@ import { icons } from '../../composables/icons'
|
|||||||
defineProps<{
|
defineProps<{
|
||||||
connected?: boolean
|
connected?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
'toggle-sidebar': []
|
||||||
|
}>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<header class="topbar">
|
<header class="topbar">
|
||||||
|
<!-- Hamburger (mobile only) -->
|
||||||
|
<button class="hamburger" @click="$emit('toggle-sidebar')" v-html="icons.list || ''"></button>
|
||||||
|
|
||||||
<!-- Search -->
|
<!-- Search -->
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<span class="search-icon" v-html="icons.search || ''"></span>
|
<span class="search-icon" v-html="icons.search || ''"></span>
|
||||||
@@ -24,9 +31,9 @@ defineProps<{
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<!-- Ask Iris Button -->
|
<!-- Ask Iris Button -->
|
||||||
<button class="btn btn-primary">
|
<button class="btn btn-primary ask-iris-btn">
|
||||||
<span class="btn-icon" v-html="icons.spark || ''"></span>
|
<span class="btn-icon" v-html="icons.spark || ''"></span>
|
||||||
Ask Iris
|
<span class="ask-label">Ask Iris</span>
|
||||||
</button>
|
</button>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
@@ -138,4 +145,65 @@ defineProps<{
|
|||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hamburger {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.topbar {
|
||||||
|
padding: 0 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search {
|
||||||
|
flex: 1;
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
border-radius: 9px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--tx-2);
|
||||||
|
cursor: pointer;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger:hover {
|
||||||
|
background: rgba(124,108,255,.1);
|
||||||
|
color: var(--tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger :deep(svg) {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ask-iris-btn {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 0;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
border-radius: 9px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ask-label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ask-iris-btn .btn-icon {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
* NexusLayout — V2 Dashboard Shell
|
* NexusLayout — V2 Dashboard Shell
|
||||||
* Flex row, 100vh, overflow hidden.
|
* Flex row, 100vh, overflow hidden.
|
||||||
* Sidebar (248px) + Main (flex:1, flex-column)
|
* Sidebar (248px) + Main (flex:1, flex-column)
|
||||||
|
* Mobile: Sidebar als Overlay mit Hamburger-Toggle
|
||||||
*/
|
*/
|
||||||
|
import { ref } from 'vue'
|
||||||
import { RouterView } from 'vue-router'
|
import { RouterView } from 'vue-router'
|
||||||
import { useAgentStore } from '../stores/agents'
|
import { useAgentStore } from '../stores/agents'
|
||||||
import GalaxyBackground from '../components/background/GalaxyBackground.vue'
|
import GalaxyBackground from '../components/background/GalaxyBackground.vue'
|
||||||
@@ -11,14 +13,35 @@ import Sidebar from '../components/layout/Sidebar.vue'
|
|||||||
import Topbar from '../components/layout/Topbar.vue'
|
import Topbar from '../components/layout/Topbar.vue'
|
||||||
|
|
||||||
const agentStore = useAgentStore()
|
const agentStore = useAgentStore()
|
||||||
|
|
||||||
|
/* ── Mobile Sidebar State ───────────────────────── */
|
||||||
|
const mobileMenuOpen = ref(false)
|
||||||
|
|
||||||
|
function closeMobileMenu() {
|
||||||
|
mobileMenuOpen.value = false
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="nexus-layout">
|
<div class="nexus-layout">
|
||||||
<GalaxyBackground />
|
<GalaxyBackground />
|
||||||
<Sidebar />
|
<Sidebar
|
||||||
|
:mobile-open="mobileMenuOpen"
|
||||||
|
@close="closeMobileMenu"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Mobile Backdrop -->
|
||||||
|
<div
|
||||||
|
v-if="mobileMenuOpen"
|
||||||
|
class="mobile-backdrop"
|
||||||
|
@click="closeMobileMenu"
|
||||||
|
></div>
|
||||||
|
|
||||||
<main class="nexus-main">
|
<main class="nexus-main">
|
||||||
<Topbar :connected="agentStore.isConnected" />
|
<Topbar
|
||||||
|
:connected="agentStore.isConnected"
|
||||||
|
@toggle-sidebar="mobileMenuOpen = !mobileMenuOpen"
|
||||||
|
/>
|
||||||
<div class="nexus-content">
|
<div class="nexus-content">
|
||||||
<RouterView />
|
<RouterView />
|
||||||
</div>
|
</div>
|
||||||
@@ -49,4 +72,22 @@ const agentStore = useAgentStore()
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mobile-backdrop {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.nexus-main {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-backdrop {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 99;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -177,4 +177,16 @@ onUnmounted(() => {
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.board-body {
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 8px;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stage {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user