diff --git a/src/components/Canvas/hooks.js b/src/components/Canvas/hooks.js
index 8fb6056..bc3a8f1 100644
--- a/src/components/Canvas/hooks.js
+++ b/src/components/Canvas/hooks.js
@@ -6,7 +6,8 @@ import * as actions from '../../store/actionIndex';
import * as fireactions from '../../store/firestoreIndex';
import { manageUser } from "../../store/firestoreAPI/authTransactions";
-import { GRID } from '../../shared/constants/grid';
+import { GRID } from '../../shared/constants';
+import { ANIMATION } from '../Card/hooks';
// TODO separate out the network code into functions data/request or something
// link the authlistener and app status management to App.js
@@ -173,7 +174,7 @@ export const useCanvasHooks = () => {
} else {
setCardAnimation({
...cardAnimation,
- [droppedCard]: 'card-blink .25s step-end 3 alternate',
+ [droppedCard]: ANIMATION.cardBlink,
});
}
}
diff --git a/src/components/Canvas/index.jsx b/src/components/Canvas/index.jsx
index ec30538..629ae82 100644
--- a/src/components/Canvas/index.jsx
+++ b/src/components/Canvas/index.jsx
@@ -2,9 +2,9 @@ import React from 'react';
import { Rnd } from 'react-rnd';
import { CANVAS_STATES, CANVAS_DIMENSIONS, useCanvasHooks } from './hooks';
-import Card from '../Card';
+import Card from '../Card/Card';
-import { GRID } from '../../shared/constants/grid';
+import { GRID } from '../../shared/constants';
import './index.scss';
import LibraryIcon from '../../assets/icons/library.svg';
import PlusIcon from '../../assets/icons/plus.svg'
diff --git a/src/components/Card/index.jsx b/src/components/Card/Card.jsx
similarity index 86%
rename from src/components/Card/index.jsx
rename to src/components/Card/Card.jsx
index 89d171d..c546b40 100644
--- a/src/components/Card/index.jsx
+++ b/src/components/Card/Card.jsx
@@ -6,8 +6,8 @@ import { useCardHooks } from './hooks';
import Title from './Title';
import Content from './Content';
-import './index.scss';
-import { GRID } from '../../shared/constants/grid';
+import './Card.scss';
+import { GRID } from '../../shared/constants';
export const Card = ({
cardId,
@@ -23,8 +23,8 @@ export const Card = ({
position,
rndStyle,
animationStyle,
- editingCard,
- setEditingCard,
+ isEditing,
+ setIsEditing,
onDragStart,
onDragStop,
onResizeStop,
@@ -43,7 +43,7 @@ export const Card = ({
// position
position={position}
// drag
- disableDragging={editingCard}
+ disableDragging={isEditing}
dragHandleClassName="input-div"
// dragGrid={[GRID.size, GRID.size]}
onDragStart={onDragStart}
@@ -72,11 +72,11 @@ export const Card = ({
>
diff --git a/src/components/Card/index.scss b/src/components/Card/Card.scss
similarity index 100%
rename from src/components/Card/index.scss
rename to src/components/Card/Card.scss
diff --git a/src/components/Card/Content.jsx b/src/components/Card/Content.jsx
index 5baedda..59ea3a4 100644
--- a/src/components/Card/Content.jsx
+++ b/src/components/Card/Content.jsx
@@ -2,7 +2,7 @@ import React from 'react';
import { useContentHooks } from './hooks';
-import './index.scss';
+import './Card.scss';
const Content = ({
cardId,
@@ -38,4 +38,4 @@ const Content = ({
);
};
-export default Content;
\ No newline at end of file
+export default Content;
diff --git a/src/components/Card/LibraryCard.jsx b/src/components/Card/LibraryCard.jsx
new file mode 100644
index 0000000..e7845cb
--- /dev/null
+++ b/src/components/Card/LibraryCard.jsx
@@ -0,0 +1,52 @@
+import React from 'react';
+
+import { useLibraryCardHooks } from './hooks';
+
+import Title from './Title';
+import LibraryContent from './LibraryContent';
+
+import './LibraryCard.scss';
+
+const LibraryCard = ({ cardId }) => {
+ const {
+ libraryCardRef,
+ isActive,
+ isSelected,
+ isEditing,
+ cardAnimation,
+ setIsEditing,
+ onDragStart,
+ onDragEnd,
+ onAnimationEnd,
+ onClick,
+ } = useLibraryCardHooks({
+ cardId
+ });
+
+ return (
+
+ {/*
*/}
+
+
+ {/* */}
+
+ );
+};
+
+export default LibraryCard;
diff --git a/src/components/Library/LibrarySearch/LibraryCard/LibraryCard.scss b/src/components/Card/LibraryCard.scss
similarity index 59%
rename from src/components/Library/LibrarySearch/LibraryCard/LibraryCard.scss
rename to src/components/Card/LibraryCard.scss
index f07303b..4a54d95 100644
--- a/src/components/Library/LibrarySearch/LibraryCard/LibraryCard.scss
+++ b/src/components/Card/LibraryCard.scss
@@ -1,5 +1,4 @@
-// card config
-$title-bar-height: 2rem;
+// config
$round-radius: 12px;
.library-card {
@@ -9,73 +8,39 @@ $round-radius: 12px;
height: auto;
border-radius: $round-radius;
box-shadow: 2px 8px 3px #d7d6d6;
-
- .library-border {
- border-radius: $round-radius;
- box-shadow: 0 0 0 2px #f4f4f4;
- }
-
- &:hover .library-border {
- box-shadow: 0 0 0 3px #c1e9ff;
- }
-
- .color-select {
- position: absolute;
- right: -1px;
- top: 32px;
- border-top: 1px solid black;
- border-right: 1px solid black;
- z-index: 100;
-
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- grid-template-rows: repeat(3, 1fr);
-
- button {
- grid-column: span 1;
- grid-row: span 1;
- width: 31px;
- height: 31px;
- border: 0;
- border-left: 1px solid black;
- border-bottom: 1px solid black;
- outline: none;
- }
- }
}
+.active-card { box-shadow: 0 0 0 6px #DBE2EB, 2px 2px 8px -3px #D7D6D6; }
+.inactive-card { box-shadow: 0 0 0 1px #F0F0F0, 2px 2px 8px -3px #D7D6D6; }
+.library-card:hover { box-shadow: 0 0 0 6px #DBE2EB, 2px 2px 8px -3px #D7D6D6; }
+@keyframes library-card-blink { 50% { box-shadow: 0 0 0 6px #5BC5FF, 2px 2px 8px -3px #D7D6D6; } }
.library-card-content-container {
+ border-radius: 0 0 $round-radius $round-radius;
position: relative;
-
-webkit-transition: 0.4s;
transition: 0.4s;
display: flex;
flex-flow: column nowrap;
- textarea {
- cursor: auto;
- }
.library-card-textarea {
display: block; /* Fallback for non-webkit */
display: -webkit-box;
-
max-width: 100%;
margin: 0 auto;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
-
margin: 0;
padding: 15px 8px 15px 15px;
border: 0;
border-radius: $round-radius;
resize: none;
-
background-color: white;
-
font-family: "Roboto";
+ cursor: auto;
+
&::-webkit-scrollbar {
width: 19px;
}
@@ -96,11 +61,3 @@ $round-radius: 12px;
-webkit-line-clamp: inherit;
}
}
-
-@keyframes library-card-blink {
- 50% {
- border: 3px solid red;
- margin: 0px;
- margin-bottom: 8px;
- }
-}
diff --git a/src/components/Card/LibraryContent.jsx b/src/components/Card/LibraryContent.jsx
new file mode 100644
index 0000000..272bd59
--- /dev/null
+++ b/src/components/Card/LibraryContent.jsx
@@ -0,0 +1,57 @@
+import React from 'react';
+
+import { useContentHooks } from './hooks';
+
+import './LibraryCard.scss';
+
+const LibraryContent = ({
+ cardId,
+ isSelected,
+ setEditingCard,
+}) => {
+ const {
+ readOnly,
+ contentRef,
+ contentValue,
+ changeContentValue,
+ beginContentEdit,
+ endContentEdit,
+ } = useContentHooks({
+ cardId,
+ setEditingCard,
+ });
+
+ const condensedStyle = {
+ minHeight: '60px',
+ maxHeight: '80px',
+ height: '80px',
+ };
+
+ const expandedStyle = {
+ minHeight: '80px',
+ maxHeight: '50vh',
+ height: '35vh',
+ };
+
+ return (
+
+
+ );
+};
+
+export default LibraryContent;
diff --git a/src/components/Card/Title.jsx b/src/components/Card/Title.jsx
index d425612..422ba36 100644
--- a/src/components/Card/Title.jsx
+++ b/src/components/Card/Title.jsx
@@ -5,7 +5,7 @@ import { useTitleHooks, useColorDropdownHooks, useOptionsDropdownHooks } from '.
import ColorDropdown from '../../components-shared/Dropdowns/ColorDropdown';
import ActionDropdown from '../../components-shared/Dropdowns/ActionDropdown';
-import './index.scss';
+import './Card.scss';
import '../../styles/colors.scss';
import OpenColorBlackIcon from '../../assets/icons/rounded-square.svg';
import OpenColorWhiteIcon from '../../assets/icons/rounded-square-white.svg';
diff --git a/src/components/Card/hooks.js b/src/components/Card/hooks.js
index fb4da5d..604133d 100644
--- a/src/components/Card/hooks.js
+++ b/src/components/Card/hooks.js
@@ -10,6 +10,11 @@ import { ACTION_TYPE } from '../../components-shared/Dropdowns/ActionDropdown';
import LibraryIcon from '../../assets/icons/library-icon.png';
import RedTrashIcon from '../../assets/icons/red-trash.png';
+export const ANIMATION = {
+ cardBlink: 'card-blink .25s step-end 3 alternate',
+ libraryCardBlink: 'library-card-blink .25s step-end 3 alternate',
+};
+
export const useCardHooks = ({
cardId,
toolMenuRef,
@@ -26,7 +31,7 @@ export const useCardHooks = ({
const [isDragging, setIsDragging] = useState(false);
const [isSelected, setIsSelected] = useState(false);
- const [editingCard, setEditingCard] = useState(false);
+ const [isEditing, setIsEditing] = useState(false);
const cardRef = useRef();
@@ -54,8 +59,8 @@ export const useCardHooks = ({
position: cardPosition,
rndStyle: { zIndex },
animationStyle: { animation: cardAnimation ? cardAnimation[cardId] : null },
- editingCard,
- setEditingCard,
+ isEditing,
+ setIsEditing,
onDragStart: () => setIsDragging(true),
onDragStop: (event, data) => {
setIsDragging(false);
@@ -81,11 +86,62 @@ export const useCardHooks = ({
setIsSelected(true);
}
},
- onAnimationEnd: () => {
- setCardAnimation({
- ...cardAnimation,
- [cardId]: null,
- })
+ onAnimationEnd: () => setCardAnimation({
+ ...cardAnimation,
+ [cardId]: null,
+ }),
+ };
+};
+
+export const useLibraryCardHooks = ({
+ cardId,
+}) => {
+ const dispatch = useDispatch();
+
+ const activeCard = useSelector(state => state.sessionManager.activeCardId);
+ const activeTab = useSelector(state => state.campaignData.present.activeViewId);
+ const cardTabs = useSelector(state => state.campaignData.present.cards[cardId].views);
+
+ const [isSelected, setIsSelected] = useState(false);
+ const [isEditing, setIsEditing] = useState(false);
+ const [cardAnimation, setCardAnimation] = useState({});
+
+ const libraryCardRef = useRef();
+
+ const isActive = cardId === activeCard;
+
+ useOutsideClick([libraryCardRef], isSelected,
+ () => {
+ if (isActive) dispatch(actions.updActiveCardId(null));
+ setIsSelected(false);
+ }
+ );
+
+ return {
+ libraryCardRef,
+ isActive,
+ isSelected,
+ isEditing,
+ cardAnimation: { animation: cardAnimation[cardId] },
+ setIsEditing,
+ onDragStart: (event) => event.dataTransfer.setData('text', cardId),
+ onDragEnd: () => {
+ if (cardTabs[activeTab]) {
+ setCardAnimation({
+ ...cardAnimation,
+ [cardId]: ANIMATION.libraryCardBlink,
+ });
+ }
+ },
+ onAnimationEnd: () => setCardAnimation({
+ ...cardAnimation,
+ [cardId]: null,
+ }),
+ onClick: () => {
+ if (!isSelected) {
+ if (cardId !== activeCard) dispatch(actions.updActiveCardId(cardId));
+ setIsSelected(true);
+ }
},
};
};
diff --git a/src/components/Library/Library.jsx b/src/components/Library/Library.jsx
index e80b608..343f841 100644
--- a/src/components/Library/Library.jsx
+++ b/src/components/Library/Library.jsx
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import './Library.scss';
-import LibrarySearch from './LibrarySearch/LibrarySearch';
+import LibrarySearch from './LibrarySearch';
import LibBtnImg from '../../assets/icons/library.png';
import ExpandImg from '../../assets/icons/left-arrow-32.png';
diff --git a/src/components/Library/LibrarySearch/LibrarySearch.jsx b/src/components/Library/LibrarySearch.jsx
similarity index 96%
rename from src/components/Library/LibrarySearch/LibrarySearch.jsx
rename to src/components/Library/LibrarySearch.jsx
index 645bfd6..b36acf8 100644
--- a/src/components/Library/LibrarySearch/LibrarySearch.jsx
+++ b/src/components/Library/LibrarySearch.jsx
@@ -2,9 +2,9 @@ import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import './LibrarySearch.scss';
-import LibraryCard from './LibraryCard/LibraryCard';
+import LibraryCard from '../Card/LibraryCard';
-import SearchImg from '../../../assets/icons/search2.png';
+import SearchImg from '../../assets/icons/search2.png';
const LibrarySearch = props => {
// STATES
diff --git a/src/components/Library/LibrarySearch/LibrarySearch.scss b/src/components/Library/LibrarySearch.scss
similarity index 96%
rename from src/components/Library/LibrarySearch/LibrarySearch.scss
rename to src/components/Library/LibrarySearch.scss
index e529ace..56a4f0e 100644
--- a/src/components/Library/LibrarySearch/LibrarySearch.scss
+++ b/src/components/Library/LibrarySearch.scss
@@ -54,7 +54,7 @@ $horizontal-divide: 0.4rem;
.library-search-results-container {
flex: 1 1 auto;
- padding: 0.2rem 0.6rem 0.2rem 0.2rem;
+ padding: 10px 5px;
align-items: center;
text-align: center;
@@ -64,4 +64,5 @@ $horizontal-divide: 0.4rem;
display: flex;
flex-flow: column nowrap;
+ gap: 20px;
}
\ No newline at end of file
diff --git a/src/components/Library/LibrarySearch/LibraryCard/LibraryCard.jsx b/src/components/Library/LibrarySearch/LibraryCard/LibraryCard.jsx
deleted file mode 100644
index d1381cb..0000000
--- a/src/components/Library/LibrarySearch/LibraryCard/LibraryCard.jsx
+++ /dev/null
@@ -1,146 +0,0 @@
-import React, { useState, useRef } from "react";
-import { useDispatch, useSelector } from "react-redux";
-import { useOutsideClick } from "../../../../utils/useOutsideClick";
-
-import "./LibraryCard.scss";
-import * as actions from "../../../../store/actionIndex";
-import { CARD_FONT_SIZE } from "../../../../shared/constants/fontSize";
-import { CARD_TITLEBAR_COLORS } from "../../../../shared/constants/colors";
-import TitleInput from "../../../UI/Inputs/TitleInput";
-import Title from "../../../Card/Title";
-import ContentTextarea from "../../../UI/Inputs/ContentTextarea";
-
-import DeleteImg from "../../../../assets/icons/delete-24.png";
-
-const LibraryCard = (props) => {
- const { cardId } = props;
- const dispatch = useDispatch();
-
- // STATES
- const [isSelected, setIsSelected] = useState(false);
- const [openColorSelect, setOpenColorSelect] = useState(false);
- const [confirmDelete, setConfirmDelete] = useState(false);
- const [editingCard, setEditingCard] = useState(false);
- const [cardAnimation, setCardAnimation] = useState({});
-
- // STORE SELECTORS
- const activeCardId = useSelector(
- (state) => state.sessionManager.activeCardId
- );
- const activeViewId = useSelector(
- (state) => state.campaignData.present.activeViewId
- );
- const cardViews = useSelector(
- (state) => state.campaignData.present.cards[cardId].views
- );
- const cardColor = useSelector(
- (state) => state.campaignData.present.cards[cardId].color
- );
- const cardTitle = useSelector(
- (state) => state.campaignData.present.cards[cardId].title
- );
- const cardText = useSelector(
- (state) => state.campaignData.present.cards[cardId].content.text
- );
-
- // REFS
- const libraryCardRef = useRef();
- const colorSelectRef = useRef();
- const colorBtnRef = useRef();
- const deleteBtnRef = useRef();
-
- // FUNCTIONS: CARD
- const cardDragStartHandler = (event) =>
- event.dataTransfer.setData("text", cardId);
- const cardDragEndHandler = () => {
- if (cardViews[activeViewId]) {
- setCardAnimation({
- ...cardAnimation,
- [cardId]: "library-card-blink .25s step-end 3 alternate",
- });
- }
- };
-
- const onAnimationEnd = () => {
- setCardAnimation({
- ...cardAnimation,
- [cardId]: null,
- });
- };
-
- const cardClickHandler = () => {
- if (!isSelected) {
- if (cardId !== activeCardId) dispatch(actions.updActiveCardId(cardId));
- setIsSelected(true);
- }
- };
-
- useOutsideClick([libraryCardRef], isSelected, () => {
- if (cardId === activeCardId) dispatch(actions.updActiveCardId(null));
- setIsSelected(false);
- });
-
- // FUNCTIONS: TITLEBAR
- useOutsideClick([colorSelectRef, colorBtnRef], openColorSelect, () =>
- setOpenColorSelect(false)
- );
-
- useOutsideClick([deleteBtnRef], confirmDelete, () => setConfirmDelete(false));
-
- const deleteCard = () => {
- if (!confirmDelete) setConfirmDelete(true);
- else dispatch(actions.destroyCard(cardId));
- };
-
- // STYLES: CARD
- const cardStyle = {
- margin: cardId === activeCardId ? "0px 0px 8px 0px" : "2px 2px 10px 2px",
- zIndex: cardId === activeCardId ? "100" : "0",
- animation: cardAnimation ? cardAnimation[cardId] : null,
- };
-
- // STYLES: CONTENT
- const contentContainerStyle = {
- minHeight: isSelected
- ? 6 * CARD_FONT_SIZE.text + "px"
- : 3 * CARD_FONT_SIZE.text + "px",
- maxHeight: isSelected ? "50vh" : 5 * CARD_FONT_SIZE.text + "px",
- height: isSelected ? "35vh" : 5 * CARD_FONT_SIZE.text + "px",
- };
-
- return (
-
-
-
- {/* content */}
-
- dispatch(actions.updCardText(cardId, v))}
- setEditingParent={setEditingCard}
- />
-
-
-
- );
-};
-
-export default LibraryCard;
diff --git a/src/components/UI/Backdrop/Backdrop.jsx b/src/components/UI/Backdrop/Backdrop.jsx
deleted file mode 100644
index 3aa415d..0000000
--- a/src/components/UI/Backdrop/Backdrop.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-
-import './Backdrop.scss';
-
-// TODO delete
-
-const backdrop = (props) => (
- props.show
- ?
- : null
-);
-
-export default backdrop;
\ No newline at end of file
diff --git a/src/components/UI/Backdrop/Backdrop.scss b/src/components/UI/Backdrop/Backdrop.scss
deleted file mode 100644
index b534936..0000000
--- a/src/components/UI/Backdrop/Backdrop.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-.backdrop {
- position: fixed;
- left: 0; top: 0;
- width: 100vw; height: 100vh;
- z-index: 500;
- background-color: rgba(0,0,0,0.5);
-}
\ No newline at end of file
diff --git a/src/components/UI/Inputs/ContentTextarea.jsx b/src/components/UI/Inputs/ContentTextarea.jsx
deleted file mode 100644
index 822c729..0000000
--- a/src/components/UI/Inputs/ContentTextarea.jsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import React, { useState, useEffect } from "react";
-
-import { CARD_FONT_SIZE } from "../../../shared/constants/fontSize";
-
-// TODO delete/change
-// Creates a title text with an edit button
-// css is fully controlled by props
-
-const ContentTextarea = ({
- className,
- styles,
- value,
- saveValue,
- setEditingParent,
-}) => {
- const [textareaValue, setTextareaValue] = useState("");
- const [editing, setEditing] = useState(false);
-
- useEffect(() => {
- setTextareaValue(value);
- }, [setTextareaValue, value]);
-
- const beginEdit = (event) => {
- if (!editing) {
- setEditing(true);
- if (setEditingParent) {
- setEditingParent(true);
- }
- }
- };
-
- const endEdit = (event) => {
- if (editing) {
- document.getSelection().removeAllRanges();
- if (textareaValue !== value) {
- saveValue(textareaValue);
- }
- setEditing(false);
- if (setEditingParent) {
- setEditingParent(false);
- }
- }
- };
-
- const keyPressHandler = (event) => {
- if (editing) {
- if (event.key === "Tab") {
- event.preventDefault();
- // TODO make tab indent. need to set cursor position after value state update
- // const { selectionStart, selectionEnd } = event.target;
- // const val = event.target.value;
- // const newValue = val.substring(0, selectionStart) + '\t' + val.substring(selectionEnd);
- // event.target.setSelectionRange(0,0);
- // setTextareaValue(newValue);
- }
- }
- };
-
- return (
-