Skip to content

Commit

Permalink
AI Assistant
Browse files Browse the repository at this point in the history
  • Loading branch information
GrabowskiM committed Oct 30, 2024
1 parent a6b17a7 commit 12cf228
Show file tree
Hide file tree
Showing 7 changed files with 414 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as middleEllipsis from './middle.ellipsis';
import * as notification from './notification.helper';
import * as objectInstances from './object.instances';
import * as pagination from './pagination.helper';
import * as react from './react.helper';
import * as request from './request.helper';
import * as system from './system.helper';
import * as table from './table.helper';
Expand All @@ -34,6 +35,7 @@ import * as user from './user.helper';
ibexa.addConfig('helpers.notification', notification);
ibexa.addConfig('helpers.objectInstances', objectInstances);
ibexa.addConfig('helpers.pagination', pagination);
ibexa.addConfig('helpers.react', react);
ibexa.addConfig('helpers.request', request);
ibexa.addConfig('helpers.system', system);
ibexa.addConfig('helpers.table', table);
Expand Down
21 changes: 21 additions & 0 deletions src/bundle/Resources/public/js/scripts/helpers/react.helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const createDynamicRoot = (contextDOMElement = window.document.body, id) => {
const rootDOMElement = document.createElement('div');

rootDOMElement.classList.add('ibexa-react-root');

if (id) {
rootDOMElement.id = id;
}

contextDOMElement.appendChild(rootDOMElement);

const reactRoot = window.ReactDOM.createRoot(rootDOMElement);

return { reactRoot, rootDOMElement };
};

const removeDynamicRoot = (rootDOMElement) => {
rootDOMElement.remove();
};

export { createDynamicRoot, removeDynamicRoot };
2 changes: 2 additions & 0 deletions src/bundle/Resources/public/scss/ui/modules/_common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
@import 'common/user.name';
@import 'common/taggify';
@import 'common/spinner';
@import 'common/draggable.dialog';
@import 'common/popup.menu';
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.c-draggable-dialog {
position: fixed;
z-index: 10000;

&__draggable {
cursor: grab;
user-select: none;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
.c-popup-menu {
display: none;
flex-direction: column;
gap: calculateRem(1px);
padding: calculateRem(8px) 0;
background: $ibexa-color-white;
border: calculateRem(1px) solid $ibexa-color-light;
border-radius: $ibexa-border-radius;
box-shadow: calculateRem(4px) calculateRem(22px) calculateRem(67px) 0 rgba($ibexa-color-info, 0.2);
position: fixed;
z-index: 1060;

&--visible {
display: flex;
}

&__search {
margin-bottom: calculateRem(4px);
padding: 0 calculateRem(8px);

&--hidden {
display: none;
}
}

&__search-input {
border-radius: $ibexa-border-radius;
}

&__groups {
max-height: calculateRem(390px);
overflow-y: auto;
}

&__group:not(:last-child) {
&::after {
content: '';
border-top: calculateRem(1px) solid $ibexa-color-light;
display: flex;
width: calc(100% - calculateRem(16px));
margin: calculateRem(1px) calculateRem(8px) 0;
}
}

&__item {
display: flex;
align-items: center;
min-width: calculateRem(150px);
padding: 0 calculateRem(8px);
transition: all $ibexa-admin-transition-duration $ibexa-admin-transition;
}

&__item-content {
position: relative;
display: flex;
align-items: center;
align-items: baseline;
width: 100%;
cursor: pointer;
padding: calculateRem(9px);
color: $ibexa-color-dark;
font-size: calculateRem(14px);
text-align: left;
text-decoration: none;
border: none;
border-radius: $ibexa-border-radius;
transition: all $ibexa-admin-transition-duration $ibexa-admin-transition;

&:hover {
background-color: $ibexa-color-light-300;
color: $ibexa-color-black;
text-decoration: none;
}

&[disabled],
&:disabled,
&--disabled {
pointer-events: none;
cursor: not-allowed;
opacity: 0.2;

&:hover {
background-color: initial;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React, { useRef, createContext, useState, useEffect } from 'react';
import PropTypes from 'prop-types';

import { getRootDOMElement } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
import { createCssClassNames } from '../helpers/css.class.names';

Check failure on line 5 in src/bundle/ui-dev/src/modules/common/draggable-dialog/draggable.dialog.js

View workflow job for this annotation

GitHub Actions / Frontend build test

'createCssClassNames' is defined but never used

export const DraggableContext = createContext();

const DraggableDialog = ({ children, initialCoords }) => {
const rootDOMElement = getRootDOMElement();
const containerRef = useRef();
const dragOffsetPosition = useRef({ x: 0, y: 0 });
const containerSize = useRef({ width: 0, height: 0 });
const [isDragging, setIsDragging] = useState(false);
const [coords, setCoords] = useState(initialCoords);
const containerAttrs = {
ref: containerRef,
className: 'c-draggable-dialog',
style: {
top: coords.y,
left: coords.x,
},
};
const getMousePosition = (event) => ({ x: event.x, y: event.y });
const setContainerCoords = (event) => {
const mouseCoords = getMousePosition(event);
let x = mouseCoords.x - dragOffsetPosition.current.x;
let y = mouseCoords.y - dragOffsetPosition.current.y;
let newDragOffsetX;
let newDragOffsetY;

if (x < 0) {
x = 0;
newDragOffsetX = mouseCoords.x;
} else if (x + containerSize.current.width > window.innerWidth) {
x = window.innerWidth - containerSize.current.width;
newDragOffsetX = mouseCoords.x - x;
}

if (y < 0) {
y = 0;
newDragOffsetY = mouseCoords.y;
} else if (y + containerSize.current.height > window.innerHeight) {
y = window.innerHeight - containerSize.current.height;
newDragOffsetY = mouseCoords.y - y;
}

if (newDragOffsetX) {
dragOffsetPosition.current.x = newDragOffsetX;
}

if (newDragOffsetY) {
dragOffsetPosition.current.y = newDragOffsetY;
}

setCoords({
x,
y,
});
};
const startDragging = (event) => {
const { x: containerX, y: containerY, width, height } = containerRef.current.getBoundingClientRect();
const mouseCoords = getMousePosition(event.nativeEvent);

dragOffsetPosition.current = {
x: mouseCoords.x - containerX,
y: mouseCoords.y - containerY,
};

containerSize.current = {
width,
height,
};

setContainerCoords(event.nativeEvent);

setIsDragging(true);
};
const stopDragging = () => {
setIsDragging(false);
};
const handleDragging = (event) => {
setContainerCoords(event);
};

useEffect(() => {
if (isDragging) {
rootDOMElement.addEventListener('mousemove', handleDragging);
rootDOMElement.addEventListener('mouseup', stopDragging);
}

return () => {
rootDOMElement.removeEventListener('mousemove', handleDragging);
rootDOMElement.removeEventListener('mouseup', stopDragging);
};
}, [isDragging]);

return (
<DraggableContext.Provider
value={{
startDragging,
}}
>
<div {...containerAttrs}>{children}</div>
</DraggableContext.Provider>
);
};

DraggableDialog.propTypes = {
initialCoords: PropTypes.shape({
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
}).isRequired,
children: PropTypes.node,
};

DraggableDialog.defaultProps = {
children: null,
};

export default DraggableDialog;
Loading

0 comments on commit 12cf228

Please sign in to comment.