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> </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} {#if selectedOptionToView}
<div> <div>
<div class="flex items-center mb-5"> <div class="flex items-center mb-5">
@@ -67,7 +67,7 @@
{/each} {/each}
</div> </div>
{:else} {:else}
<div class="flex mb-3 justify-between"> <div class="flex flex-wrap gap-2 mb-3 justify-between">
<div> <div>
<h3 class="dark:text-white font-bold"> <h3 class="dark:text-white font-bold">
{poll.question} {poll.question}
+122 -7
View File
@@ -1,5 +1,5 @@
<script> <script>
import { onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import hotkeys from 'hotkeys-js'; import hotkeys from 'hotkeys-js';
import Forum from 'carbon-icons-svelte/lib/Forum.svelte'; import Forum from 'carbon-icons-svelte/lib/Forum.svelte';
import AlignBoxTopLeft from 'carbon-icons-svelte/lib/AlignBoxTopLeft.svelte'; import AlignBoxTopLeft from 'carbon-icons-svelte/lib/AlignBoxTopLeft.svelte';
@@ -14,14 +14,33 @@
import Notes from './components/Notes/index.svelte'; import Notes from './components/Notes/index.svelte';
import Poll from './components/Poll/index.svelte'; import Poll from './components/Poll/index.svelte';
import APPS_CONSTANTS from './constants'; import APPS_CONSTANTS from './constants';
import { browser } from '$app/environment';
let selectedApp; let selectedApp;
let resize = false;
let isDragging = false;
let startX;
let initialWidth;
let appBarRef;
let appContentRef;
const ResizableSidebar = window.innerWidth >= 1024;
function handleClose() { function handleClose() {
selectedApp = null; selectedApp = null;
if (ResizableSidebar) {
appBarRef.style.width = '60px';
}
} }
function handleAppClick(appName) { function handleAppClick(appName) {
if (!selectedApp && ResizableSidebar) {
if (window.innerWidth <= 1024) {
appBarRef.style.width = '300px';
} else {
appBarRef.style.width = '400px';
}
}
if (appName === selectedApp) { if (appName === selectedApp) {
handleClose(); handleClose();
} else { } else {
@@ -29,7 +48,69 @@
} }
$apps.dropdown = false; $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(() => { 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) { hotkeys('A+1,A+2,A+3,A+4', function (event, handler) {
event.preventDefault(); event.preventDefault();
switch (handler.key) { 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> </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={`apps`}>
<div class="lg:hidden"> <div class="lg:hidden">
<IconButton <IconButton
@@ -103,7 +197,12 @@
</div> </div>
{#if !!selectedApp} {#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} {#if selectedApp === APPS_CONSTANTS.APPS.QANDA}
<QandA {handleClose} /> <QandA {handleClose} />
{:else if selectedApp === APPS_CONSTANTS.APPS.LIVE_CHAT} {:else if selectedApp === APPS_CONSTANTS.APPS.LIVE_CHAT}
@@ -138,8 +237,25 @@
} }
& .app { & .app {
width: 400px; width: 100%;
transition: all 1s ease-out; 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; position: relative;
overflow: auto; overflow: auto;
} }
@@ -187,8 +303,7 @@
} }
& .app { & .app {
width: 400px; width: 100%;
transition: all 1s ease-out;
position: relative; position: relative;
overflow: auto; overflow: auto;
} }
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { page } from '$app/stores'; import { page } from '$app/stores';
import hotkeys from 'hotkeys-js'; import hotkeys from 'hotkeys-js';
@@ -13,7 +13,7 @@
import { course } from '$lib/components/Course/store'; import { course } from '$lib/components/Course/store';
import { NavClasses } from '$lib/utils/constants/reusableClass'; import { NavClasses } from '$lib/utils/constants/reusableClass';
import { isMobile } from '$lib/utils/store/useMobile'; 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 { profile } from '$lib/utils/store/user';
import { getIsLessonComplete } from '../Lesson/functions'; import { getIsLessonComplete } from '../Lesson/functions';
@@ -29,7 +29,15 @@
} }
let show: boolean = false; 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 = () => { const toggleSidebar = () => {
$menu.hidden = !$menu.hidden; $menu.hidden = !$menu.hidden;
@@ -49,7 +57,75 @@
else show = true; 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(() => { onMount(() => {
if (ResizableSidebar) {
sidebarRef.addEventListener('mousedown', startDragging);
document.addEventListener('mousemove', dragSidebar);
document.addEventListener('mouseup', stopDragging);
document.addEventListener('mousemove', handleCursor);
}
if (browser) { if (browser) {
if (localStorage.getItem('hideCourseNav')) { if (localStorage.getItem('hideCourseNav')) {
show = localStorage.getItem('hideCourseNav') === 'false'; 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); $: handleMobileChange($isMobile);
$: { $: {
@@ -142,6 +227,7 @@
} }
]; ];
} }
$: ResizableSidebar;
</script> </script>
<aside <aside
@@ -149,10 +235,18 @@
$menu.hidden $menu.hidden
? '-translate-x-[100%] absolute md:translate-x-0 md:relative z-[40]' ? '-translate-x-[100%] absolute md:translate-x-0 md:relative z-[40]'
: 'translate-x-0 absolute 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"> <div class="sidebar-contenth-full flex flex-col">
<ul class="my-5"> <ul
class="sidebar-content my-5"
style={$sideBar.open && 'width:0' ? 'display:block' : ''}
bind:this={menuContentRef}
>
{#each navItems as navItem} {#each navItems as navItem}
{#if !navItem.show || (typeof navItem.show === 'function' && navItem.show())} {#if !navItem.show || (typeof navItem.show === 'function' && navItem.show())}
<NavExpandable <NavExpandable
+11 -1
View File
@@ -12,7 +12,7 @@
import { currentOrgPath } from '$lib/utils/store/org'; import { currentOrgPath } from '$lib/utils/store/org';
import { toggleBodyByMode } from '$lib/utils/functions/app'; import { toggleBodyByMode } from '$lib/utils/functions/app';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { menu } from '../Org/store'; import { menu, sideBar } from '../Org/store';
export let title = ''; export let title = '';
export let navClass = ''; export let navClass = '';
@@ -22,6 +22,10 @@
$menu.hidden = !$menu.hidden; $menu.hidden = !$menu.hidden;
}; };
const openSidebar = () => {
$sideBar.open = !$sideBar.open;
};
function toggleDarkMode() { function toggleDarkMode() {
$appStore.isDark = !$appStore.isDark; $appStore.isDark = !$appStore.isDark;
@@ -50,6 +54,12 @@
</IconButton> </IconButton>
</li> </li>
<li class="hidden md:block">
<IconButton onClick={openSidebar}>
<Menu size={16} class=" text-white" />
</IconButton>
</li>
{#if isCoursePage} {#if isCoursePage}
<div class="hidden md:block"> <div class="hidden md:block">
<IconButton <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({ export const newOrgModal = writable({
open: false open: false
}); });
export const sideBar = writable({
open: true
});