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:
emmanuel
2023-10-03 14:51:02 +00:00
committed by Space Cloud
co-authored by Rotimi Best
parent 5009f22e79
commit d3bda61904
6 changed files with 319 additions and 16 deletions
@@ -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}
+122 -7
View File
@@ -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
+11 -1
View File
@@ -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>
+4
View File
@@ -7,3 +7,7 @@ export const menu = writable({
export const newOrgModal = writable({
open: false
});
export const sideBar = writable({
open: true
});