Library: - 添加 checkbox 和鼠标框选功能 - Unregistered 卡片添加快速注册按钮 - 状态标签移至左下方,人脸图标移至左侧中间 - Deep Scan 改为 unregister -> register -> process - 完整国际化(日语、繁体中文、英语) PeopleView: - 修复卡片不显示问题(使用 get_file_traces API) - 移除对 identity_id 字段的依赖 其他: - 添加日语语言包 - 添加 useDragSelect composable - 新增文档:Face Bbox Null Bug Report
329 lines
20 KiB
Vue
329 lines
20 KiB
Vue
<script setup lang="ts">
|
||
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import AgentTip from './components/AgentTip.vue'
|
||
import BuildVersion from './components/BuildVersion.vue'
|
||
import { loadUserBehavior } from '@/stores/agentStore'
|
||
import { useI18n } from 'vue-i18n'
|
||
import { changeLanguage, getCurrentLanguage } from './locales'
|
||
import { useAdvancedMode } from '@/stores/advancedMode'
|
||
import { useTheme } from '@/stores/themeStore'
|
||
|
||
const { t } = useI18n()
|
||
const router = useRouter()
|
||
const { isAdvanced, toggleAdvanced } = useAdvancedMode()
|
||
const { theme, toggleTheme } = useTheme()
|
||
|
||
const appZoom = ref(100)
|
||
const loggedInUser = ref(localStorage.getItem('username') || '')
|
||
const currentLanguage = ref(getCurrentLanguage())
|
||
|
||
const sidebarWidth = ref(240)
|
||
const isDragging = ref(false)
|
||
const sidebarCollapsed = ref(true)
|
||
const isMobile = ref(window.innerWidth < 768)
|
||
const mobileOpen = ref(false)
|
||
|
||
function toggleSidebar() {
|
||
if (isMobile.value) {
|
||
mobileOpen.value = !mobileOpen.value
|
||
} else {
|
||
sidebarCollapsed.value = !sidebarCollapsed.value
|
||
localStorage.setItem('sidebar_collapsed', String(sidebarCollapsed.value))
|
||
}
|
||
}
|
||
|
||
function closeMobileDrawer() {
|
||
mobileOpen.value = false
|
||
}
|
||
|
||
function handleResize() {
|
||
isMobile.value = window.innerWidth < 768
|
||
if (!isMobile.value) mobileOpen.value = false
|
||
}
|
||
|
||
function refreshUser() {
|
||
const user = localStorage.getItem('username') || ''
|
||
loggedInUser.value = user
|
||
}
|
||
|
||
function handleLogout() {
|
||
if (!confirm('Are you sure you want to logout?')) return
|
||
localStorage.removeItem('token')
|
||
localStorage.removeItem('username')
|
||
localStorage.removeItem('expires_at')
|
||
loggedInUser.value = ''
|
||
router.push('/login')
|
||
}
|
||
|
||
function onChangeLanguage() {
|
||
changeLanguage(currentLanguage.value)
|
||
}
|
||
|
||
let systemMedia: MediaQueryList | null = null
|
||
|
||
function handleKeydown(e: KeyboardEvent) {
|
||
if ((e.metaKey || e.ctrlKey)) {
|
||
if (e.key === '=' || e.key === '+') {
|
||
e.preventDefault()
|
||
appZoom.value = Math.min(appZoom.value + 10, 300)
|
||
document.documentElement.style.zoom = appZoom.value + '%'
|
||
} else if (e.key === '-') {
|
||
e.preventDefault()
|
||
appZoom.value = Math.max(appZoom.value - 10, 50)
|
||
document.documentElement.style.zoom = appZoom.value + '%'
|
||
} else if (e.key === '0') {
|
||
e.preventDefault()
|
||
appZoom.value = 100
|
||
document.documentElement.style.zoom = '100%'
|
||
}
|
||
}
|
||
}
|
||
|
||
function startDrag(e: MouseEvent) {
|
||
isDragging.value = true
|
||
document.body.style.cursor = 'col-resize'
|
||
document.body.style.userSelect = 'none'
|
||
}
|
||
|
||
function handleDrag(e: MouseEvent) {
|
||
if (!isDragging.value) return
|
||
const newWidth = e.clientX - 28
|
||
sidebarWidth.value = Math.max(180, Math.min(400, newWidth))
|
||
}
|
||
|
||
function stopDrag() {
|
||
isDragging.value = false
|
||
document.body.style.cursor = ''
|
||
document.body.style.userSelect = ''
|
||
}
|
||
|
||
onMounted(() => {
|
||
document.addEventListener('keydown', handleKeydown)
|
||
document.addEventListener('mousemove', handleDrag)
|
||
document.addEventListener('mouseup', stopDrag)
|
||
window.addEventListener('resize', handleResize)
|
||
|
||
refreshUser()
|
||
loadUserBehavior()
|
||
|
||
window.addEventListener('ms-login', () => {
|
||
refreshUser()
|
||
loadUserBehavior()
|
||
})
|
||
})
|
||
|
||
watch(() => router.currentRoute.value.path, () => {
|
||
refreshUser()
|
||
closeMobileDrawer()
|
||
})
|
||
|
||
onUnmounted(() => {
|
||
document.removeEventListener('keydown', handleKeydown)
|
||
document.removeEventListener('mousemove', handleDrag)
|
||
document.removeEventListener('mouseup', stopDrag)
|
||
window.removeEventListener('resize', handleResize)
|
||
})
|
||
</script>
|
||
<template>
|
||
<BuildVersion />
|
||
<div id="app" class="ms-app" :class="{ 'ms-app-mobile': isMobile }" :data-current-login="'guest'">
|
||
<div v-if="isMobile && mobileOpen" class="ms-overlay" @click="closeMobileDrawer"></div>
|
||
<aside class="ms-side" :class="{ collapsed: !isMobile && sidebarCollapsed, 'mobile-open': isMobile && mobileOpen }" :style="isMobile ? {} : { width: sidebarCollapsed ? '62px' : sidebarWidth + 'px', minWidth: sidebarCollapsed ? '62px' : sidebarWidth + 'px' }">
|
||
<div class="gs-sidebar-toggle" @click="toggleSidebar">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||
:style="{ transform: sidebarCollapsed ? 'rotate(0deg)' : 'rotate(180deg)' }">
|
||
<polyline points="9 18 15 12 9 6"/>
|
||
</svg>
|
||
</div>
|
||
<div class="gs-logo" :class="{ 'gs-logo-collapsed': sidebarCollapsed }">{{ sidebarCollapsed ? 'WS' : 'Workspace' }}</div>
|
||
<nav class="gs-nav">
|
||
<router-link to="/search" class="gs-nav-item" active-class="active">
|
||
<svg class="gs-nav-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<circle cx="11" cy="11" r="8"/>
|
||
<path d="M21 21l-4.35-4.35"/>
|
||
</svg>
|
||
<span class="gs-nav-label">{{ t('nav.search') }}</span>
|
||
</router-link>
|
||
<router-link to="/library" class="gs-nav-item" active-class="active">
|
||
<svg class="gs-nav-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<rect x="3" y="3" width="7" height="7" rx="1"/>
|
||
<rect x="14" y="3" width="7" height="7" rx="1"/>
|
||
<rect x="3" y="14" width="7" height="7" rx="1"/>
|
||
<rect x="14" y="14" width="7" height="7" rx="1"/>
|
||
</svg>
|
||
<span class="gs-nav-label">{{ t('nav.library') }}</span>
|
||
</router-link>
|
||
<router-link to="/admin" class="gs-nav-item" active-class="active">
|
||
<svg class="gs-nav-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<circle cx="12" cy="12" r="3"/>
|
||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
||
</svg>
|
||
<span class="gs-nav-label">{{ t('nav.admin') }}</span>
|
||
</router-link>
|
||
<router-link to="/client" class="gs-nav-item" active-class="active">
|
||
<svg class="gs-nav-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
|
||
</svg>
|
||
<span class="gs-nav-label">{{ t('nav.client') }}</span>
|
||
</router-link>
|
||
</nav>
|
||
<div class="gs-divider" :class="{ 'gs-hidden': sidebarCollapsed }"></div>
|
||
<div class="gs-footer" :class="{ 'gs-hidden': sidebarCollapsed }">
|
||
<div class="gs-controls">
|
||
<select v-model="currentLanguage" @change="onChangeLanguage" class="gs-lang-select">
|
||
<option value="en">{{ $t('language.en') }}</option>
|
||
<option value="zh-TW">{{ $t('language.zh-TW') }}</option>
|
||
<option value="ja">{{ $t('language.ja') }}</option>
|
||
<option value="auto">{{ $t('language.auto') }}</option>
|
||
</select>
|
||
<button class="gs-control-btn" :class="{ 'gs-control-active': isAdvanced }" :title="isAdvanced ? 'Advanced Mode: ON' : 'Advanced Mode: OFF'" @click="toggleAdvanced">
|
||
<svg v-if="isAdvanced" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="11" width="16" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 7.9-2"/></svg>
|
||
<svg v-else width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="11" width="16" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>
|
||
</button>
|
||
<button class="gs-control-btn" :title="theme === 'dark' ? 'Switch to Light' : 'Switch to Dark'" @click="toggleTheme">{{ theme === 'dark' ? '☀️' : '🌙' }}</button>
|
||
</div>
|
||
<div class="gs-account-row">
|
||
<template v-if="loggedInUser">
|
||
<span class="gs-account-name">{{ loggedInUser }}</span>
|
||
<button class="gs-logout-btn" @click="handleLogout" title="Logout">⏻ {{ t('common.logout') }}</button>
|
||
</template>
|
||
<template v-else>
|
||
<router-link to="/login" class="gs-login-link">{{ t('common.login') }}</router-link>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
<div class="gs-footer-compact">
|
||
<template v-if="loggedInUser">
|
||
<button class="gs-logout-btn-compact" @click="handleLogout" title="Logout">⏻</button>
|
||
</template>
|
||
<template v-else>
|
||
<router-link to="/login" class="gs-login-link-compact" title="Login">⏻</router-link>
|
||
</template>
|
||
</div>
|
||
</aside>
|
||
<div class="ms-divider" :class="{ 'ms-divider-hidden': sidebarCollapsed }" @mousedown="startDrag"></div>
|
||
<main class="ms-main">
|
||
<div v-if="isMobile" class="ms-mobile-header">
|
||
<button class="ms-mobile-hamburger" @click="toggleSidebar" aria-label="Menu">
|
||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
|
||
</button>
|
||
<span class="ms-mobile-title">Momentry Studio</span>
|
||
</div>
|
||
<router-view />
|
||
</main>
|
||
<nav v-if="isMobile" class="ms-bottom-nav">
|
||
<router-link to="/search" class="ms-bottom-nav-item" active-class="active" @click="closeMobileDrawer">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg>
|
||
<span>Search</span>
|
||
</router-link>
|
||
<router-link to="/library" class="ms-bottom-nav-item" active-class="active" @click="closeMobileDrawer">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
|
||
<span>Library</span>
|
||
</router-link>
|
||
<router-link to="/admin" class="ms-bottom-nav-item" active-class="active" @click="closeMobileDrawer">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
||
<span>Admin</span>
|
||
</router-link>
|
||
<router-link to="/client" class="ms-bottom-nav-item" active-class="active" @click="closeMobileDrawer">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8"/><path d="M12 17v4"/></svg>
|
||
<span>Client</span>
|
||
</router-link>
|
||
<router-link v-if="!loggedInUser" to="/login" class="ms-bottom-nav-item" active-class="active" @click="closeMobileDrawer">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/><polyline points="10 17 15 12 10 7"/><line x1="15" y1="12" x2="3" y2="12"/></svg>
|
||
<span>Login</span>
|
||
</router-link>
|
||
<button v-else class="ms-bottom-nav-item ms-bottom-nav-btn-logout" @click="handleLogout">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
|
||
<span>Logout</span>
|
||
</button>
|
||
</nav>
|
||
<AgentTip v-if="loggedInUser" />
|
||
</div>
|
||
</template>
|
||
|
||
<style>
|
||
@import './assets/wordpress-exact.css';
|
||
html, body { height: 100%; margin: 0; }
|
||
</style>
|
||
|
||
<style scoped>
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
#app, .ms-app { background: var(--background-color) !important; display: flex; max-width: 1400px; margin: 0 auto; padding: 28px; gap: 0; height: 100vh; box-sizing: border-box; }
|
||
.ms-side { width: 240px; min-width: 240px; background: var(--card-background) !important; border-radius: 18px; padding: 18px 14px; box-shadow: var(--shadow); display: flex; flex-direction: column; position: relative; overflow: visible; height: 100%; }
|
||
.ms-side.collapsed { align-items: center; padding: 18px 8px; }
|
||
.ms-side.collapsed .gs-nav { align-items: center; width: 100%; }
|
||
.ms-side.collapsed .gs-nav-item { justify-content: center; padding: 0; width: 44px; }
|
||
.ms-side.collapsed .gs-nav-label { display: none; }
|
||
.ms-side.collapsed .gs-nav-icon { width: 22px; height: 22px; }
|
||
.gs-footer-compact { display: none; }
|
||
.ms-side.collapsed .gs-footer-compact { display: flex; flex-direction: column; align-items: center; margin-top: auto; padding: 10px 0; }
|
||
.gs-logout-btn-compact, .gs-login-link-compact { background: none; border: 1px solid var(--border-color); cursor: pointer; font-size: 16px; color: var(--text-secondary); width: 36px; height: 36px; border-radius: 8px; display: flex; align-items: center; justify-content: center; text-decoration: none; transition: all .15s; }
|
||
.gs-logout-btn-compact:hover { color: var(--danger-color); border-color: var(--danger-color); background: var(--danger-background); }
|
||
.gs-login-link-compact:hover { color: var(--text-primary); border-color: var(--text-primary); }
|
||
.gs-hidden { display: none !important; }
|
||
.gs-sidebar-toggle { display: flex; align-items: center; justify-content: flex-end; padding: 0 4px 12px 4px; cursor: pointer; color: var(--text-secondary); flex-shrink: 0; }
|
||
.gs-sidebar-toggle svg { transition: transform 0.2s; }
|
||
.ms-side.collapsed .gs-sidebar-toggle { justify-content: center; width: 100%; }
|
||
.gs-logo-collapsed { text-align: center; padding: 8px 4px 16px 4px; font-size: 14px; }
|
||
.ms-divider { width: 28px; flex-shrink: 0; cursor: col-resize; display: flex; align-items: center; justify-content: center; }
|
||
.ms-divider-hidden { cursor: default; pointer-events: none; opacity: 0; }
|
||
.ms-divider::after { content: ''; width: 4px; height: 40px; background: var(--border-color); border-radius: 2px; transition: background 0.2s, height 0.2s; }
|
||
.ms-divider:hover::after { background: var(--primary-color); height: 60px; }
|
||
.gs-logo { font-size: 15px; font-weight: 600; color: var(--text-primary); padding: 8px 12px 16px 12px; flex-shrink: 0; }
|
||
.gs-nav { display: flex; flex-direction: column; gap: 4px; flex-shrink: 0; }
|
||
.gs-nav-item { display: flex; align-items: center; gap: 12px; height: 48px; padding: 0 12px; border-radius: 10px; text-decoration: none; color: var(--text-primary) !important; font-weight: 500; font-size: 16px; line-height: 1; background: transparent !important; box-sizing: border-box; transition: all 0.15s; }
|
||
.gs-nav-item:hover { background: var(--hover-background) !important; color: var(--primary-color) !important; }
|
||
.gs-nav-item.active { background: var(--hover-background) !important; color: var(--primary-color) !important; font-weight: 600; }
|
||
.gs-nav-icon { width: 22px; height: 22px; flex-shrink: 0; }
|
||
.gs-divider { height: 1px; background: var(--border-light); margin: 14px 8px; flex-shrink: 0; }
|
||
.gs-footer { margin-top: auto; padding: 10px 8px; border-radius: 12px; background: var(--hover-background); flex-shrink: 0; display: flex; flex-direction: column; gap: 8px; }
|
||
.gs-controls { display: flex; align-items: center; gap: 6px; }
|
||
.gs-control-btn { width: 28px; height: 28px; border: 1px solid var(--border-color); border-radius: 6px; background: var(--card-background); cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; transition: all 0.15s; color: #888; flex-shrink: 0; filter: grayscale(1); }
|
||
.gs-control-btn:hover { background: var(--border-light); border-color: var(--text-secondary); filter: grayscale(0); }
|
||
.gs-control-active { color: var(--primary-color); border-color: var(--primary-color); background: var(--primary-color-light, rgba(66,133,244,0.1)); filter: grayscale(0); }
|
||
.gs-lang-switcher { width: 100%; }
|
||
.gs-lang-select { width: 100%; padding: 6px 8px; border: 1px solid var(--border-color); border-radius: 6px; background: var(--card-background); font-size: 12px; font-family: inherit; color: var(--text-secondary); cursor: pointer; outline: none; }
|
||
.gs-lang-select:focus { border-color: var(--text-primary); }
|
||
.gs-account-row { display: flex; align-items: center; justify-content: center; gap: 8px; }
|
||
.gs-account-name { font-size: 12px; color: var(--text-secondary); }
|
||
.gs-logout-btn { background: none; border: 1px solid var(--border-color); cursor: pointer; font-size: 13px; color: var(--text-secondary); padding: 3px 8px; border-radius: 6px; transition: all .15s; margin-left: 6px; }
|
||
.gs-logout-btn:hover { color: var(--danger-color); border-color: var(--danger-color); background: var(--danger-background); }
|
||
.gs-login-link { font-size: 12px; color: var(--text-secondary); text-decoration: none; }
|
||
.gs-login-link:hover { color: var(--text-primary); }
|
||
.ms-main { flex: 1; min-width: 0; background: var(--card-background) !important; border-radius: 18px; padding: 36px 42px; overflow-y: auto; overflow-x: hidden; height: 100%; }
|
||
.ms-content { max-width: 1200px; }
|
||
|
||
/* Mobile overlay */
|
||
.ms-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 999; }
|
||
|
||
/* Mobile header */
|
||
.ms-mobile-header { display: flex; align-items: center; gap: 10px; padding-bottom: 12px; }
|
||
.ms-mobile-hamburger { background: none; border: none; cursor: pointer; color: var(--text-primary); padding: 4px; }
|
||
.ms-mobile-title { font-size: 15px; font-weight: 600; color: var(--text-primary); }
|
||
|
||
/* Bottom nav */
|
||
.ms-bottom-nav { display: flex; position: fixed; bottom: 0; left: 0; right: 0; z-index: 998;
|
||
background: var(--card-background); border-top: 1px solid var(--border-light);
|
||
justify-content: space-around; padding: 6px 0 env(safe-area-inset-bottom, 6px) 0;
|
||
box-shadow: 0 -2px 8px rgba(0,0,0,0.06); }
|
||
.ms-bottom-nav-item { display: flex; flex-direction: column; align-items: center; gap: 2px;
|
||
text-decoration: none; color: var(--text-secondary); font-size: 10px; padding: 2px 8px; }
|
||
.ms-bottom-nav-item.active { color: var(--primary-color); }
|
||
.ms-bottom-nav-item svg { width: 20px; height: 20px; }
|
||
.ms-bottom-nav-btn-logout { background: none; border: none; cursor: pointer; }
|
||
|
||
@media (max-width: 767px) {
|
||
.ms-app { padding: 0; max-width: 100%; height: 100dvh; }
|
||
.ms-app.ms-app-mobile { padding: 0; }
|
||
.ms-side { position: fixed; left: 0; top: 0; bottom: 0; z-index: 1000;
|
||
transform: translateX(-100%); transition: transform 0.25s ease;
|
||
width: 260px !important; min-width: 260px !important; border-radius: 0 18px 18px 0; }
|
||
.ms-side.mobile-open { transform: translateX(0); }
|
||
.ms-side .gs-sidebar-toggle { display: none; }
|
||
.ms-divider { display: none; }
|
||
.ms-main { padding: 12px 12px 60px; border-radius: 0; height: 100dvh; }
|
||
.gs-footer-compact { display: none !important; }
|
||
}
|
||
</style>
|