Polish workspace organization selector
This commit is contained in:
@@ -165,7 +165,9 @@
|
||||
|
||||
.sidebar-workspace-menu {
|
||||
@apply absolute bottom-[calc(100%+0.5rem)] left-0 right-0 z-30 flex flex-col gap-1 rounded-[1.25rem] border p-2;
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
isolation: isolate;
|
||||
background: #fffdf8;
|
||||
background-clip: padding-box;
|
||||
border-color: rgba(23, 32, 51, 0.08);
|
||||
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.12);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
mdiChevronDown,
|
||||
mdiCogOutline,
|
||||
mdiPlus,
|
||||
mdiSwapHorizontal,
|
||||
} from '@mdi/js';
|
||||
|
||||
const router = useRouter();
|
||||
@@ -22,6 +23,7 @@
|
||||
const authStore = useAuthStore();
|
||||
|
||||
const isWorkspaceMenuOpen = ref(false);
|
||||
const isOrganizationListOpen = ref(false);
|
||||
const workspaceMenuRef = ref(null);
|
||||
|
||||
const activeOrganization = computed(() => organizationStore.activeOrganization);
|
||||
@@ -36,6 +38,11 @@
|
||||
});
|
||||
const canSwitchWorkspaces = computed(() => visibleWorkspaces.value.length > 1);
|
||||
const canSwitchOrganizations = computed(() => organizationStore.organizations.length > 1);
|
||||
const switchableOrganizations = computed(() =>
|
||||
organizationStore.organizations.filter(
|
||||
organization => organization.id !== organizationStore.selectedOrganizationId
|
||||
)
|
||||
);
|
||||
const canManageWorkspaces = computed(() =>
|
||||
activeOrganization.value?.currentUserPermissions?.includes(organizationPermissions.createWorkspaces) ||
|
||||
activeOrganization.value?.currentUserPermissions?.includes(organizationPermissions.manageWorkspaces) ||
|
||||
@@ -57,11 +64,13 @@
|
||||
}
|
||||
|
||||
isWorkspaceMenuOpen.value = !isWorkspaceMenuOpen.value;
|
||||
isOrganizationListOpen.value = false;
|
||||
}
|
||||
|
||||
function chooseWorkspace(workspaceId) {
|
||||
workspaceStore.setActiveWorkspace(workspaceId);
|
||||
isWorkspaceMenuOpen.value = false;
|
||||
isOrganizationListOpen.value = false;
|
||||
}
|
||||
|
||||
function chooseOrganization(organizationId) {
|
||||
@@ -71,21 +80,29 @@
|
||||
workspace => workspace.organizationId === organizationId
|
||||
);
|
||||
workspaceStore.setActiveWorkspace(nextWorkspace?.id ?? null);
|
||||
isOrganizationListOpen.value = false;
|
||||
}
|
||||
|
||||
function toggleOrganizationList() {
|
||||
isOrganizationListOpen.value = !isOrganizationListOpen.value;
|
||||
}
|
||||
|
||||
async function openCreateWorkspace() {
|
||||
isWorkspaceMenuOpen.value = false;
|
||||
isOrganizationListOpen.value = false;
|
||||
await router.push({ name: 'workspace-create' });
|
||||
}
|
||||
|
||||
async function openOrganizationSettings(organizationId) {
|
||||
isWorkspaceMenuOpen.value = false;
|
||||
isOrganizationListOpen.value = false;
|
||||
await router.push({ name: 'organization-settings', params: { organizationId } });
|
||||
}
|
||||
|
||||
function handleDocumentClick(event) {
|
||||
if (workspaceMenuRef.value && !workspaceMenuRef.value.contains(event.target)) {
|
||||
isWorkspaceMenuOpen.value = false;
|
||||
isOrganizationListOpen.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,17 +171,47 @@
|
||||
<v-icon :icon="mdiPlus" />
|
||||
</button>
|
||||
|
||||
<div class="organization-switcher">
|
||||
<div class="organization-switcher-label">
|
||||
<span>{{ t('workspaceSelector.organizationLabel') }}</span>
|
||||
<strong>{{ activeOrganizationName }}</strong>
|
||||
<div
|
||||
v-if="activeOrganization"
|
||||
class="organization-switcher"
|
||||
>
|
||||
<div class="organization-current-row">
|
||||
<button
|
||||
class="user-menu-item organization-current"
|
||||
type="button"
|
||||
@click="openOrganizationSettings(activeOrganization.id)"
|
||||
>
|
||||
<span class="organization-mark">{{ activeOrganization.name.slice(0, 1).toUpperCase() }}</span>
|
||||
<span class="user-menu-item-copy">
|
||||
<span>{{ activeOrganizationName }}</span>
|
||||
<small>{{ t('workspaceSelector.organizationLabel') }}</small>
|
||||
</span>
|
||||
<v-icon
|
||||
:icon="mdiCogOutline"
|
||||
class="organization-action-icon"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
v-for="organization in organizationStore.organizations"
|
||||
v-if="canSwitchOrganizations"
|
||||
class="organization-swap-button"
|
||||
type="button"
|
||||
:aria-expanded="isOrganizationListOpen"
|
||||
@click="toggleOrganizationList"
|
||||
>
|
||||
<span>Change organization</span>
|
||||
<v-icon :icon="mdiSwapHorizontal" />
|
||||
</button>
|
||||
|
||||
<div
|
||||
v-if="isOrganizationListOpen"
|
||||
class="organization-options"
|
||||
>
|
||||
<button
|
||||
v-for="organization in switchableOrganizations"
|
||||
:key="organization.id"
|
||||
class="user-menu-item organization-option"
|
||||
:class="{ 'user-menu-item-active': organization.id === organizationStore.selectedOrganizationId }"
|
||||
type="button"
|
||||
@click="chooseOrganization(organization.id)"
|
||||
>
|
||||
@@ -174,16 +221,7 @@
|
||||
<small>{{ t('workspaceSelector.organizationLabel') }}</small>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
v-if="activeOrganization"
|
||||
class="user-menu-item organization-settings-link"
|
||||
type="button"
|
||||
@click="openOrganizationSettings(activeOrganization.id)"
|
||||
>
|
||||
<span>{{ t('workspaceSelector.organizationSettings') }}</span>
|
||||
<v-icon :icon="mdiCogOutline" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -279,18 +317,18 @@
|
||||
border-color: rgba(23, 32, 51, 0.08);
|
||||
}
|
||||
|
||||
.organization-switcher-label {
|
||||
@apply flex flex-col gap-0.5 px-3 py-2;
|
||||
.organization-current-row {
|
||||
@apply flex w-full min-w-0 flex-col gap-1;
|
||||
}
|
||||
|
||||
.organization-switcher-label span {
|
||||
@apply text-xs font-bold uppercase tracking-[0.18em];
|
||||
color: #7a8799;
|
||||
.organization-current {
|
||||
@apply w-full min-w-0 border;
|
||||
background: rgba(23, 32, 51, 0.04);
|
||||
border-color: rgba(23, 32, 51, 0.08);
|
||||
}
|
||||
|
||||
.organization-switcher-label strong {
|
||||
@apply truncate text-sm;
|
||||
color: #172033;
|
||||
.organization-current:hover {
|
||||
background: rgba(23, 32, 51, 0.07);
|
||||
}
|
||||
|
||||
.organization-mark {
|
||||
@@ -299,7 +337,23 @@
|
||||
color: #172033;
|
||||
}
|
||||
|
||||
.organization-settings-link {
|
||||
@apply justify-between;
|
||||
.organization-action-icon {
|
||||
@apply flex-shrink-0 text-base;
|
||||
color: #526178;
|
||||
}
|
||||
|
||||
.organization-swap-button {
|
||||
@apply flex w-full items-center justify-between gap-3 rounded-[0.9rem] border px-3 py-2.5 text-sm font-semibold transition-colors;
|
||||
background: rgba(23, 32, 51, 0.04);
|
||||
border-color: rgba(23, 32, 51, 0.08);
|
||||
color: #172033;
|
||||
}
|
||||
|
||||
.organization-swap-button:hover {
|
||||
background: rgba(23, 32, 51, 0.08);
|
||||
}
|
||||
|
||||
.organization-options {
|
||||
@apply flex flex-col gap-1;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user