mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-18 05:02:14 +01:00
add animation to the mobile sidebar
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ChartBarIcon, ArrowDownTrayIcon, EllipsisVerticalIcon, LockClosedIcon } from '@heroicons/vue/20/solid';
|
import {
|
||||||
|
ChartBarIcon,
|
||||||
|
ArrowDownTrayIcon,
|
||||||
|
EllipsisVerticalIcon,
|
||||||
|
LockClosedIcon,
|
||||||
|
} from '@heroicons/vue/20/solid';
|
||||||
import { SaveIcon } from 'lucide-vue-next';
|
import { SaveIcon } from 'lucide-vue-next';
|
||||||
import { getOrganizationCurrencyString } from '@/utils/money';
|
import { getOrganizationCurrencyString } from '@/utils/money';
|
||||||
import {
|
import {
|
||||||
@@ -281,9 +286,7 @@ const tableData = computed(() => {
|
|||||||
class="h-14 sm:h-16 border-b border-default-background-separator flex flex-wrap gap-y-3 justify-between items-center">
|
class="h-14 sm:h-16 border-b border-default-background-separator flex flex-wrap gap-y-3 justify-between items-center">
|
||||||
<div class="flex items-center space-x-3 sm:space-x-6">
|
<div class="flex items-center space-x-3 sm:space-x-6">
|
||||||
<PageTitle :icon="ChartBarIcon" title="Reporting"></PageTitle>
|
<PageTitle :icon="ChartBarIcon" title="Reporting"></PageTitle>
|
||||||
<ReportingTabNavbar
|
<ReportingTabNavbar active="reporting" class="hidden sm:flex"></ReportingTabNavbar>
|
||||||
active="reporting"
|
|
||||||
class="hidden sm:flex"></ReportingTabNavbar>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="hidden sm:flex space-x-2">
|
<div class="hidden sm:flex space-x-2">
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
@@ -312,10 +315,7 @@ const tableData = computed(() => {
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
<SecondaryButton
|
<SecondaryButton v-if="canCreateReports()" :icon="SaveIcon" @click="onSaveReportClick">
|
||||||
v-if="canCreateReports()"
|
|
||||||
:icon="SaveIcon"
|
|
||||||
@click="onSaveReportClick">
|
|
||||||
Save Report
|
Save Report
|
||||||
</SecondaryButton>
|
</SecondaryButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -339,15 +339,9 @@ const tableData = computed(() => {
|
|||||||
<DropdownMenuItem @click="triggerExport('xlsx')">
|
<DropdownMenuItem @click="triggerExport('xlsx')">
|
||||||
Export as Excel
|
Export as Excel
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem @click="triggerExport('csv')">
|
<DropdownMenuItem @click="triggerExport('csv')"> Export as CSV </DropdownMenuItem>
|
||||||
Export as CSV
|
<DropdownMenuItem @click="triggerExport('ods')"> Export as ODS </DropdownMenuItem>
|
||||||
</DropdownMenuItem>
|
<DropdownMenuItem v-if="canCreateReports()" @click="onSaveReportClick">
|
||||||
<DropdownMenuItem @click="triggerExport('ods')">
|
|
||||||
Export as ODS
|
|
||||||
</DropdownMenuItem>
|
|
||||||
<DropdownMenuItem
|
|
||||||
v-if="canCreateReports()"
|
|
||||||
@click="onSaveReportClick">
|
|
||||||
Save Report
|
Save Report
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import Banner from '@/Components/Banner.vue';
|
|||||||
import OrganizationSwitcher from '@/Components/OrganizationSwitcher.vue';
|
import OrganizationSwitcher from '@/Components/OrganizationSwitcher.vue';
|
||||||
import CurrentSidebarTimer from '@/Components/CurrentSidebarTimer.vue';
|
import CurrentSidebarTimer from '@/Components/CurrentSidebarTimer.vue';
|
||||||
import {
|
import {
|
||||||
Bars3Icon,
|
|
||||||
CalendarIcon,
|
CalendarIcon,
|
||||||
ChartBarIcon,
|
ChartBarIcon,
|
||||||
ClockIcon,
|
ClockIcon,
|
||||||
@@ -18,11 +17,13 @@ import {
|
|||||||
UserGroupIcon,
|
UserGroupIcon,
|
||||||
XMarkIcon,
|
XMarkIcon,
|
||||||
DocumentTextIcon,
|
DocumentTextIcon,
|
||||||
|
ViewColumnsIcon,
|
||||||
} from '@heroicons/vue/20/solid';
|
} from '@heroicons/vue/20/solid';
|
||||||
|
import { PanelLeft } from 'lucide-vue-next';
|
||||||
import NavigationSidebarItem from '@/Components/NavigationSidebarItem.vue';
|
import NavigationSidebarItem from '@/Components/NavigationSidebarItem.vue';
|
||||||
import UserSettingsIcon from '@/Components/UserSettingsIcon.vue';
|
import UserSettingsIcon from '@/Components/UserSettingsIcon.vue';
|
||||||
import MainContainer from '@/packages/ui/src/MainContainer.vue';
|
import MainContainer from '@/packages/ui/src/MainContainer.vue';
|
||||||
import { onMounted, provide, ref } from 'vue';
|
import { nextTick, onMounted, provide, ref } from 'vue';
|
||||||
import NotificationContainer from '@/Components/NotificationContainer.vue';
|
import NotificationContainer from '@/Components/NotificationContainer.vue';
|
||||||
import { initializeStores } from '@/utils/init';
|
import { initializeStores } from '@/utils/init';
|
||||||
import { useCurrentTimeEntryStore } from '@/utils/useCurrentTimeEntry';
|
import { useCurrentTimeEntryStore } from '@/utils/useCurrentTimeEntry';
|
||||||
@@ -35,6 +36,7 @@ import {
|
|||||||
canViewProjects,
|
canViewProjects,
|
||||||
canViewReport,
|
canViewReport,
|
||||||
canViewTags,
|
canViewTags,
|
||||||
|
canViewTasks,
|
||||||
} from '@/utils/permissions';
|
} from '@/utils/permissions';
|
||||||
import { isBillingActivated, isInvoicingActivated } from '@/utils/billing';
|
import { isBillingActivated, isInvoicingActivated } from '@/utils/billing';
|
||||||
import type { User } from '@/types/models';
|
import type { User } from '@/types/models';
|
||||||
@@ -61,6 +63,24 @@ defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const showSidebarMenu = ref(false);
|
const showSidebarMenu = ref(false);
|
||||||
|
const sidebarVisible = ref(false);
|
||||||
|
|
||||||
|
function openSidebar() {
|
||||||
|
showSidebarMenu.value = true;
|
||||||
|
nextTick(() => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
sidebarVisible.value = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeSidebar() {
|
||||||
|
sidebarVisible.value = false;
|
||||||
|
setTimeout(() => {
|
||||||
|
showSidebarMenu.value = false;
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
const isUnloading = ref(false);
|
const isUnloading = ref(false);
|
||||||
|
|
||||||
const { organization, isLoading: isOrganizationLoading } = useOrganizationQuery(
|
const { organization, isLoading: isOrganizationLoading } = useOrganizationQuery(
|
||||||
@@ -102,11 +122,26 @@ const page = usePage<{
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-bind="$attrs" class="flex flex-wrap bg-background text-text-secondary">
|
<div v-bind="$attrs" class="flex flex-wrap bg-background text-text-secondary">
|
||||||
|
<!-- Mobile sidebar overlay -->
|
||||||
|
<Teleport to="body">
|
||||||
|
<div
|
||||||
|
v-if="showSidebarMenu"
|
||||||
|
class="fixed inset-0 z-40 lg:hidden"
|
||||||
|
@click="closeSidebar">
|
||||||
|
<div
|
||||||
|
class="absolute inset-0 bg-default-background transition-opacity duration-200"
|
||||||
|
:class="sidebarVisible ? 'opacity-50' : 'opacity-0'" />
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
:class="{
|
:class="[
|
||||||
'!flex bg-default-background w-full z-30': showSidebarMenu,
|
sidebarVisible
|
||||||
}"
|
? 'max-lg:translate-x-0 max-lg:shadow-xl'
|
||||||
class="flex-shrink-0 h-screen hidden fixed w-[230px] 2xl:w-[250px] px-2.5 2xl:px-3 py-4 lg:flex flex-col justify-between">
|
: 'max-lg:-translate-x-full',
|
||||||
|
]"
|
||||||
|
class="flex-shrink-0 h-screen fixed w-[280px] px-2.5 py-4 hidden lg:flex flex-col justify-between bg-background border-r border-default-background-separator max-lg:z-50 max-lg:transition-transform max-lg:duration-200 max-lg:ease-in-out lg:w-[230px] 2xl:w-[250px] 2xl:px-3 lg:border-r-0"
|
||||||
|
:style="showSidebarMenu ? { display: 'flex' } : undefined">
|
||||||
<div class="flex flex-col h-full">
|
<div class="flex flex-col h-full">
|
||||||
<div
|
<div
|
||||||
class="border-b border-default-background-separator pb-2 flex items-center gap-1">
|
class="border-b border-default-background-separator pb-2 flex items-center gap-1">
|
||||||
@@ -121,9 +156,13 @@ const page = usePage<{
|
|||||||
@click="openPalette">
|
@click="openPalette">
|
||||||
<MagnifyingGlassIcon class="h-4 w-4 text-icon-default" />
|
<MagnifyingGlassIcon class="h-4 w-4 text-icon-default" />
|
||||||
</Button>
|
</Button>
|
||||||
<XMarkIcon
|
<Button
|
||||||
class="w-8 lg:hidden flex-shrink-0"
|
variant="ghost"
|
||||||
@click="showSidebarMenu = false"></XMarkIcon>
|
size="icon"
|
||||||
|
class="h-7 w-7 flex-shrink-0 lg:hidden"
|
||||||
|
@click="closeSidebar">
|
||||||
|
<XMarkIcon class="h-4 w-4 text-icon-default" />
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div class="border-b border-default-background-separator">
|
<div class="border-b border-default-background-separator">
|
||||||
<CurrentSidebarTimer></CurrentSidebarTimer>
|
<CurrentSidebarTimer></CurrentSidebarTimer>
|
||||||
@@ -151,6 +190,12 @@ const page = usePage<{
|
|||||||
:icon="CalendarIcon"
|
:icon="CalendarIcon"
|
||||||
:current="route().current('calendar')"
|
:current="route().current('calendar')"
|
||||||
:href="route('calendar')"></NavigationSidebarItem>
|
:href="route('calendar')"></NavigationSidebarItem>
|
||||||
|
<NavigationSidebarItem
|
||||||
|
v-if="canViewTasks()"
|
||||||
|
title="Board"
|
||||||
|
:icon="ViewColumnsIcon"
|
||||||
|
:href="route('kanban')"
|
||||||
|
:current="route().current('kanban')"></NavigationSidebarItem>
|
||||||
<NavigationSidebarItem
|
<NavigationSidebarItem
|
||||||
title="Reporting"
|
title="Reporting"
|
||||||
:icon="ChartBarIcon"
|
:icon="ChartBarIcon"
|
||||||
@@ -279,9 +324,13 @@ const page = usePage<{
|
|||||||
class="h-screen overflow-y-auto flex flex-col bg-default-background border-l border-default-background-separator">
|
class="h-screen overflow-y-auto flex flex-col bg-default-background border-l border-default-background-separator">
|
||||||
<div
|
<div
|
||||||
class="lg:hidden w-full px-3 py-1 border-b border-b-default-background-separator text-text-secondary flex justify-between items-center">
|
class="lg:hidden w-full px-3 py-1 border-b border-b-default-background-separator text-text-secondary flex justify-between items-center">
|
||||||
<Bars3Icon
|
<Button
|
||||||
class="w-7 text-text-secondary"
|
variant="ghost"
|
||||||
@click="showSidebarMenu = !showSidebarMenu"></Bars3Icon>
|
size="icon"
|
||||||
|
class="h-7 w-7 shrink-0"
|
||||||
|
@click="openSidebar">
|
||||||
|
<PanelLeft class="h-4 w-4 text-icon-default" />
|
||||||
|
</Button>
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<OrganizationSwitcher></OrganizationSwitcher>
|
<OrganizationSwitcher></OrganizationSwitcher>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -266,9 +266,7 @@ async function downloadExport(format: ExportFormat) {
|
|||||||
class="h-14 sm:h-16 border-b border-default-background-separator flex flex-wrap gap-y-3 justify-between items-center">
|
class="h-14 sm:h-16 border-b border-default-background-separator flex flex-wrap gap-y-3 justify-between items-center">
|
||||||
<div class="flex items-center space-x-3 sm:space-x-6">
|
<div class="flex items-center space-x-3 sm:space-x-6">
|
||||||
<PageTitle :icon="ChartBarIcon" title="Reporting"></PageTitle>
|
<PageTitle :icon="ChartBarIcon" title="Reporting"></PageTitle>
|
||||||
<ReportingTabNavbar
|
<ReportingTabNavbar active="detailed" class="hidden sm:flex"></ReportingTabNavbar>
|
||||||
active="detailed"
|
|
||||||
class="hidden sm:flex"></ReportingTabNavbar>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="hidden sm:block">
|
<div class="hidden sm:block">
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
|
|||||||
@@ -72,9 +72,7 @@ watch(currentPage, () => {
|
|||||||
class="h-14 sm:h-16 border-b border-default-background-separator flex flex-wrap gap-y-3 justify-between items-center">
|
class="h-14 sm:h-16 border-b border-default-background-separator flex flex-wrap gap-y-3 justify-between items-center">
|
||||||
<div class="flex items-center space-x-3 sm:space-x-6">
|
<div class="flex items-center space-x-3 sm:space-x-6">
|
||||||
<PageTitle :icon="ChartBarIcon" title="Reporting"></PageTitle>
|
<PageTitle :icon="ChartBarIcon" title="Reporting"></PageTitle>
|
||||||
<ReportingTabNavbar
|
<ReportingTabNavbar active="shared" class="hidden sm:flex"></ReportingTabNavbar>
|
||||||
active="shared"
|
|
||||||
class="hidden sm:flex"></ReportingTabNavbar>
|
|
||||||
</div>
|
</div>
|
||||||
</MainContainer>
|
</MainContainer>
|
||||||
<MainContainer class="sm:hidden py-2 border-b border-default-background-separator">
|
<MainContainer class="sm:hidden py-2 border-b border-default-background-separator">
|
||||||
|
|||||||
Reference in New Issue
Block a user