2025-04-12 17:39:38 +08:00

254 lines
6.8 KiB
Vue

<template>
<div class="flex h-screen flex-col justify-between bg-gray-50 p-2">
<div>
<Dropdown :options="dropdownItems">
<template v-slot="{ open }">
<button
class="flex w-[15rem] items-center rounded-md px-2 py-2 text-left"
:class="open ? 'bg-white shadow-sm' : 'hover:bg-gray-200'"
>
<JLogo class="h-8 w-8 rounded" />
<div class="ml-2 flex flex-col">
<div class="text-base font-medium leading-none text-gray-900">
今果 Jingrow
</div>
<div
v-if="$account.user"
class="mt-1 hidden text-sm leading-none text-gray-700 sm:inline"
>
{{ $account.user.full_name }}
</div>
</div>
<FeatherIcon
name="chevron-down"
class="ml-auto h-5 w-5 text-gray-700"
/>
</button>
</template>
</Dropdown>
<div class="mt-2 flex flex-col space-y-0.5">
<div class="mb-2 flex flex-col space-y-0.5">
<button
v-if="$account.number_of_sites > 3"
class="rounded text-gray-900 hover:bg-gray-100"
@click="show = true"
>
<div class="flex w-full items-center px-2 py-1">
<span class="mr-1.5">
<FeatherIcon name="search" class="h-5 w-5 text-gray-700" />
</span>
<span class="text-sm">Search</span>
<span class="ml-auto text-sm text-gray-500">
<template v-if="$platform === 'mac'">K</template>
<template v-else>Ctrl+K</template>
</span>
</div>
</button>
<button
class="rounded text-gray-900 hover:bg-gray-100"
@click="this.$router.push({ name: 'Notifications' })"
>
<div
class="flex w-full items-center rounded-md px-2 py-1"
:class="{
'bg-white shadow-sm':
this.$route.fullPath.startsWith('/notifications')
}"
>
<span class="mr-1.5">
<FeatherIcon name="inbox" class="h-4.5 w-4.5 text-gray-700" />
</span>
<span class="text-sm">Notifications </span>
<span
v-if="unreadNotificationsCount > 0"
class="ml-auto rounded bg-gray-400 px-1.5 py-0.5 text-xs text-white"
>
{{
unreadNotificationsCount > 99
? '99+'
: unreadNotificationsCount
}}
</span>
</div>
</button>
</div>
<CommandPalette
:show="showCommandPalette"
@close="showCommandPalette = false"
/>
<router-link
v-for="item in items"
:key="item.label"
:to="item.route"
v-slot="{ href, route, navigate }"
>
<a
:class="[
(
Boolean(item.highlight)
? item.highlight(route)
: item.route == '/'
)
? 'bg-white shadow-sm'
: 'text-gray-900 hover:bg-gray-100'
]"
:href="href"
@click="navigate"
class="flex items-center rounded-md px-2 py-1 pr-10 text-start text-sm focus:outline-none"
>
<Component class="mr-1.5 text-gray-700" :is="item.icon" />
{{ item.label }}
</a>
</router-link>
</div>
</div>
<SwitchTeamDialog v-model="showTeamSwitcher" />
</div>
</template>
<script>
import { FCIcons } from '@/components/icons';
import SwitchTeamDialog from './SwitchTeamDialog.vue';
import JLogo from '@/components/icons/JLogo.vue';
import CommandPalette from '@/components/CommandPalette.vue';
import { unreadNotificationsCount } from '@/data/notifications';
export default {
name: 'Sidebar',
components: {
JLogo,
SwitchTeamDialog,
CommandPalette
},
data() {
return {
showCommandPalette: false,
showTeamSwitcher: false,
dropdownItems: [
{
label: 'Switch Team',
icon: 'command',
onClick: () => (this.showTeamSwitcher = true)
},
{
label: 'Support & Docs',
icon: 'help-circle',
onClick: () => (window.location.href = '/support')
},
{
label: 'Logout',
icon: 'log-out',
onClick: () => this.$auth.logout()
}
]
};
},
mounted() {
window.addEventListener('keydown', e => {
if (e.key === 'k' && (e.ctrlKey || e.metaKey)) {
this.showCommandPalette = !this.showCommandPalette;
e.preventDefault();
}
if (e.key === 'Escape') {
this.showCommandPalette = false;
}
});
this.$socket.emit('pagetype_subscribe', 'Jcloud Notification');
this.$socket.on('jcloud_notification', data => {
if (data.team === this.$account.team.name) {
unreadNotificationsCount.setData(data => data + 1);
}
});
unreadNotificationsCount.fetch();
},
beforeUnmount() {
this.$socket.emit('pagetype_unsubscribe', 'Jcloud Notification');
this.$socket.off('jcloud_notification');
},
computed: {
unreadNotificationsCount() {
return unreadNotificationsCount.data;
},
items() {
return [
{
label: 'Sites',
route: '/sites',
highlight: () => {
return this.$route.fullPath.startsWith('/sites');
},
icon: FCIcons.SiteIcon
},
{
label: 'Bench Groups',
route: '/groups',
highlight: () => {
return this.$route.fullPath.startsWith('/groups');
},
icon: FCIcons.BenchIcon
//condition: () => this.$account.team?.benches_enabled
},
{
label: 'Servers',
route: '/servers',
highlight: () => {
return this.$route.fullPath.startsWith('/servers');
},
icon: FCIcons.ServerIcon,
condition: () => this.$account.team?.servers_enabled
},
{
label: 'Spaces',
route: '/spaces',
highlight: () => {
return this.$route.fullPath.startsWith('/spaces');
},
icon: FCIcons.SpacesIcon,
condition: () => this.$account.team?.code_servers_enabled
},
{
label: 'Apps',
route: '/marketplace/apps',
highlight: () => {
return this.$route.fullPath.startsWith('/marketplace');
},
icon: FCIcons.AppsIcon,
condition: () => this.$account.team?.is_developer
},
{
label: 'Security',
route: '/security',
highlight: () => {
return this.$route.fullPath.startsWith('/security');
},
icon: FCIcons.SecurityIcon,
condition: () => this.$account.team?.security_portal_enabled
},
{
label: 'Billing',
route: '/billing',
highlight: () => {
return this.$route.fullPath.startsWith('/billing');
},
icon: FCIcons.BillingIcon,
condition: () =>
$account.user?.name === $account.team?.user ||
$account.user?.user_type === 'System User'
},
{
label: 'Settings',
route: '/settings',
highlight: () => {
return this.$route.fullPath.startsWith('/settings');
},
icon: FCIcons.SettingsIcon
}
].filter(d => (d.condition ? d.condition() : true));
}
}
};
</script>