899 lines
20 KiB
Vue
899 lines
20 KiB
Vue
<template>
|
|
<q-layout view="lHh Lpr lFf" class="app-shell">
|
|
<q-header v-if="!isLoginPage" class="app-header">
|
|
<q-toolbar class="app-toolbar">
|
|
<div class="app-toolbar__page">
|
|
<q-btn
|
|
flat
|
|
dense
|
|
round
|
|
icon="sym_o_menu"
|
|
class="app-toolbar__menu"
|
|
aria-label="Abrir menu"
|
|
@click="toggleLeftDrawer"
|
|
/>
|
|
|
|
<div class="app-toolbar__breadcrumbs">
|
|
<span class="app-toolbar__eyebrow">Clipper · Painel</span>
|
|
<h1 class="app-toolbar__title">{{ currentRouteTitle }}</h1>
|
|
<p v-if="currentRouteDescription" class="app-toolbar__subtitle">
|
|
{{ currentRouteDescription }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="app-toolbar__actions">
|
|
<Button
|
|
v-if="quickAction"
|
|
:icon="quickAction.icon || 'sym_o_add'"
|
|
:label="quickAction.label"
|
|
@click="handleQuickAction"
|
|
/>
|
|
|
|
<q-btn
|
|
flat
|
|
round
|
|
dense
|
|
color="primary"
|
|
icon="sym_o_notifications"
|
|
class="app-toolbar__icon"
|
|
aria-label="Notificações"
|
|
/>
|
|
|
|
<Toggle v-model="darkMode" color="primary" @toggle="toggleDarkMode" />
|
|
|
|
<q-btn
|
|
v-if="!isLoginPage"
|
|
flat
|
|
dense
|
|
round
|
|
class="app-toolbar__avatar-btn"
|
|
>
|
|
<q-avatar size="36px" class="app-toolbar__avatar">
|
|
<span>{{ userInitials }}</span>
|
|
</q-avatar>
|
|
|
|
<q-menu
|
|
class="app-user-menu"
|
|
anchor="bottom right"
|
|
self="top right"
|
|
>
|
|
<div class="app-user-menu__header">
|
|
<q-avatar size="40px" color="primary" text-color="white">
|
|
{{ userInitials }}
|
|
</q-avatar>
|
|
|
|
<div class="app-user-menu__info">
|
|
<div class="app-user-menu__name">
|
|
{{ currentUserName || "Usuário" }}
|
|
</div>
|
|
<div
|
|
v-if="
|
|
currentUserEmail && currentUserEmail !== currentUserName
|
|
"
|
|
class="app-user-menu__email"
|
|
>
|
|
{{ currentUserEmail }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<q-separator spaced />
|
|
|
|
<q-list padding class="app-user-menu__list">
|
|
<q-item clickable disable>
|
|
<q-item-section avatar>
|
|
<q-icon name="sym_o_settings" />
|
|
</q-item-section>
|
|
<q-item-section>
|
|
<q-item-label>Configurações</q-item-label>
|
|
<q-item-label caption>Em breve</q-item-label>
|
|
</q-item-section>
|
|
</q-item>
|
|
|
|
<q-item
|
|
clickable
|
|
:disable="logoutLoading"
|
|
@click="handleLogout"
|
|
>
|
|
<q-item-section avatar>
|
|
<q-icon name="sym_o_logout" />
|
|
</q-item-section>
|
|
<q-item-section>
|
|
<q-item-label>Logout</q-item-label>
|
|
</q-item-section>
|
|
</q-item>
|
|
</q-list>
|
|
</q-menu>
|
|
</q-btn>
|
|
</div>
|
|
</q-toolbar>
|
|
</q-header>
|
|
|
|
<q-drawer
|
|
v-if="!isLoginPage"
|
|
v-model="leftDrawerOpen"
|
|
show-if-above
|
|
:width="260"
|
|
bordered
|
|
class="app-drawer"
|
|
>
|
|
<div class="app-drawer__header">
|
|
<q-avatar size="44px" color="primary" text-color="white">CI</q-avatar>
|
|
<div>
|
|
<div class="app-drawer__brand">Clipper IA</div>
|
|
<div class="app-drawer__tag">Assistente de cortes</div>
|
|
</div>
|
|
</div>
|
|
|
|
<q-scroll-area class="fit">
|
|
<template v-if="menuSections.length">
|
|
<q-list padding class="app-nav">
|
|
<template
|
|
v-for="(section, sectionIndex) in menuSections"
|
|
:key="section.key"
|
|
>
|
|
<q-item-label header class="app-nav__header">
|
|
<q-icon
|
|
v-if="section.icon"
|
|
:name="section.icon"
|
|
size="18px"
|
|
class="app-nav__header-icon"
|
|
/>
|
|
<span>{{ section.label }}</span>
|
|
</q-item-label>
|
|
|
|
<q-item
|
|
v-for="route in section.items"
|
|
:key="route.path"
|
|
clickable
|
|
v-ripple
|
|
:active="$route.path.startsWith(route.path)"
|
|
:to="route.path"
|
|
class="app-nav__item"
|
|
active-class="app-nav__item--active"
|
|
>
|
|
<q-item-section avatar>
|
|
<q-icon
|
|
:name="
|
|
route.meta?.icon || section.icon || 'sym_o_dashboard'
|
|
"
|
|
/>
|
|
</q-item-section>
|
|
<q-item-section>
|
|
<div class="app-nav__label">{{ route.meta?.title }}</div>
|
|
<div v-if="route.meta?.description" class="app-nav__caption">
|
|
{{ route.meta.description }}
|
|
</div>
|
|
</q-item-section>
|
|
<q-item-section side>
|
|
<q-icon
|
|
name="sym_o_chevron_right"
|
|
size="18px"
|
|
class="app-nav__chevron"
|
|
/>
|
|
</q-item-section>
|
|
</q-item>
|
|
|
|
<q-separator
|
|
v-if="sectionIndex !== menuSections.length - 1"
|
|
spaced
|
|
inset
|
|
/>
|
|
</template>
|
|
</q-list>
|
|
</template>
|
|
|
|
<div v-else class="app-nav__empty">
|
|
<q-icon name="sym_o_lock_person" size="36px" color="primary" />
|
|
<div class="app-nav__empty-title">Nenhum menu disponível</div>
|
|
<p class="app-nav__empty-text">
|
|
Entre em contato com o administrador para habilitar as permissões
|
|
necessárias.
|
|
</p>
|
|
</div>
|
|
</q-scroll-area>
|
|
|
|
<div class="app-drawer__footer">
|
|
<div class="app-drawer__cta">
|
|
<div class="app-drawer__cta-title">Precisa de ajuda?</div>
|
|
<div class="app-drawer__cta-text">
|
|
Nossa equipe está pronta para acelerar seus cortes.
|
|
</div>
|
|
<Button
|
|
color="secondary"
|
|
text-color="primary"
|
|
variant="ghost"
|
|
icon="sym_o_help"
|
|
label="Abrir suporte"
|
|
full-width
|
|
/>
|
|
</div>
|
|
</div>
|
|
</q-drawer>
|
|
|
|
<q-page-container>
|
|
<div v-if="isLoginPage">
|
|
<router-view />
|
|
</div>
|
|
<div v-else class="app-page">
|
|
<router-view />
|
|
</div>
|
|
</q-page-container>
|
|
</q-layout>
|
|
</template>
|
|
|
|
<script>
|
|
import { Dark } from "quasar";
|
|
import Cookies from "js-cookie";
|
|
|
|
import Button from "@components/Button";
|
|
import Toggle from "@components/Toggle";
|
|
|
|
import { API } from "@config/axios";
|
|
import { routes, MENUS } from "./auth/router";
|
|
import {
|
|
buildUserProfileFromToken,
|
|
extractUserInitials,
|
|
mapRolesToAppRoles,
|
|
} from "@/utils/keycloak";
|
|
|
|
const MENU_CONFIG = {
|
|
default: {
|
|
label: "Navegação",
|
|
icon: "sym_o_dashboard",
|
|
},
|
|
[MENUS.VIDEOS]: {
|
|
label: "Vídeos",
|
|
icon: "sym_o_video_library",
|
|
},
|
|
[MENUS.USUARIOS]: {
|
|
label: "Usuários",
|
|
icon: "sym_o_groups",
|
|
},
|
|
};
|
|
|
|
export default {
|
|
name: "App",
|
|
components: {
|
|
Button,
|
|
Toggle,
|
|
},
|
|
data() {
|
|
return {
|
|
leftDrawerOpen: true,
|
|
darkMode: Dark.isActive,
|
|
logoutLoading: false,
|
|
routes,
|
|
userProfile: this.getInitialUserProfile(),
|
|
};
|
|
},
|
|
computed: {
|
|
navigationRoutes() {
|
|
return this.routes.filter(
|
|
(route) => route.meta?.showinModal && this.hasPermission(route)
|
|
);
|
|
},
|
|
menuSections() {
|
|
const groups = this.navigationRoutes.reduce((acc, route) => {
|
|
const key = route.meta?.menu || "default";
|
|
|
|
if (!acc[key]) {
|
|
const config = MENU_CONFIG[key] || MENU_CONFIG.default || {};
|
|
|
|
acc[key] = {
|
|
key,
|
|
label:
|
|
config.label ||
|
|
route.meta?.menuLabel ||
|
|
route.meta?.title ||
|
|
"Navegação",
|
|
icon: config.icon,
|
|
items: [],
|
|
};
|
|
}
|
|
|
|
acc[key].items.push(route);
|
|
|
|
return acc;
|
|
}, {});
|
|
|
|
return Object.values(groups).map((section) => ({
|
|
...section,
|
|
items: section.items.sort((a, b) => {
|
|
const orderA = a.meta?.order ?? 0;
|
|
const orderB = b.meta?.order ?? 0;
|
|
return orderA - orderB;
|
|
}),
|
|
}));
|
|
},
|
|
currentRouteTitle() {
|
|
const route = this.$route;
|
|
return route.meta?.title || route.name || "Clipper IA";
|
|
},
|
|
currentRouteDescription() {
|
|
const current = this.$route.meta?.description;
|
|
if (current) return current;
|
|
|
|
const fallback = this.findParentRoute();
|
|
|
|
return (
|
|
fallback?.meta?.description || "Operacionalize cortes com inteligência."
|
|
);
|
|
},
|
|
quickAction() {
|
|
if (this.$route.meta?.quickAction === false) {
|
|
return null;
|
|
}
|
|
|
|
if (this.$route.meta?.quickAction) {
|
|
return this.$route.meta.quickAction;
|
|
}
|
|
|
|
const fallback = this.findParentRoute();
|
|
|
|
return fallback?.meta?.quickAction || null;
|
|
},
|
|
isLoginPage() {
|
|
return this.$route.path === "/login";
|
|
},
|
|
userRoles() {
|
|
const profileRoles = Array.isArray(this.userProfile?.roles)
|
|
? this.userProfile.roles
|
|
: [];
|
|
const rawRoles = Array.isArray(this.userProfile?.rawRoles)
|
|
? this.userProfile.rawRoles
|
|
: [];
|
|
|
|
const canonical = mapRolesToAppRoles([...profileRoles, ...rawRoles]);
|
|
|
|
return Array.from(new Set(canonical));
|
|
},
|
|
currentUserName() {
|
|
return this.userProfile?.name || this.userProfile?.username || "";
|
|
},
|
|
currentUserEmail() {
|
|
return this.userProfile?.email || this.userProfile?.username || "";
|
|
},
|
|
userInitials() {
|
|
return extractUserInitials(this.currentUserName) || "CI";
|
|
},
|
|
},
|
|
watch: {
|
|
"$route.path"() {
|
|
this.syncDrawerWithViewport();
|
|
this.refreshUserProfile();
|
|
},
|
|
},
|
|
mounted() {
|
|
this.syncDrawerWithViewport();
|
|
this.refreshUserProfile();
|
|
window.addEventListener("resize", this.syncDrawerWithViewport);
|
|
},
|
|
beforeUnmount() {
|
|
window.removeEventListener("resize", this.syncDrawerWithViewport);
|
|
},
|
|
methods: {
|
|
toggleLeftDrawer() {
|
|
this.leftDrawerOpen = !this.leftDrawerOpen;
|
|
},
|
|
toggleDarkMode() {
|
|
Dark.toggle();
|
|
this.darkMode = Dark.isActive;
|
|
},
|
|
handleQuickAction() {
|
|
if (this.quickAction?.handler) {
|
|
this.quickAction.handler();
|
|
return;
|
|
}
|
|
|
|
if (this.quickAction?.to) {
|
|
this.$router.push(this.quickAction.to);
|
|
}
|
|
},
|
|
async handleLogout() {
|
|
try {
|
|
this.logoutLoading = true;
|
|
|
|
await API.post("/auth/logout");
|
|
|
|
const cookieRemovalOptions = { path: "/" };
|
|
|
|
Cookies.remove("token", cookieRemovalOptions);
|
|
Cookies.remove("refresh_token", cookieRemovalOptions);
|
|
Cookies.remove("user_roles", cookieRemovalOptions);
|
|
Cookies.remove("user_profile", cookieRemovalOptions);
|
|
|
|
this.userProfile = { roles: [] };
|
|
this.leftDrawerOpen = false;
|
|
|
|
if (this.$route.path !== "/login") {
|
|
this.$router.push("/login");
|
|
}
|
|
} catch (error) {
|
|
} finally {
|
|
this.logoutLoading = false;
|
|
}
|
|
},
|
|
syncDrawerWithViewport() {
|
|
if (window.innerWidth < 1024) {
|
|
this.leftDrawerOpen = false;
|
|
} else {
|
|
this.leftDrawerOpen = true;
|
|
}
|
|
},
|
|
findParentRoute() {
|
|
const currentMenu = this.$route.meta?.menu;
|
|
|
|
if (!currentMenu) {
|
|
return this.navigationRoutes.find(
|
|
(route) => route.path === this.$route.path
|
|
);
|
|
}
|
|
|
|
return this.navigationRoutes.find(
|
|
(route) => route.meta?.menu && route.meta.menu === currentMenu
|
|
);
|
|
},
|
|
hasPermission(route) {
|
|
const required = route.meta?.permissions;
|
|
|
|
if (!Array.isArray(required) || required.length === 0) {
|
|
return true;
|
|
}
|
|
|
|
return required.some((role) => this.userRoles.includes(role));
|
|
},
|
|
getInitialUserProfile() {
|
|
const profileCookie = Cookies.get("user_profile");
|
|
const rolesCookie = Cookies.get("user_roles");
|
|
|
|
let profileFromCookie = null;
|
|
|
|
if (profileCookie) {
|
|
try {
|
|
profileFromCookie = JSON.parse(profileCookie);
|
|
} catch (error) {
|
|
console.warn("Invalid user profile cookie", error);
|
|
}
|
|
}
|
|
|
|
const collectedRawRoles = new Set();
|
|
|
|
if (Array.isArray(profileFromCookie?.roles)) {
|
|
profileFromCookie.roles.forEach((role) => collectedRawRoles.add(role));
|
|
}
|
|
|
|
if (Array.isArray(profileFromCookie?.rawRoles)) {
|
|
profileFromCookie.rawRoles.forEach((role) =>
|
|
collectedRawRoles.add(role)
|
|
);
|
|
}
|
|
|
|
if (rolesCookie) {
|
|
try {
|
|
const parsedRoles = JSON.parse(rolesCookie);
|
|
|
|
if (Array.isArray(parsedRoles)) {
|
|
parsedRoles.forEach((role) => collectedRawRoles.add(role));
|
|
}
|
|
} catch (error) {
|
|
console.warn("Invalid roles cookie", error);
|
|
}
|
|
}
|
|
|
|
const combinedRawRoles = Array.from(collectedRawRoles);
|
|
const mappedRoles = mapRolesToAppRoles(combinedRawRoles);
|
|
|
|
if (profileFromCookie) {
|
|
return {
|
|
...profileFromCookie,
|
|
rawRoles: combinedRawRoles,
|
|
roles: mappedRoles,
|
|
};
|
|
}
|
|
|
|
const token = Cookies.get("token");
|
|
|
|
if (!token) {
|
|
if (mappedRoles.length) {
|
|
return {
|
|
roles: mappedRoles,
|
|
rawRoles: combinedRawRoles,
|
|
};
|
|
}
|
|
|
|
return { roles: [] };
|
|
}
|
|
|
|
const profile = buildUserProfileFromToken(token);
|
|
|
|
if (!profile) {
|
|
return { roles: [] };
|
|
}
|
|
|
|
const combinedFromToken = new Set([
|
|
...(profile.rawRoles || []),
|
|
...combinedRawRoles,
|
|
...(profile.roles || []),
|
|
]);
|
|
|
|
const finalRawRoles = Array.from(combinedFromToken);
|
|
const finalRoles = mapRolesToAppRoles(finalRawRoles);
|
|
|
|
return {
|
|
...profile,
|
|
rawRoles: finalRawRoles,
|
|
roles: finalRoles,
|
|
};
|
|
},
|
|
refreshUserProfile() {
|
|
const profile = this.getInitialUserProfile();
|
|
this.userProfile = profile || { roles: [] };
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.app-shell {
|
|
background: transparent;
|
|
}
|
|
|
|
.app-header {
|
|
backdrop-filter: blur(18px);
|
|
background: rgba(255, 255, 255, 0.92);
|
|
border-bottom: 1px solid rgba(127, 86, 217, 0.12);
|
|
padding: 10px clamp(12px, 2vw, 24px);
|
|
}
|
|
|
|
body.body--dark .app-header {
|
|
background: rgba(16, 24, 40, 0.9);
|
|
border-bottom-color: rgba(244, 235, 255, 0.08);
|
|
}
|
|
|
|
.app-toolbar {
|
|
width: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: clamp(16px, 3vw, 40px);
|
|
}
|
|
|
|
.app-toolbar__page {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
}
|
|
|
|
.app-toolbar__menu {
|
|
display: none;
|
|
}
|
|
|
|
.app-toolbar__breadcrumbs {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
}
|
|
|
|
.app-toolbar__eyebrow {
|
|
font-size: 12px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.12em;
|
|
color: #7f56d9;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.app-toolbar__title {
|
|
font-size: clamp(24px, 3vw, 32px);
|
|
font-weight: 700;
|
|
color: #101828;
|
|
margin: 0;
|
|
}
|
|
|
|
.app-toolbar__subtitle {
|
|
font-size: 14px;
|
|
color: #475467;
|
|
margin: 0;
|
|
max-width: 420px;
|
|
}
|
|
|
|
body.body--dark .app-toolbar__eyebrow {
|
|
color: #f4ebff;
|
|
}
|
|
|
|
body.body--dark .app-toolbar__title {
|
|
color: rgba(255, 255, 255, 0.92);
|
|
}
|
|
|
|
body.body--dark .app-toolbar__subtitle {
|
|
color: rgba(255, 255, 255, 0.7);
|
|
}
|
|
|
|
.app-toolbar__actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
.app-toolbar__avatar-btn {
|
|
padding: 0;
|
|
min-width: 0;
|
|
}
|
|
|
|
.app-toolbar__avatar-btn .q-btn__content {
|
|
padding: 0;
|
|
}
|
|
|
|
.app-toolbar__icon {
|
|
background: rgba(127, 86, 217, 0.08);
|
|
color: #53389e;
|
|
}
|
|
|
|
body.body--dark .app-toolbar__icon {
|
|
background: rgba(244, 235, 255, 0.12);
|
|
color: #f4ebff;
|
|
}
|
|
|
|
.app-toolbar__avatar {
|
|
background: rgba(127, 86, 217, 0.16);
|
|
color: #53389e;
|
|
font-weight: 600;
|
|
}
|
|
|
|
body.body--dark .app-toolbar__avatar {
|
|
background: rgba(244, 235, 255, 0.2);
|
|
color: #0b1120;
|
|
}
|
|
|
|
.app-user-menu {
|
|
min-width: 240px;
|
|
padding: 12px 0;
|
|
}
|
|
|
|
.app-user-menu__header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
padding: 0 16px 8px;
|
|
}
|
|
|
|
.app-user-menu__info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
}
|
|
|
|
.app-user-menu__name {
|
|
font-weight: 600;
|
|
color: #101828;
|
|
}
|
|
|
|
.app-user-menu__email {
|
|
font-size: 13px;
|
|
color: #667085;
|
|
}
|
|
|
|
.app-user-menu__list .q-item {
|
|
border-radius: 12px;
|
|
}
|
|
|
|
.app-user-menu__list .q-item:not(.q-item--disabled):hover {
|
|
background: rgba(127, 86, 217, 0.08);
|
|
}
|
|
|
|
body.body--dark .app-user-menu__name {
|
|
color: rgba(255, 255, 255, 0.9);
|
|
}
|
|
|
|
body.body--dark .app-user-menu__email {
|
|
color: rgba(255, 255, 255, 0.65);
|
|
}
|
|
|
|
body.body--dark .app-user-menu__list .q-item:not(.q-item--disabled):hover {
|
|
background: rgba(244, 235, 255, 0.12);
|
|
}
|
|
|
|
.app-drawer {
|
|
padding: 24px 0 16px;
|
|
border-right: none;
|
|
background: #ffffff;
|
|
}
|
|
|
|
body.body--dark .app-drawer {
|
|
background: rgba(16, 24, 40, 0.96);
|
|
}
|
|
|
|
.app-drawer__header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
padding: 0 24px 24px;
|
|
}
|
|
|
|
.app-drawer__brand {
|
|
font-weight: 700;
|
|
font-size: 18px;
|
|
color: #101828;
|
|
}
|
|
|
|
.app-drawer__tag {
|
|
font-size: 13px;
|
|
color: #667085;
|
|
}
|
|
|
|
body.body--dark .app-drawer__brand {
|
|
color: rgba(255, 255, 255, 0.92);
|
|
}
|
|
|
|
body.body--dark .app-drawer__tag {
|
|
color: rgba(255, 255, 255, 0.55);
|
|
}
|
|
|
|
.app-nav {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
}
|
|
|
|
.app-nav__header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 12px;
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
color: #98a2b3;
|
|
}
|
|
|
|
.app-nav__header-icon {
|
|
color: #7f56d9;
|
|
}
|
|
|
|
.app-nav__item {
|
|
border-radius: 14px;
|
|
margin: 0 12px;
|
|
padding: 12px;
|
|
transition: background 0.2s ease, transform 0.2s ease;
|
|
}
|
|
|
|
.app-nav__item:hover {
|
|
background: rgba(127, 86, 217, 0.08);
|
|
transform: translateX(4px);
|
|
}
|
|
|
|
.app-nav__item--active {
|
|
background: rgba(127, 86, 217, 0.16);
|
|
color: #53389e;
|
|
}
|
|
|
|
.app-nav__label {
|
|
font-weight: 600;
|
|
color: #101828;
|
|
}
|
|
|
|
.app-nav__caption {
|
|
font-size: 12px;
|
|
color: #667085;
|
|
}
|
|
|
|
.app-nav__chevron {
|
|
color: #c7c9d9;
|
|
}
|
|
|
|
body.body--dark .app-nav__item:hover {
|
|
background: rgba(244, 235, 255, 0.1);
|
|
}
|
|
|
|
body.body--dark .app-nav__item--active {
|
|
background: rgba(244, 235, 255, 0.18);
|
|
color: rgba(255, 255, 255, 0.9);
|
|
}
|
|
|
|
body.body--dark .app-nav__label {
|
|
color: rgba(255, 255, 255, 0.9);
|
|
}
|
|
|
|
body.body--dark .app-nav__caption {
|
|
color: rgba(255, 255, 255, 0.6);
|
|
}
|
|
|
|
body.body--dark .app-nav__chevron {
|
|
color: rgba(244, 235, 255, 0.4);
|
|
}
|
|
|
|
.app-nav__empty {
|
|
padding: 48px 24px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
text-align: center;
|
|
gap: 12px;
|
|
color: #475467;
|
|
}
|
|
|
|
.app-nav__empty-title {
|
|
font-weight: 600;
|
|
color: #101828;
|
|
}
|
|
|
|
.app-nav__empty-text {
|
|
margin: 0;
|
|
font-size: 13px;
|
|
color: #667085;
|
|
}
|
|
|
|
body.body--dark .app-nav__header-icon {
|
|
color: #f4ebff;
|
|
}
|
|
|
|
body.body--dark .app-nav__empty-title {
|
|
color: rgba(255, 255, 255, 0.9);
|
|
}
|
|
|
|
body.body--dark .app-nav__empty-text {
|
|
color: rgba(255, 255, 255, 0.6);
|
|
}
|
|
|
|
.app-drawer__footer {
|
|
padding: 24px;
|
|
}
|
|
|
|
.app-drawer__cta {
|
|
background: rgba(127, 86, 217, 0.12);
|
|
border-radius: 16px;
|
|
padding: 20px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
.app-drawer__cta-title {
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
color: #53389e;
|
|
}
|
|
|
|
.app-drawer__cta-text {
|
|
font-size: 13px;
|
|
color: #475467;
|
|
}
|
|
|
|
body.body--dark .app-drawer__cta {
|
|
background: rgba(244, 235, 255, 0.12);
|
|
}
|
|
|
|
body.body--dark .app-drawer__cta-title {
|
|
color: rgba(255, 255, 255, 0.9);
|
|
}
|
|
|
|
body.body--dark .app-drawer__cta-text {
|
|
color: rgba(255, 255, 255, 0.7);
|
|
}
|
|
|
|
@media (max-width: 1024px) {
|
|
.app-toolbar__menu {
|
|
display: inline-flex;
|
|
}
|
|
|
|
.app-drawer {
|
|
background: #ffffff;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.app-toolbar__actions {
|
|
gap: 8px;
|
|
}
|
|
|
|
.app-toolbar__subtitle {
|
|
max-width: 280px;
|
|
}
|
|
|
|
.app-toolbar__icon,
|
|
.app-toolbar__avatar {
|
|
display: none;
|
|
}
|
|
}
|
|
</style>
|