CLASSROOMIO-T-184:Made the sidebar draggable
CLASSROOMIO-T-184:removed console.log Merge branch 'CLASSROOMIO-T-184' of https://gitlab.com/thenextgreat/classroomio into CLASSROOMIO-T-184 Merge branch 'main' into CLASSROOMIO-T-184 CLASSROOMIO-T-184:Made updates to the resizeable sidebars CLASSROOMIO-T-184:Making the resizable sidebar better CLASSROOMIO-T-184: fix server side error and ts support Merge branch 'main' into CLASSROOMIO-T-184 CLASSROOMIO-T-184:Made the slidebar draggable Co-authored-by: Ifeanyi Nwosu <[email protected]> Co-authored-by: Rotimi Best <[email protected]> Merge-request: CLASSROOMIO-MR-81 Merged-by: Best Admin <[email protected]>
This commit is contained in:
committed by
Space Cloud
co-authored by
Rotimi Best
parent
5009f22e79
commit
d3bda61904
@@ -46,7 +46,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="p-4 bg-white dark:bg-black border-2 rounded-md mb-3">
|
||||
<div class="p-4 flex-wrap bg-white dark:bg-black border-2 rounded-md mb-3 w-full">
|
||||
{#if selectedOptionToView}
|
||||
<div>
|
||||
<div class="flex items-center mb-5">
|
||||
@@ -67,7 +67,7 @@
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex mb-3 justify-between">
|
||||
<div class="flex flex-wrap gap-2 mb-3 justify-between">
|
||||
<div>
|
||||
<h3 class="dark:text-white font-bold">
|
||||
{poll.question}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import hotkeys from 'hotkeys-js';
|
||||
import Forum from 'carbon-icons-svelte/lib/Forum.svelte';
|
||||
import AlignBoxTopLeft from 'carbon-icons-svelte/lib/AlignBoxTopLeft.svelte';
|
||||
@@ -14,14 +14,33 @@
|
||||
import Notes from './components/Notes/index.svelte';
|
||||
import Poll from './components/Poll/index.svelte';
|
||||
import APPS_CONSTANTS from './constants';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
let selectedApp;
|
||||
let resize = false;
|
||||
let isDragging = false;
|
||||
let startX;
|
||||
let initialWidth;
|
||||
let appBarRef;
|
||||
let appContentRef;
|
||||
|
||||
const ResizableSidebar = window.innerWidth >= 1024;
|
||||
|
||||
function handleClose() {
|
||||
selectedApp = null;
|
||||
if (ResizableSidebar) {
|
||||
appBarRef.style.width = '60px';
|
||||
}
|
||||
}
|
||||
|
||||
function handleAppClick(appName) {
|
||||
if (!selectedApp && ResizableSidebar) {
|
||||
if (window.innerWidth <= 1024) {
|
||||
appBarRef.style.width = '300px';
|
||||
} else {
|
||||
appBarRef.style.width = '400px';
|
||||
}
|
||||
}
|
||||
if (appName === selectedApp) {
|
||||
handleClose();
|
||||
} else {
|
||||
@@ -29,7 +48,69 @@
|
||||
}
|
||||
$apps.dropdown = false;
|
||||
}
|
||||
|
||||
function handleCursor(event) {
|
||||
if (!ResizableSidebar) return;
|
||||
if (!resize && selectedApp) {
|
||||
const isNearLeftBorder = event.clientX - appContentRef.getBoundingClientRect().left < 8;
|
||||
const isNearRightBorder = appContentRef.getBoundingClientRect().right - event.clientX < 8;
|
||||
|
||||
if (isNearLeftBorder || isNearRightBorder) {
|
||||
appContentRef.style.cursor = 'ew-resize';
|
||||
} else {
|
||||
appContentRef.style.cursor = 'auto';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startDragging(event) {
|
||||
if (!ResizableSidebar) return;
|
||||
if (event.button === 0 && selectedApp) {
|
||||
event.preventDefault();
|
||||
const isNearLeftBorder = event.clientX - appContentRef.getBoundingClientRect().left < 8;
|
||||
const isNearRightBorder = appContentRef.getBoundingClientRect().right - event.clientX < 8;
|
||||
|
||||
if (
|
||||
(isNearRightBorder || isNearLeftBorder) &&
|
||||
event.clientX >= 0 &&
|
||||
event.clientX <= window.innerWidth
|
||||
) {
|
||||
isDragging = true;
|
||||
resize = true;
|
||||
startX = event.clientX;
|
||||
initialWidth = parseInt(getComputedStyle(appBarRef).width, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stopDragging() {
|
||||
if (!ResizableSidebar) return;
|
||||
isDragging = false;
|
||||
resize = false;
|
||||
}
|
||||
|
||||
function dragSidebar(event) {
|
||||
if (!ResizableSidebar) return;
|
||||
if (!isDragging || !selectedApp) return;
|
||||
const deltaX = startX - event.clientX + 60;
|
||||
let newWidth = initialWidth + deltaX;
|
||||
if (newWidth <= 100) {
|
||||
handleClose();
|
||||
appBarRef.style.width = '60px';
|
||||
appContentRef.style.width = '0';
|
||||
} else {
|
||||
appBarRef.style.width = newWidth + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (ResizableSidebar) {
|
||||
appBarRef.addEventListener('mousedown', startDragging);
|
||||
document.addEventListener('mousemove', dragSidebar);
|
||||
document.addEventListener('mouseup', stopDragging);
|
||||
document.addEventListener('mousemove', handleCursor);
|
||||
}
|
||||
|
||||
hotkeys('A+1,A+2,A+3,A+4', function (event, handler) {
|
||||
event.preventDefault();
|
||||
switch (handler.key) {
|
||||
@@ -48,9 +129,22 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (ResizableSidebar) {
|
||||
appBarRef.removeEventListener('mousedown', startDragging);
|
||||
document.removeEventListener('mousemove', dragSidebar);
|
||||
document.removeEventListener('mouseup', stopDragging);
|
||||
document.removeEventListener('mousemove', handleCursor);
|
||||
}
|
||||
});
|
||||
$: ResizableSidebar;
|
||||
</script>
|
||||
|
||||
<div class={`root ${$apps.open ? 'open dark:bg-black' : 'close dark:bg-black'}`}>
|
||||
<div
|
||||
class={`${$apps.open ? 'open dark:bg-slate-800' : 'close dark:bg-slate-800'} root`}
|
||||
bind:this={appBarRef}
|
||||
>
|
||||
<div class={`apps`}>
|
||||
<div class="lg:hidden">
|
||||
<IconButton
|
||||
@@ -103,7 +197,12 @@
|
||||
</div>
|
||||
|
||||
{#if !!selectedApp}
|
||||
<div class="app">
|
||||
<div
|
||||
class={`app cursor-auto lg:cursor-ew-resize ${
|
||||
resize && ' border-l-8 border-l-blue-500 transition-none'
|
||||
} `}
|
||||
bind:this={appContentRef}
|
||||
>
|
||||
{#if selectedApp === APPS_CONSTANTS.APPS.QANDA}
|
||||
<QandA {handleClose} />
|
||||
{:else if selectedApp === APPS_CONSTANTS.APPS.LIVE_CHAT}
|
||||
@@ -138,8 +237,25 @@
|
||||
}
|
||||
|
||||
& .app {
|
||||
width: 400px;
|
||||
transition: all 1s ease-out;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) and (max-width: 1023px) {
|
||||
.app {
|
||||
min-width: 280px;
|
||||
max-width: 300px;
|
||||
width: 300px;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
.app {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
@@ -187,8 +303,7 @@
|
||||
}
|
||||
|
||||
& .app {
|
||||
width: 400px;
|
||||
transition: all 1s ease-out;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import hotkeys from 'hotkeys-js';
|
||||
@@ -13,7 +13,7 @@
|
||||
import { course } from '$lib/components/Course/store';
|
||||
import { NavClasses } from '$lib/utils/constants/reusableClass';
|
||||
import { isMobile } from '$lib/utils/store/useMobile';
|
||||
import { menu } from '$lib/components/Org/store';
|
||||
import { menu, sideBar } from '$lib/components/Org/store';
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
import { getIsLessonComplete } from '../Lesson/functions';
|
||||
|
||||
@@ -29,7 +29,15 @@
|
||||
}
|
||||
|
||||
let show: boolean = false;
|
||||
let isLessonActive = false;
|
||||
let isLessonActive: boolean = false;
|
||||
let resize = false;
|
||||
let isDragging = false;
|
||||
let startX;
|
||||
let initialWidth;
|
||||
let sidebarRef;
|
||||
let menuContentRef;
|
||||
|
||||
const ResizableSidebar = window.innerWidth >= 1024;
|
||||
|
||||
const toggleSidebar = () => {
|
||||
$menu.hidden = !$menu.hidden;
|
||||
@@ -49,7 +57,75 @@
|
||||
else show = true;
|
||||
}
|
||||
|
||||
function handleCursor(event) {
|
||||
if (!resize) {
|
||||
const isNearLeftBorder = event.clientX - sidebarRef.getBoundingClientRect().left < 8;
|
||||
const isNearRightBorder = sidebarRef.getBoundingClientRect().right - event.clientX < 8;
|
||||
|
||||
if (isNearLeftBorder || isNearRightBorder) {
|
||||
sidebarRef.style.cursor = 'ew-resize';
|
||||
} else {
|
||||
sidebarRef.style.cursor = 'auto';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startDragging(event) {
|
||||
if (event.button === 0) {
|
||||
event.preventDefault();
|
||||
|
||||
const isNearRightBorder = sidebarRef.getBoundingClientRect().right - event.clientX < 8;
|
||||
const isNearLeftBorder = event.clientX - sidebarRef.getBoundingClientRect().left < 8;
|
||||
|
||||
if (
|
||||
(isNearRightBorder || isNearLeftBorder) &&
|
||||
event.clientX >= 0 &&
|
||||
event.clientX <= window.innerWidth
|
||||
) {
|
||||
isDragging = true;
|
||||
resize = true;
|
||||
startX = event.clientX;
|
||||
initialWidth = parseInt(getComputedStyle(sidebarRef).width, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stopDragging() {
|
||||
isDragging = false;
|
||||
resize = false;
|
||||
}
|
||||
|
||||
function dragSidebar(event) {
|
||||
if (!ResizableSidebar) return;
|
||||
if (!isDragging) return;
|
||||
|
||||
const deltaX = event.clientX - startX;
|
||||
let newWidth = initialWidth + deltaX;
|
||||
|
||||
if (newWidth < 150) {
|
||||
sidebarRef.style.width = '0';
|
||||
menuContentRef.style.display = 'none';
|
||||
$sideBar.open = false;
|
||||
isDragging = false;
|
||||
resize = false;
|
||||
} else if (newWidth > window.innerWidth / 3 && window.innerWidth >= 1280) {
|
||||
sidebarRef.style.width = '40vw';
|
||||
} else if (newWidth > window.innerWidth / 4 && window.innerWidth < 1280) {
|
||||
sidebarRef.style.width = '28vw';
|
||||
} else {
|
||||
sidebarRef.style.width = newWidth + 'px';
|
||||
menuContentRef.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (ResizableSidebar) {
|
||||
sidebarRef.addEventListener('mousedown', startDragging);
|
||||
document.addEventListener('mousemove', dragSidebar);
|
||||
document.addEventListener('mouseup', stopDragging);
|
||||
document.addEventListener('mousemove', handleCursor);
|
||||
}
|
||||
|
||||
if (browser) {
|
||||
if (localStorage.getItem('hideCourseNav')) {
|
||||
show = localStorage.getItem('hideCourseNav') === 'false';
|
||||
@@ -68,6 +144,15 @@
|
||||
});
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (ResizableSidebar) {
|
||||
sidebarRef.removeEventListener('mousedown', startDragging);
|
||||
document.removeEventListener('mousemove', dragSidebar);
|
||||
document.removeEventListener('mouseup', stopDragging);
|
||||
document.removeEventListener('mousemove', handleCursor);
|
||||
}
|
||||
});
|
||||
|
||||
$: handleMobileChange($isMobile);
|
||||
|
||||
$: {
|
||||
@@ -142,6 +227,7 @@
|
||||
}
|
||||
];
|
||||
}
|
||||
$: ResizableSidebar;
|
||||
</script>
|
||||
|
||||
<aside
|
||||
@@ -149,10 +235,18 @@
|
||||
$menu.hidden
|
||||
? '-translate-x-[100%] absolute md:translate-x-0 md:relative z-[40]'
|
||||
: 'translate-x-0 absolute md:relative z-[40]'
|
||||
} transition w-[90vw] md:max-w-[350px] bg-gray-100 dark:bg-black h-[calc(100vh-48px)] overflow-y-auto border border-l-0 border-t-0 border-b-0 border-r-1`}
|
||||
} transition w-[90vw] md:w-[350px] bg-gray-100 dark:bg-black h-[calc(100vh-48px)] ${
|
||||
resize && 'border-r-8 border-r-blue-500'
|
||||
} overflow-y-auto border border-l-0 border-t-0 border-b-0 border-r-1`}
|
||||
style={$sideBar.open && 'width:0' ? 'width :300px' : 'width:0'}
|
||||
bind:this={sidebarRef}
|
||||
>
|
||||
<div class="h-full flex flex-col">
|
||||
<ul class="my-5">
|
||||
<div class="sidebar-contenth-full flex flex-col">
|
||||
<ul
|
||||
class="sidebar-content my-5"
|
||||
style={$sideBar.open && 'width:0' ? 'display:block' : ''}
|
||||
bind:this={menuContentRef}
|
||||
>
|
||||
{#each navItems as navItem}
|
||||
{#if !navItem.show || (typeof navItem.show === 'function' && navItem.show())}
|
||||
<NavExpandable
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import { currentOrgPath } from '$lib/utils/store/org';
|
||||
import { toggleBodyByMode } from '$lib/utils/functions/app';
|
||||
import { goto } from '$app/navigation';
|
||||
import { menu } from '../Org/store';
|
||||
import { menu, sideBar } from '../Org/store';
|
||||
|
||||
export let title = '';
|
||||
export let navClass = '';
|
||||
@@ -22,6 +22,10 @@
|
||||
$menu.hidden = !$menu.hidden;
|
||||
};
|
||||
|
||||
const openSidebar = () => {
|
||||
$sideBar.open = !$sideBar.open;
|
||||
};
|
||||
|
||||
function toggleDarkMode() {
|
||||
$appStore.isDark = !$appStore.isDark;
|
||||
|
||||
@@ -50,6 +54,12 @@
|
||||
</IconButton>
|
||||
</li>
|
||||
|
||||
<li class="hidden md:block">
|
||||
<IconButton onClick={openSidebar}>
|
||||
<Menu size={16} class=" text-white" />
|
||||
</IconButton>
|
||||
</li>
|
||||
|
||||
{#if isCoursePage}
|
||||
<div class="hidden md:block">
|
||||
<IconButton
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<!-- ResizableSidebar.svelte -->
|
||||
|
||||
<script>
|
||||
let expanding = null;
|
||||
let startX = 0;
|
||||
let initialX = 0;
|
||||
let initialWidth = 300; // Initial width
|
||||
let width = initialWidth;
|
||||
let x = 20; // Initial x-position
|
||||
const grabberWidth = 10;
|
||||
const MIN_WIDTH = 300; // Minimum width
|
||||
const MAX_WIDTH = 500; // Maximum width
|
||||
|
||||
function startExpand(type, event) {
|
||||
expanding = type;
|
||||
startX = event.pageX;
|
||||
initialX = x;
|
||||
initialWidth = width;
|
||||
}
|
||||
|
||||
function stopExpand() {
|
||||
expanding = null;
|
||||
}
|
||||
|
||||
function expand(event) {
|
||||
if (!expanding) return;
|
||||
|
||||
const deltaX = event.pageX - startX;
|
||||
const newWidth = initialWidth + deltaX;
|
||||
|
||||
// Ensure the width stays within the specified range
|
||||
if (newWidth >= MIN_WIDTH && newWidth <= MAX_WIDTH) {
|
||||
width = newWidth;
|
||||
x = initialX + deltaX;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:fragment on:mouseup={stopExpand} />
|
||||
|
||||
<svg viewBox="0 0 100 40" height="44" width="300" on:mousemove={expand} class:expanding>
|
||||
<rect {x} y="2" {width} height="36" class="step" />
|
||||
<rect
|
||||
{x}
|
||||
y="2"
|
||||
width={grabberWidth}
|
||||
height="36"
|
||||
fill="red"
|
||||
class:active={expanding === 'left' ? 'grip active' : 'grip'}
|
||||
on:mousedown={startExpand.bind(this, 'left')}
|
||||
/>
|
||||
<rect
|
||||
x={x + width - grabberWidth}
|
||||
y="2"
|
||||
width={grabberWidth}
|
||||
height="36"
|
||||
fill="blue"
|
||||
class:active={expanding === 'right' ? 'grip active' : 'grip'}
|
||||
on:mousedown={startExpand.bind(this, 'right')}
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<style>
|
||||
.step {
|
||||
fill: #8884;
|
||||
stroke: #222a;
|
||||
rx: 2;
|
||||
}
|
||||
.expanding .step {
|
||||
stroke: #228e;
|
||||
}
|
||||
.grip {
|
||||
cursor: col-resize;
|
||||
fill: #fff0;
|
||||
}
|
||||
.grip.active,
|
||||
.grip:hover {
|
||||
fill: #2288;
|
||||
}
|
||||
</style>
|
||||
@@ -7,3 +7,7 @@ export const menu = writable({
|
||||
export const newOrgModal = writable({
|
||||
open: false
|
||||
});
|
||||
|
||||
export const sideBar = writable({
|
||||
open: true
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user