277 lines
8.5 KiB
Vue
277 lines
8.5 KiB
Vue
<script setup>
|
|
import { computed, ref } from 'vue';
|
|
import { useRoute } from 'vue-router';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useAuthStore } from '@/features/auth/stores/authStore.js';
|
|
import WorkspaceSelector from './WorkspaceSelector.vue';
|
|
import {
|
|
mdiCalendar,
|
|
mdiChevronDown,
|
|
mdiCogOutline,
|
|
mdiFormatListBulleted,
|
|
mdiLogin,
|
|
mdiPlus,
|
|
mdiTable,
|
|
} from '@mdi/js';
|
|
|
|
const route = useRoute();
|
|
const { t } = useI18n();
|
|
const authStore = useAuthStore();
|
|
const isContentViewMenuOpen = ref(false);
|
|
|
|
const contentViewActions = computed(() => {
|
|
if (route.name !== 'content-items') {
|
|
return [];
|
|
}
|
|
|
|
const query = route.query;
|
|
const activeView = ['upcoming', 'table'].includes(query.view) ? query.view : 'calendar';
|
|
|
|
return [
|
|
{
|
|
key: 'calendar',
|
|
label: t('contentItems.views.calendar'),
|
|
icon: mdiCalendar,
|
|
active: activeView === 'calendar',
|
|
route: {
|
|
name: 'content-items',
|
|
query: {
|
|
...query,
|
|
view: query.view === 'week' ? 'week' : 'month',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
key: 'upcoming',
|
|
label: t('contentItems.upcoming'),
|
|
icon: mdiFormatListBulleted,
|
|
active: activeView === 'upcoming',
|
|
route: {
|
|
name: 'content-items',
|
|
query: {
|
|
...query,
|
|
view: 'upcoming',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
key: 'table',
|
|
label: t('contentItems.views.table'),
|
|
icon: mdiTable,
|
|
active: activeView === 'table',
|
|
route: {
|
|
name: 'content-items',
|
|
query: {
|
|
...query,
|
|
view: 'table',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
});
|
|
|
|
const activeContentViewAction = computed(() =>
|
|
contentViewActions.value.find(action => action.active) ?? contentViewActions.value[0]
|
|
);
|
|
|
|
const appBarActions = computed(() => {
|
|
if (!authStore.isAuthenticated) {
|
|
return [];
|
|
}
|
|
|
|
switch (route.name) {
|
|
case 'workspace-dashboard':
|
|
case 'content-items':
|
|
return authStore.isManager || authStore.isProvider
|
|
? [{
|
|
key: 'create-content',
|
|
label: t('contentItems.newItem'),
|
|
icon: mdiPlus,
|
|
route: { name: 'content-item-create' },
|
|
}]
|
|
: [];
|
|
case 'campaigns':
|
|
return [{
|
|
key: 'create-campaign',
|
|
label: t('campaigns.newCampaign'),
|
|
icon: mdiPlus,
|
|
route: { name: 'campaigns', query: { create: 'true' } },
|
|
}];
|
|
case 'channels':
|
|
return [{
|
|
key: 'create-channel',
|
|
label: t('channels.createTitle'),
|
|
icon: mdiPlus,
|
|
route: { name: 'channels', query: { create: 'true' } },
|
|
}];
|
|
case 'workspace-settings':
|
|
case 'settings-user-information':
|
|
case 'settings-workspaces':
|
|
case 'settings-integrations':
|
|
return [{
|
|
key: 'settings',
|
|
label: t('nav.settings'),
|
|
icon: mdiCogOutline,
|
|
route: { name: 'settings-user-information' },
|
|
}];
|
|
default:
|
|
return [];
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<nav class="side-container">
|
|
<div class="side-menu">
|
|
<div class="side-menu-items side-menu-left">
|
|
<WorkspaceSelector
|
|
v-if="authStore.isAuthenticated"
|
|
/>
|
|
</div>
|
|
|
|
<div class="side-menu-items side-menu-right">
|
|
<template v-if="!authStore.isAuthenticated">
|
|
<router-link to="/login">
|
|
<button class="menu-item-action">
|
|
<v-icon :icon="mdiLogin" />
|
|
<span class="label">{{ t('nav.signIn') }}</span>
|
|
</button>
|
|
</router-link>
|
|
</template>
|
|
|
|
<div
|
|
v-if="contentViewActions.length"
|
|
class="view-selector"
|
|
>
|
|
<button
|
|
class="menu-item-action view-selector-button"
|
|
type="button"
|
|
@click="isContentViewMenuOpen = !isContentViewMenuOpen"
|
|
>
|
|
<v-icon :icon="activeContentViewAction.icon" />
|
|
<span class="label">{{ activeContentViewAction.label }}</span>
|
|
<v-icon
|
|
class="selector-chevron"
|
|
:icon="mdiChevronDown"
|
|
/>
|
|
</button>
|
|
|
|
<div
|
|
v-if="isContentViewMenuOpen"
|
|
class="view-selector-menu"
|
|
>
|
|
<router-link
|
|
v-for="action in contentViewActions"
|
|
:key="action.key"
|
|
:to="action.route"
|
|
class="menu-action-link"
|
|
@click="isContentViewMenuOpen = false"
|
|
>
|
|
<button
|
|
class="view-selector-option"
|
|
:class="{ 'view-selector-option-active': action.active }"
|
|
type="button"
|
|
>
|
|
<v-icon :icon="action.icon" />
|
|
<span>{{ action.label }}</span>
|
|
</button>
|
|
</router-link>
|
|
</div>
|
|
</div>
|
|
|
|
<router-link
|
|
v-for="action in appBarActions"
|
|
:key="action.key"
|
|
:to="action.route"
|
|
class="menu-action-link"
|
|
>
|
|
<button class="menu-item-action">
|
|
<v-icon :icon="action.icon" />
|
|
<span class="label">{{ action.label }}</span>
|
|
</button>
|
|
</router-link>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.side-container {
|
|
@apply sticky top-0 z-20 flex flex-col gap-4 px-5 py-4 md:flex-row md:items-center md:justify-between;
|
|
background: rgba(255, 250, 242, 0.82);
|
|
backdrop-filter: blur(18px);
|
|
border-bottom: 1px solid rgba(23, 32, 51, 0.08);
|
|
isolation: isolate;
|
|
}
|
|
|
|
.side-menu {
|
|
@apply flex w-full flex-1 items-center justify-between gap-3;
|
|
}
|
|
|
|
.side-menu-items {
|
|
@apply flex flex-wrap items-center justify-end gap-2;
|
|
overflow: visible;
|
|
}
|
|
|
|
.side-menu-left {
|
|
@apply justify-start pl-3;
|
|
}
|
|
|
|
.side-menu-right {
|
|
@apply justify-end;
|
|
}
|
|
|
|
.view-selector {
|
|
@apply relative;
|
|
}
|
|
|
|
.view-selector-button {
|
|
@apply min-w-11 justify-between;
|
|
}
|
|
|
|
.selector-chevron {
|
|
@apply text-base;
|
|
}
|
|
|
|
.view-selector-menu {
|
|
@apply absolute right-0 top-[calc(100%+0.5rem)] z-30 flex min-w-52 flex-col gap-1 rounded-[1rem] border p-2 shadow-xl;
|
|
background: #ffffff;
|
|
border-color: rgba(23, 32, 51, 0.1);
|
|
}
|
|
|
|
.label {
|
|
@apply hidden text-nowrap md:inline;
|
|
}
|
|
|
|
.menu-item-action {
|
|
@apply flex h-11 items-center gap-3 rounded-full px-4 transition-colors;
|
|
background: rgba(255, 255, 255, 0.8);
|
|
color: #172033;
|
|
border: 1px solid rgba(23, 32, 51, 0.06);
|
|
}
|
|
|
|
.menu-item-action:hover {
|
|
background: #172033;
|
|
color: #fffaf2;
|
|
}
|
|
|
|
.view-selector-option {
|
|
@apply flex min-h-11 w-full items-center gap-3 rounded-[0.75rem] px-3 text-left text-sm font-semibold transition;
|
|
color: #172033;
|
|
}
|
|
|
|
.view-selector-option:hover,
|
|
.view-selector-option-active {
|
|
background: #172033;
|
|
color: #fffaf2;
|
|
}
|
|
|
|
.menu-item-action i {
|
|
@apply text-xl;
|
|
}
|
|
|
|
.menu-action-link {
|
|
@apply no-underline;
|
|
}
|
|
</style>
|