feat(fe2): presentations ui polish

This commit is contained in:
Jack
2025-09-24 15:08:05 +01:00
committed by GitHub
15 changed files with 111 additions and 60 deletions
@@ -1,6 +1,6 @@
<template>
<div
class="bg-foundation border border-outline-3 rounded-xl shadow-md h-10 flex items-center"
class="bg-foundation border border-outline-3 rounded-xl shadow-md flex items-center h-10"
>
<div class="flex items-center justify-between space-x-1 p-1">
<FormButton>Share</FormButton>
@@ -9,21 +9,32 @@
class="hidden md:flex touch:hidden"
@click="toggleFullscreen"
>
<LucideFullscreen class="size-4" />
<LucideMinimize
v-if="isFullscreen"
:size="16"
:stroke-width="1.5"
:absolute-stroke-width="true"
/>
<LucideMaximize
v-else
:size="16"
:stroke-width="1.5"
:absolute-stroke-width="true"
/>
</PresentationFloatingPanelButton>
<PresentationFloatingPanelButton
:is-active="isSidebarOpen"
@click="emit('toggleSidebar')"
>
<LucideInfo class="size-4" />
<LucideInfo :size="16" :stroke-width="1.5" :absolute-stroke-width="true" />
</PresentationFloatingPanelButton>
</div>
</div>
</template>
<script setup lang="ts">
import { LucideInfo, LucideFullscreen } from 'lucide-vue-next'
import { LucideInfo, LucideMaximize, LucideMinimize } from 'lucide-vue-next'
const emit = defineEmits<{
(e: 'toggleSidebar'): void
@@ -31,6 +42,8 @@ const emit = defineEmits<{
const isSidebarOpen = defineModel<boolean>('is-sidebar-open')
const isFullscreen = ref(false)
const toggleFullscreen = () => {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen()
@@ -38,4 +51,17 @@ const toggleFullscreen = () => {
document.exitFullscreen()
}
}
// Listen for fullscreen changes
const handleFullscreenChange = () => {
isFullscreen.value = !!document.fullscreenElement
}
onMounted(() => {
document.addEventListener('fullscreenchange', handleFullscreenChange)
})
onUnmounted(() => {
document.removeEventListener('fullscreenchange', handleFullscreenChange)
})
</script>
@@ -1,16 +1,26 @@
<template>
<PresentationFloatingPanel>
<div class="flex items-center justify-between space-x-1">
<div class="flex items-center justify-between space-x-2">
<PresentationFloatingPanelButton
:active="isSidebarOpen"
@click="emit('toggleSidebar')"
>
<LucideArrowLeftToLine v-if="isSidebarOpen" class="size-4" />
<LucidePanelLeft v-else class="size-4" />
<LucideArrowLeftToLine
v-if="isSidebarOpen"
:size="16"
:stroke-width="1.5"
:absolute-stroke-width="true"
/>
<LucidePanelLeft
v-else
:size="16"
:stroke-width="1.5"
:absolute-stroke-width="true"
/>
</PresentationFloatingPanelButton>
<h1
v-if="presentation?.title"
class="hidden sm:block text-body-xs font-medium text-foreground leading-none sm:pr-1.5"
class="hidden sm:block text-body-xs font-medium text-foreground leading-none sm:pr-3 max-w-64 truncate"
>
{{ presentation?.title }}
</h1>
@@ -1,8 +1,8 @@
<template>
<aside
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"
class="bg-foundation h-[196px] lg:h-dvh w-full lg:w-[260px] xl:w-[324px] border-t lg:border-t-0 lg:border-l border-outline-3 p-4"
>
<div class="hidden lg:flex items-center justify-end space-x-0.5">
<div class="hidden lg:flex items-center justify-end space-x-1">
<div
v-tippy="
canUpdateSlide ? undefined : 'You do not have permission to edit this slide'
@@ -24,9 +24,12 @@
@click="$emit('close')"
/>
</div>
<section class="pt-2 flex flex-col gap-4">
<div class="flex items-center justify-between gap-x-2">
<h1 v-if="currentSlide?.name" class="text-xl font-medium text-foreground px-2">
<section class="lg:pt-4 lg:px-1 flex flex-col gap-3">
<div class="flex items-start justify-between gap-x-2">
<h1
v-if="currentSlide?.name"
class="text-xl/7 xl:text-[26px]/8 tracking-[-0.399px] xl:tracking-[-0.494px] font-medium text-foreground px-1 lg:px-2 xl:px-3 py-0.5 lg:py-1.5"
>
{{ currentSlide?.name }}
</h1>
<div class="lg:hidden flex items-center gap-x-1">
@@ -37,18 +40,12 @@
hide-text
@click="isSlideEditDialogOpen = true"
/>
<FormButton
:icon-left="LucideX"
color="subtle"
hide-text
@click="$emit('close')"
/>
</div>
</div>
<p
v-if="currentSlide?.description"
class="text-body-sm text-foreground whitespace-pre-wrap px-2"
class="text-body-sm xl:text-body text-foreground whitespace-pre-wrap px-1 lg:px-2 xl:px-3 lg:py-1"
>
{{ currentSlide?.description }}
</p>
@@ -1,28 +1,34 @@
<template>
<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 class="absolute inset-0 bg-black/20" />
</div>
<aside
class="relative z-20 bg-foundation h-dvh w-52 md:w-60 border-r border-outline-3 pt-3"
class="relative z-20 bg-foundation h-dvh w-[212px] md:w-60 border-r border-outline-3"
>
<div class="flex flex-col h-full">
<section class="flex-shrink-0 flex items-center gap-3 px-3">
<section
class="flex-shrink-0 flex items-center gap-3 absolute bg-foundation/70 backdrop-blur-lg w-full p-3 pb-2.5 border-b border-white/80 dark:border-gray-900/30"
>
<NuxtLink
class="flex items-center gap-2 min-w-0 flex-1"
class="flex items-center gap-2.5 min-w-0 flex-1"
:to="workspaceRoute(workspace?.slug)"
>
<WorkspaceAvatar :name="workspace?.name" :logo="workspace?.logo" />
<WorkspaceAvatar
:name="workspace?.name"
:logo="workspace?.logo"
size="lg"
/>
<div class="flex-1 min-w-0">
<p class="text-body-xs text-foreground truncate">
<p class="text-body-xs font-medium text-foreground truncate">
{{ workspace?.name }}
</p>
</div>
</NuxtLink>
</section>
<section
class="flex-1 flex justify-center simple-scrollbar overflow-y-auto mt-3 pb-3 px-3"
class="flex-1 flex justify-center simple-scrollbar overflow-y-auto pt-16 pb-3 px-3"
>
<PresentationSlideList />
</section>
@@ -4,15 +4,15 @@
<PresentationHeader
v-if="!hideUi"
v-model:is-sidebar-open="isLeftSidebarOpen"
class="absolute top-4 z-40"
:class="[isLeftSidebarOpen ? 'left-56 md:left-[15.75rem]' : 'left-4']"
class="absolute top-3 z-40"
:class="[isLeftSidebarOpen ? 'left-56 md:left-[15.75rem]' : 'left-3']"
@toggle-sidebar="isLeftSidebarOpen = !isLeftSidebarOpen"
/>
<PresentationActions
v-if="!hideUi"
v-model:is-sidebar-open="isInfoSidebarOpen"
class="absolute bottom-4 lg:top-4 right-4 z-20"
class="absolute bottom-3 lg:top-3 right-3 z-20"
:class="{
'bottom-52 lg:bottom-auto lg:right-[17rem] xl:right-[21rem]':
isInfoSidebarOpen
@@ -28,12 +28,12 @@
isInfoSidebarOpen
? 'translate-y-[calc(-50%+25px-6rem)] lg:translate-y-[-50%]'
: 'translate-y-[-50%]',
isLeftSidebarOpen ? 'lg:left-[14.75rem] hidden md:block' : 'left-0'
isLeftSidebarOpen ? 'lg:left-60 hidden md:block' : 'left-0'
]"
/>
<PresentationSpeckleLogo
class="absolute right-4 z-30 top-4 lg:top-auto lg:bottom-4"
class="absolute right-3 z-30 top-3 lg:top-auto lg:bottom-3"
:class="[isInfoSidebarOpen ? '' : '']"
/>
@@ -60,10 +60,10 @@
<PresentationControls
:hide-ui="hideUi"
class="absolute left-4 lg:left-1/2 lg:-translate-x-1/2"
class="absolute left-3 lg:left-1/2 lg:-translate-x-1/2"
:class="[
isInfoSidebarOpen ? 'bottom-52 lg:bottom-4' : 'bottom-4',
isLeftSidebarOpen ? 'hidden md:flex md:left-64' : ''
isInfoSidebarOpen ? 'bottom-52 lg:bottom-3' : 'bottom-3',
isLeftSidebarOpen ? 'hidden md:flex md:left-[252px]' : ''
]"
/>
</div>
@@ -101,7 +101,7 @@ const onLoadingChange = (loading: boolean) => {
if (!loading) {
hideUi.value = false
isLeftSidebarOpen.value = !isMobile.value
isLeftSidebarOpen.value = false
isInfoSidebarOpen.value = !isMobile.value
}
}
@@ -1,5 +1,5 @@
<template>
<div class="p-4 absolute group">
<div class="p-5 absolute group">
<ul class="flex flex-col space-y-2">
<li v-for="slide in visibleSlides" :key="slide.id">
<div
@@ -11,7 +11,7 @@
<div
v-if="showSlideList"
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"
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-2xl p-2 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,12 +1,21 @@
<template>
<PresentationFloatingPanel class="flex items-center shrink-0 select-none px-3 h-10">
<span class="text-body-2xs text-foreground-2">Made with</span>
<img
class="size-5 block mr-0.5 ml-1"
src="~~/assets/images/speckle_logo_big.png"
alt="Speckle"
/>
<PresentationFloatingPanel
class="flex items-center shrink-0 select-none px-[3px] h-10"
>
<NuxtLink
to="https://speckle.systems/"
external
target="_blank"
class="flex items-center gap-1 hover:bg-highlight-1 rounded-md h-8 px-2.5"
>
<span class="text-body-xs text-foreground-2">Made with</span>
<img
class="size-6 block mr-[0.5px] ml-0.5"
src="~~/assets/images/speckle_logo_big.png"
alt="Speckle"
/>
<div class="text-body-xs mt-0 font-medium">Speckle</div>
<div class="text-body-xs mt-0 font-medium">Speckle</div>
</NuxtLink>
</PresentationFloatingPanel>
</template>
@@ -1,7 +1,7 @@
<template>
<button
:disabled="disabled"
class="bg-foundation size-9 flex items-center justify-center hover:bg-primary-muted disabled:hover:bg-transparent text-foreground disabled:text-foreground-3"
class="bg-foundation size-8 rounded-md flex items-center justify-center hover:bg-primary-muted disabled:hover:bg-transparent text-foreground disabled:text-foreground-3"
>
<component :is="icon" class="size-4" />
<slot />
@@ -1,6 +1,6 @@
<template>
<div
class="flex items-center rounded-xl bg-foundation border border-outline-3 shadow-md overflow-hidden divide-x divide-outline-3"
class="flex items-center rounded-xl bg-foundation border border-outline-3 shadow-md overflow-hidden h-10 p-[3px]"
:class="{ hidden: hideUi }"
>
<PresentationControlsButton
@@ -1,8 +1,9 @@
<template>
<button
class="size-8 flex items-center justify-center bg-foundation rounded-xl hover:bg-info-lighter hover:text-primary-focus dark:hover:text-foreground-on-primary"
class="size-8 flex items-center text-foreground justify-center bg-foundation rounded-md hover:bg-primary-muted dark:hover:text-foreground-on-primary"
:class="{
'bg-info-lighter text-primary-focus dark:text-foreground-on-primary': isActive
'bg-info-lighter hover:!bg-info-lighter text-primary-focus dark:text-foreground-on-primary':
isActive
}"
>
<slot />
@@ -1,6 +1,6 @@
<template>
<div
class="bg-foundation border border-outline-3 rounded-xl p-1 shadow-md h-10 flex items-center"
class="bg-foundation border border-collapse border-outline-3 rounded-xl p-1 p-x-[3px] shadow-md flex items-center h-10"
>
<slot />
</div>
@@ -1,18 +1,20 @@
<template>
<li class="w-full" :class="{ 'pb-1 last:pb-0': hideTitle }">
<li class="w-full" :class="{ 'pb-0': hideTitle }">
<button
class="bg-foundation-page rounded-xl overflow-hidden border border-outline-3 transition-all duration-200 hover:!border-outline-4 w-full"
class="bg-foundation-page rounded-md 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-contain"
class="w-full aspect-[3/2] md:aspect-video object-cover"
/>
</button>
<p v-if="!hideTitle" class="text-body-3xs leading-none text-foreground my-2">
{{ slideIndex }}. {{ slide.name }}
<p v-if="!hideTitle" class="text-body-3xs font-medium text-foreground mt-1.5 mb-2">
<span class="font-semibold mr-1">{{ slideIndex }}.</span>
{{ slide.name }}
</p>
</li>
</template>
@@ -63,7 +63,7 @@
/>
</div>
</template>
<div class="px-3 pt-3">
<div class="px-2 pt-2">
<ViewerButtonGroup>
<ViewerButtonGroupButton
v-for="viewsType in Object.values(ViewsType)"
@@ -7,7 +7,7 @@
v-if="!hasGroups || !project"
:type="emptyStateType"
/>
<div v-else class="p-1.5 pt-2">
<div v-else class="p-2 pt-2">
<ViewerSavedViewsPanelViewsGroup
v-for="group in groups"
:key="group.id"
@@ -24,7 +24,7 @@
</div>
</div>
</div>
<div class="flex flex-col min-w-0 grow">
<div class="flex flex-col min-w-0 grow gap-y-0.5">
<div class="text-body-2xs font-medium text-foreground truncate grow-0">
{{ view.name }}
</div>
@@ -279,7 +279,7 @@ const menuItems = computed((): LayoutMenuItem<MenuItems>[][] => [
const wrapperClasses = computed(() => {
const classParts = [
'flex items-center gap-2 p-1.5 w-full group rounded-md cursor-pointer relative transition-all'
'flex items-center gap-2 p-2 w-full group rounded-md cursor-pointer relative transition-all'
]
if (isActive.value) {