Merge branch 'main' into andrew/web-4174-resetting-section-box-shouldnt-disable-tool
This commit is contained in:
@@ -2,10 +2,13 @@
|
||||
<div
|
||||
class="bg-foundation border border-outline-3 rounded-xl shadow-md h-10 flex items-center"
|
||||
>
|
||||
<div class="flex items-center justify-between md:space-x-1 p-1">
|
||||
<FormButton class="hidden md:flex">Share</FormButton>
|
||||
<div class="flex items-center justify-between space-x-1 p-1">
|
||||
<FormButton>Share</FormButton>
|
||||
|
||||
<PresentationFloatingPanelButton class="hidden md:flex" @click="toggleFullscreen">
|
||||
<PresentationFloatingPanelButton
|
||||
class="hidden md:flex touch:hidden"
|
||||
@click="toggleFullscreen"
|
||||
>
|
||||
<LucideFullscreen class="size-4" />
|
||||
</PresentationFloatingPanelButton>
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<aside
|
||||
class="bg-foundation h-48 md:h-dvh w-full md:w-64 xl:w-80 border-t md:border-t-0 md:border-l border-outline-3 py-5 px-4"
|
||||
class="bg-foundation h-48 lg:h-dvh w-full lg:w-64 xl:w-80 border-t lg:border-t-0 lg:border-l border-outline-3 py-5 px-4"
|
||||
>
|
||||
<div class="hidden md:flex items-center justify-end space-x-0.5">
|
||||
<div class="hidden lg:flex items-center justify-end space-x-0.5">
|
||||
<div
|
||||
v-tippy="
|
||||
canUpdateSlide ? undefined : 'You do not have permission to edit this slide'
|
||||
@@ -29,14 +29,21 @@
|
||||
<h1 v-if="currentSlide?.name" class="text-xl font-medium text-foreground px-2">
|
||||
{{ currentSlide?.name }}
|
||||
</h1>
|
||||
<FormButton
|
||||
v-if="canUpdate"
|
||||
:icon-left="LucidePencilLine"
|
||||
color="subtle"
|
||||
hide-text
|
||||
class="md:hidden"
|
||||
@click="isSlideEditDialogOpen = true"
|
||||
/>
|
||||
<div class="lg:hidden flex items-center gap-x-1">
|
||||
<FormButton
|
||||
v-if="canUpdate"
|
||||
:icon-left="LucidePencilLine"
|
||||
color="subtle"
|
||||
hide-text
|
||||
@click="isSlideEditDialogOpen = true"
|
||||
/>
|
||||
<FormButton
|
||||
:icon-left="LucideX"
|
||||
color="subtle"
|
||||
hide-text
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="w-full md:w-auto">
|
||||
<div class="w-full sm:w-auto">
|
||||
<div class="fixed inset-0 z-10 md:hidden">
|
||||
<div class="absolute inset-0 bg-black/50" />
|
||||
</div>
|
||||
@@ -20,12 +20,6 @@
|
||||
</p>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
<UserAvatar
|
||||
v-if="isLoggedIn"
|
||||
size="sm"
|
||||
class="ml-auto flex-shrink-0"
|
||||
:user="activeUser"
|
||||
/>
|
||||
</section>
|
||||
<section
|
||||
class="flex-1 flex justify-center simple-scrollbar overflow-y-auto mt-3 pb-3 px-3"
|
||||
@@ -59,7 +53,7 @@ graphql(`
|
||||
}
|
||||
`)
|
||||
|
||||
const { isLoggedIn, activeUser } = useActiveUser()
|
||||
const { isLoggedIn } = useActiveUser()
|
||||
const {
|
||||
response: { workspace }
|
||||
} = useInjectedPresentationState()
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
<PresentationActions
|
||||
v-if="!hideUi"
|
||||
v-model:is-sidebar-open="isInfoSidebarOpen"
|
||||
class="absolute bottom-4 md:top-4 right-4 z-20"
|
||||
class="absolute bottom-4 lg:top-4 right-4 z-20"
|
||||
:class="{
|
||||
'bottom-52 lg:bottom-auto md:right-[17rem] xl:right-[21rem]':
|
||||
'bottom-52 lg:bottom-auto lg:right-[17rem] xl:right-[21rem]':
|
||||
isInfoSidebarOpen
|
||||
}"
|
||||
@toggle-sidebar="isInfoSidebarOpen = !isInfoSidebarOpen"
|
||||
@@ -23,12 +23,17 @@
|
||||
<PresentationSlideIndicator
|
||||
v-if="!isViewerLoading"
|
||||
:show-slide-list="!isLeftSidebarOpen"
|
||||
class="absolute top-1/2 translate-y-[calc(-50%+25px)] z-20"
|
||||
:class="[isLeftSidebarOpen ? 'lg:left-[14.75rem] hidden md:block' : 'left-0']"
|
||||
class="absolute top-1/2 z-20"
|
||||
:class="[
|
||||
isInfoSidebarOpen
|
||||
? 'translate-y-[calc(-50%+25px-6rem)] lg:translate-y-[-50%]'
|
||||
: 'translate-y-[-50%]',
|
||||
isLeftSidebarOpen ? 'lg:left-[14.75rem] hidden md:block' : 'left-0'
|
||||
]"
|
||||
/>
|
||||
|
||||
<PresentationSpeckleLogo
|
||||
class="absolute right-4 z-30 top-4 md:top-auto md:bottom-4"
|
||||
class="absolute right-4 z-30 top-4 lg:top-auto lg:bottom-4"
|
||||
:class="[isInfoSidebarOpen ? '' : '']"
|
||||
/>
|
||||
|
||||
@@ -37,7 +42,7 @@
|
||||
class="absolute left-0 top-0 md:relative flex-shrink-0 z-30"
|
||||
/>
|
||||
|
||||
<div class="flex-1 z-0">
|
||||
<div class="flex-1 z-0 flex flex-col lg:flex-row">
|
||||
<Component
|
||||
:is="presentation ? ViewerWrapper : 'div'"
|
||||
:group="presentation"
|
||||
@@ -45,20 +50,20 @@
|
||||
@loading-change="onLoadingChange"
|
||||
@progress-change="onProgressChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<PresentationInfoSidebar
|
||||
v-if="isInfoSidebarOpen"
|
||||
class="flex-shrink-0 z-20"
|
||||
@close="isInfoSidebarOpen = false"
|
||||
/>
|
||||
<PresentationInfoSidebar
|
||||
v-if="isInfoSidebarOpen"
|
||||
class="flex-shrink-0 z-20"
|
||||
@close="isInfoSidebarOpen = false"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<PresentationControls
|
||||
:hide-ui="hideUi"
|
||||
class="absolute left-4 md:left-1/2 md:-translate-x-1/2"
|
||||
class="absolute left-4 lg:left-1/2 lg:-translate-x-1/2"
|
||||
:class="[
|
||||
isInfoSidebarOpen ? 'bottom-52 md:bottom-4' : 'bottom-4',
|
||||
isLeftSidebarOpen ? 'hidden md:flex' : ''
|
||||
isInfoSidebarOpen ? 'bottom-52 lg:bottom-4' : 'bottom-4',
|
||||
isLeftSidebarOpen ? 'hidden md:flex md:left-64' : ''
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<img
|
||||
:src="slide?.screenshot"
|
||||
:alt="slide?.name"
|
||||
class="w-full object-cover rounded-lg border border-outline-3"
|
||||
class="w-full object-cover rounded-lg border border-outline-3 h-64"
|
||||
/>
|
||||
<FormTextInput
|
||||
v-model="name"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<div
|
||||
v-if="showSlideList"
|
||||
class="absolute top-[calc(50%+25px)] -translate-y-1/2 max-h-[75vh] overflow-y-auto w-56 simple-scrollbar bg-foundation border border-outline-3 rounded-xl p-3 shadow-md transition-all duration-300 ease-out opacity-0 invisible group-hover:opacity-100 group-hover:visible -translate-x-5 group-hover:translate-x-0"
|
||||
class="hidden lg:block absolute top-[calc(50%+25px)] -translate-y-1/2 max-h-[75vh] overflow-y-auto w-56 simple-scrollbar bg-foundation border border-outline-3 rounded-xl p-3 shadow-md transition-all duration-300 ease-out opacity-0 invisible group-hover:opacity-100 group-hover:visible -translate-x-5 group-hover:translate-x-0"
|
||||
>
|
||||
<PresentationSlideList class="w-full" hide-title />
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
<template>
|
||||
<li :class="{ 'pb-1 last:pb-0': hideTitle }">
|
||||
<li class="w-full" :class="{ 'pb-1 last:pb-0': hideTitle }">
|
||||
<button
|
||||
class="bg-foundation-page rounded-xl overflow-hidden border border-outline-3 transition-all duration-200 hover:!border-outline-4"
|
||||
class="bg-foundation-page rounded-xl overflow-hidden border border-outline-3 transition-all duration-200 hover:!border-outline-4 w-full"
|
||||
:class="[isCurrentSlide ? '!border-outline-5' : '']"
|
||||
@click="onSelectSlide"
|
||||
>
|
||||
<img :src="slide.screenshot" :alt="slide.name" class="w-full h-28 object-cover" />
|
||||
<img
|
||||
:src="slide.screenshot"
|
||||
:alt="slide.name"
|
||||
class="w-full h-28 object-contain"
|
||||
/>
|
||||
</button>
|
||||
<p v-if="!hideTitle" class="text-body-3xs leading-none text-foreground my-2">
|
||||
{{ slideIndex }}. {{ slide.name }}
|
||||
|
||||
@@ -2,20 +2,27 @@
|
||||
<template>
|
||||
<div
|
||||
ref="resizableElement"
|
||||
class="relative sm:absolute z-10 right-0 overflow-hidden w-screen bottom-0 sm:bottom-auto sm:top-[3.5rem] lg:top-[3rem] sm:right-2 lg:right-0 h-[40dvh] sm:h-[calc(100dvh-8rem)] lg:h-[calc(100dvh-3rem)] sm:max-w-[264px]"
|
||||
class="relative sm:absolute z-10 right-0 overflow-hidden w-screen bottom-0 sm:bottom-auto sm:right-2 h-[40dvh] sm:max-w-[276px]"
|
||||
:style="isLgOrLarger ? { maxWidth: width + 'px' } : {}"
|
||||
:class="[open ? '' : 'pointer-events-none']"
|
||||
:class="[
|
||||
open ? '' : 'pointer-events-none',
|
||||
isEmbedEnabled
|
||||
? 'sm:top-2 sm:h-[calc(100dvh-8rem)]'
|
||||
: 'sm:top-[3.5rem] lg:h-[calc(100dvh-3rem)] lg:top-[3rem] lg:right-0 sm:h-[calc(100dvh-8rem)]'
|
||||
]"
|
||||
>
|
||||
<div class="flex h-full" :class="open ? '' : 'sm:translate-x-[100%]'">
|
||||
<!-- Resize Handle -->
|
||||
<div
|
||||
v-if="!isEmbedEnabled"
|
||||
ref="resizeHandle"
|
||||
class="absolute h-full max-h-[calc(100dvh-3rem)] w-4 transition border-l sm:rounded-lg lg:rounded-none hover:border-l-[2px] border-outline-2 hover:border-primary hidden lg:flex items-center cursor-ew-resize z-30"
|
||||
@mousedown="startResizing"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="flex flex-col w-full h-full relative z-20 overflow-hidden sm:rounded-lg lg:rounded-none border-l border-t sm:border lg:border-0 lg:border-l border-outline-2 bg-foundation"
|
||||
class="flex flex-col w-full h-full relative z-20 overflow-hidden sm:rounded-lg border-l border-t sm:border border-outline-2 bg-foundation"
|
||||
:class="!isEmbedEnabled ? 'lg:rounded-none lg:border-0 lg:border-l' : ''"
|
||||
>
|
||||
<div
|
||||
class="h-10 pl-4 pr-2 flex items-center justify-between border-b border-outline-2"
|
||||
@@ -39,6 +46,7 @@
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useEventListener, useBreakpoints } from '@vueuse/core'
|
||||
import { TailwindBreakpoints } from '~~/lib/common/helpers/tailwind'
|
||||
import { useEmbed } from '~/lib/viewer/composables/setup/embed'
|
||||
|
||||
defineProps<{
|
||||
open: boolean
|
||||
@@ -52,12 +60,13 @@ const emit = defineEmits<{
|
||||
const resizableElement = ref(null)
|
||||
const resizeHandle = ref(null)
|
||||
const isResizing = ref(false)
|
||||
const width = ref(280)
|
||||
const width = ref(276)
|
||||
let startWidth = 0
|
||||
let startX = 0
|
||||
|
||||
const breakpoints = useBreakpoints(TailwindBreakpoints)
|
||||
const isLgOrLarger = breakpoints.greaterOrEqual('lg')
|
||||
const { isEnabled: isEmbedEnabled } = useEmbed()
|
||||
|
||||
const startResizing = (event: MouseEvent) => {
|
||||
event.preventDefault()
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
|
||||
<template>
|
||||
<aside
|
||||
class="absolute left-2 lg:left-0 z-50 flex rounded-lg border border-outline-2 bg-foundation px-1 overflow-visible lg:h-full focus-visible:outline-none"
|
||||
class="absolute left-2 z-50 flex rounded-lg border border-outline-2 bg-foundation px-1 overflow-visible focus-visible:outline-none"
|
||||
:class="[
|
||||
isEmbedEnabled
|
||||
? 'top-[0.5rem]'
|
||||
: 'top-[3.5rem] lg:top-[3rem] lg:rounded-none lg:px-2 lg:max-h-[calc(100dvh-3rem)] lg:border-l-0 lg:border-t-0 lg:border-b-0',
|
||||
: 'top-[3.5rem] lg:top-[3rem] lg:rounded-none lg:px-2 lg:max-h-[calc(100dvh-3rem)] lg:border-l-0 lg:border-t-0 lg:border-b-0 lg:h-full lg:left-0',
|
||||
hasActivePanel && 'h-full max-h-[calc(100dvh-8rem)] rounded-r-none'
|
||||
]"
|
||||
>
|
||||
@@ -121,7 +121,7 @@
|
||||
|
||||
<!-- Resize handle -->
|
||||
<div
|
||||
v-if="activePanel !== 'none'"
|
||||
v-if="activePanel !== 'none' && !isEmbedEnabled"
|
||||
ref="resizeHandle"
|
||||
class="absolute h-full max-h-[calc(100dvh-3rem)] w-4 transition border-l hover:border-l-[2px] border-outline-2 hover:border-primary hidden lg:flex items-center cursor-ew-resize z-30"
|
||||
:style="`left:${width + 52}px;`"
|
||||
@@ -289,7 +289,7 @@ const throttledHandleMouseMove = useThrottleFn((event: MouseEvent) => {
|
||||
)
|
||||
panelExtensionWidth.value = newWidth
|
||||
}
|
||||
}, 150)
|
||||
}, 50)
|
||||
|
||||
if (import.meta.client) {
|
||||
useResizeObserver(scrollableControlsContainer, (entries) => {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
/>
|
||||
<template #title-actions>
|
||||
<div
|
||||
class="flex gap-0.5 items-center opacity-0 group-hover/disclosure:opacity-100"
|
||||
class="flex gap-0.5 items-center lg:opacity-0 lg:group-hover/disclosure:opacity-100"
|
||||
@click.stop
|
||||
>
|
||||
<LayoutMenu
|
||||
|
||||
@@ -36,6 +36,10 @@ export class HighlightExtension extends SelectionExtension {
|
||||
}
|
||||
this.options = highlightMaterialData
|
||||
}
|
||||
|
||||
/** Disable default click events - highlighting is controlled through state only */
|
||||
protected override onObjectClicked() {}
|
||||
protected override onObjectDoubleClick() {}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
type UserMeta {
|
||||
flag(key: String!): Boolean!
|
||||
newWorkspaceExplainerDismissed: Boolean!
|
||||
speckleConBannerDismissed: Boolean!
|
||||
intelligenceCommunityStandUpBannerDismissed: Boolean!
|
||||
@@ -6,6 +7,7 @@ type UserMeta {
|
||||
}
|
||||
|
||||
type UserMetaMutations {
|
||||
setFlag(key: String!, value: Boolean!): Boolean!
|
||||
setNewWorkspaceExplainerDismissed(value: Boolean!): Boolean!
|
||||
setSpeckleConBannerDismissed(value: Boolean!): Boolean!
|
||||
setIntelligenceCommunityStandUpBannerDismissed(value: Boolean!): Boolean!
|
||||
|
||||
@@ -298,10 +298,19 @@ export const StreamFavorites = buildTableHelper('stream_favorites', [
|
||||
'cursor'
|
||||
])
|
||||
|
||||
export const UsersMetaFlags = ['presentationsFeatureNudgeDismissed'] as const
|
||||
|
||||
type UsersMetaFlag = (typeof UsersMetaFlags)[number]
|
||||
|
||||
export const isUsersMetaFlag = (key: string): key is UsersMetaFlag => {
|
||||
return UsersMetaFlags.includes(key as UsersMetaFlag)
|
||||
}
|
||||
|
||||
export const UsersMeta = buildMetaTableHelper(
|
||||
'users_meta',
|
||||
['userId', 'key', 'value', 'createdAt', 'updatedAt'],
|
||||
[
|
||||
...UsersMetaFlags,
|
||||
'isOnboardingFinished',
|
||||
'onboardingStreamId',
|
||||
'activeWorkspace',
|
||||
|
||||
@@ -4955,14 +4955,21 @@ export type UserGendoAiCredits = {
|
||||
|
||||
export type UserMeta = {
|
||||
__typename?: 'UserMeta';
|
||||
flag: Scalars['Boolean']['output'];
|
||||
intelligenceCommunityStandUpBannerDismissed: Scalars['Boolean']['output'];
|
||||
legacyProjectsExplainerCollapsed: Scalars['Boolean']['output'];
|
||||
newWorkspaceExplainerDismissed: Scalars['Boolean']['output'];
|
||||
speckleConBannerDismissed: Scalars['Boolean']['output'];
|
||||
};
|
||||
|
||||
|
||||
export type UserMetaFlagArgs = {
|
||||
key: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export type UserMetaMutations = {
|
||||
__typename?: 'UserMetaMutations';
|
||||
setFlag: Scalars['Boolean']['output'];
|
||||
setIntelligenceCommunityStandUpBannerDismissed: Scalars['Boolean']['output'];
|
||||
setLegacyProjectsExplainerCollapsed: Scalars['Boolean']['output'];
|
||||
setNewWorkspaceExplainerDismissed: Scalars['Boolean']['output'];
|
||||
@@ -4970,6 +4977,12 @@ export type UserMetaMutations = {
|
||||
};
|
||||
|
||||
|
||||
export type UserMetaMutationsSetFlagArgs = {
|
||||
key: Scalars['String']['input'];
|
||||
value: Scalars['Boolean']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type UserMetaMutationsSetIntelligenceCommunityStandUpBannerDismissedArgs = {
|
||||
value: Scalars['Boolean']['input'];
|
||||
};
|
||||
@@ -8557,6 +8570,7 @@ export type UserGendoAiCreditsResolvers<ContextType = GraphQLContext, ParentType
|
||||
};
|
||||
|
||||
export type UserMetaResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['UserMeta'] = ResolversParentTypes['UserMeta']> = {
|
||||
flag?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType, RequireFields<UserMetaFlagArgs, 'key'>>;
|
||||
intelligenceCommunityStandUpBannerDismissed?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
|
||||
legacyProjectsExplainerCollapsed?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
|
||||
newWorkspaceExplainerDismissed?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
|
||||
@@ -8565,6 +8579,7 @@ export type UserMetaResolvers<ContextType = GraphQLContext, ParentType extends R
|
||||
};
|
||||
|
||||
export type UserMetaMutationsResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['UserMetaMutations'] = ResolversParentTypes['UserMetaMutations']> = {
|
||||
setFlag?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType, RequireFields<UserMetaMutationsSetFlagArgs, 'key' | 'value'>>;
|
||||
setIntelligenceCommunityStandUpBannerDismissed?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType, RequireFields<UserMetaMutationsSetIntelligenceCommunityStandUpBannerDismissedArgs, 'value'>>;
|
||||
setLegacyProjectsExplainerCollapsed?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType, RequireFields<UserMetaMutationsSetLegacyProjectsExplainerCollapsedArgs, 'value'>>;
|
||||
setNewWorkspaceExplainerDismissed?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType, RequireFields<UserMetaMutationsSetNewWorkspaceExplainerDismissedArgs, 'value'>>;
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
lookupUsersFactory,
|
||||
bulkLookupUsersFactory
|
||||
} from '@/modules/core/repositories/users'
|
||||
import { Users, UsersMeta } from '@/modules/core/dbSchema'
|
||||
import { isUsersMetaFlag, Users, UsersMeta } from '@/modules/core/dbSchema'
|
||||
import { throwForNotHavingServerRole } from '@/modules/shared/authz'
|
||||
import {
|
||||
deleteAllUserInvitesFactory,
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
findServerInvitesFactory
|
||||
} from '@/modules/serverinvites/repositories/serverInvites'
|
||||
import db from '@/db/knex'
|
||||
import { BadRequestError } from '@/modules/shared/errors'
|
||||
import { BadRequestError, InvalidArgumentError } from '@/modules/shared/errors'
|
||||
import {
|
||||
updateUserAndNotifyFactory,
|
||||
deleteUserFactory,
|
||||
@@ -502,6 +502,16 @@ export default {
|
||||
meta: () => ({})
|
||||
},
|
||||
UserMetaMutations: {
|
||||
setFlag: async (_parent, { key, value }, ctx) => {
|
||||
if (!isUsersMetaFlag(key)) {
|
||||
throw new InvalidArgumentError(`User flag ${key} is not known.`)
|
||||
}
|
||||
|
||||
const meta = metaHelpers(Users, db)
|
||||
const res = await meta.set(ctx.userId!, key, value)
|
||||
|
||||
return !!res.value
|
||||
},
|
||||
setLegacyProjectsExplainerCollapsed: async (_parent, args, ctx) => {
|
||||
const meta = metaHelpers(Users, db)
|
||||
const res = await meta.set(
|
||||
|
||||
Reference in New Issue
Block a user