diff --git a/common/user-behaviors.js b/common/user-behaviors.js
index 99aa6d6c..84871cf4 100644
--- a/common/user-behaviors.js
+++ b/common/user-behaviors.js
@@ -69,11 +69,6 @@ export const signOut = async ({ viewer }) => {
// NOTE(jim): Permanently deletes you, forever.
export const deleteMe = async ({ viewer }) => {
- const message = "Do you really want to delete your account? It will be permanently removed";
- if (!window.confirm(message)) {
- return false;
- }
-
await Actions.updateSearch("delete-user");
let response = await Actions.deleteViewer();
diff --git a/components/core/ApplicationLayout.js b/components/core/ApplicationLayout.js
index bc6b69fc..ca5746f5 100644
--- a/components/core/ApplicationLayout.js
+++ b/components/core/ApplicationLayout.js
@@ -51,13 +51,11 @@ const STYLES_CONTENT = css`
}
`;
-const STYLES_SIDEBAR = css`
- z-index: ${Constants.zindex.sidebar};
+const STYLES_SIDEBAR_ELEMENTS = css`
height: 100vh;
width: ${Constants.sizes.sidebar}px;
padding: 0;
flex-shrink: 0;
- position: fixed;
background-color: rgba(195, 195, 196, 1);
top: 0;
right: 0;
@@ -66,12 +64,20 @@ const STYLES_SIDEBAR = css`
@media (max-width: ${Constants.sizes.mobile}px) {
width: 100%;
}
-
+ /*
@supports ((-webkit-backdrop-filter: blur(25px)) or (backdrop-filter: blur(25px))) {
-webkit-backdrop-filter: blur(25px);
backdrop-filter: blur(25px);
background-color: rgba(195, 195, 196, 0.6);
}
+ */
+`;
+
+const STYLES_SIDEBAR = css`
+ position: fixed;
+ top: 0; right: 0;
+ margin: auto;
+ z-index: ${Constants.zindex.sidebar};
`;
const STYLES_SIDEBAR_HEADER = css`
@@ -202,13 +208,15 @@ export default class ApplicationLayout extends React.Component {
enabled
onOutsideRectEvent={this._handleDismiss}
>
-
{
- this._sidebar = c;
- }}
- >
- {sidebarElements}
+
+
{
+ this._sidebar = c;
+ }}
+ >
+ {sidebarElements}
+
) : null}
diff --git a/components/core/CarouselSidebar.js b/components/core/CarouselSidebar.js
index 3d4f936a..384dd9ad 100644
--- a/components/core/CarouselSidebar.js
+++ b/components/core/CarouselSidebar.js
@@ -21,6 +21,7 @@ import { Tag } from "~/components/system/components/Tag";
import isEqual from "lodash/isEqual";
import cloneDeep from "lodash/cloneDeep";
import ProcessedText from "~/components/core/ProcessedText";
+import { ConfirmationModal } from "~/components/core/ConfirmationModal";
const DEFAULT_BOOK =
"https://slate.textile.io/ipfs/bafkreibk32sw7arspy5kw3p5gkuidfcwjbwqyjdktd5wkqqxahvkm2qlyi";
@@ -38,7 +39,6 @@ const STYLES_NO_VISIBLE_SCROLL = css`
scrollbar-width: none;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
-
::-webkit-scrollbar {
width: 0px;
display: none;
@@ -77,13 +77,11 @@ const STYLES_SIDEBAR = css`
justify-content: space-between;
background-color: rgba(20, 20, 20, 0.8);
${STYLES_NO_VISIBLE_SCROLL}
-
@supports ((-webkit-backdrop-filter: blur(75px)) or (backdrop-filter: blur(75px))) {
-webkit-backdrop-filter: blur(75px);
backdrop-filter: blur(75px);
background-color: rgba(150, 150, 150, 0.2);
}
-
@media (max-width: ${Constants.sizes.mobile}px) {
display: none;
}
@@ -95,7 +93,6 @@ const STYLES_DISMISS_BOX = css`
right: 16px;
color: ${Constants.system.darkGray};
cursor: pointer;
-
:hover {
color: ${Constants.system.white};
}
@@ -123,7 +120,6 @@ const STYLES_META_TITLE = css`
text-decoration: none;
word-break: break-all;
overflow-wrap: anywhere;
-
:hover {
color: ${Constants.system.blue};
}
@@ -173,11 +169,9 @@ const STYLES_ACTION = css`
border-bottom: 1px solid #3c3c3c;
display: flex;
align-items: center;
-
:hover {
color: ${Constants.system.brand};
}
-
:last-child {
border: none;
}
@@ -243,7 +237,6 @@ const STYLES_AUTOSAVE = css`
position: absolute;
top: 24px;
left: 16px;
-
@keyframes slate-animations-autosave {
0% {
opacity: 0;
@@ -300,6 +293,7 @@ class CarouselSidebar extends React.Component {
showSavedMessage: false,
showConnectedSection: false,
showFileSection: true,
+ modalShow: false,
};
componentDidMount = () => {
@@ -449,11 +443,11 @@ class CarouselSidebar extends React.Component {
});
};
- _handleDelete = () => {
+ _handleDelete = (res) => {
if (this.props.external || !this.props.isOwner) return;
- const message =
- "Are you sure you want to delete this? It will be removed from your collections as well";
- if (!window.confirm(message)) {
+
+ if (!res) {
+ this.setState({ modalShow: false });
return;
}
const id = this.props.data.id;
@@ -745,7 +739,7 @@ class CarouselSidebar extends React.Component {
if (editingAllowed) {
actions.push(
-
+
this.setState({ modalShow: true })}>
Delete
@@ -847,70 +841,81 @@ class CarouselSidebar extends React.Component {
}
return (
-
- {this.state.showSavedMessage && (
-
-
- Changes saved
-
+ <>
+ {this.state.modalShow && (
+
)}
-
-
-
-
-
- {elements}
-
- {!this.props.external &&
{actions}
}
- {privacy}
- {uploadCoverImage}
- {!this.props.external && (
- <>
-
this._handleToggleAccordion("showConnectedSection")}
- >
-
-
-
- Add to collection
-
- {this.state.showConnectedSection && (
-
-
-
- )}
- >
+
+ {this.state.showSavedMessage && (
+
+
+ Changes saved
+
)}
+
+
+
- {this.props.data.filename.endsWith(".md") ? (
- <>
-
- Settings
-
-
- >
- ) : null}
+
+ {elements}
+
+ {!this.props.external &&
{actions}
}
+ {privacy}
+ {uploadCoverImage}
+ {!this.props.external && (
+ <>
+
this._handleToggleAccordion("showConnectedSection")}
+ >
+
+
+
+ Add to collection
+
+ {this.state.showConnectedSection && (
+
+
+
+ )}
+ >
+ )}
+
+ {this.props.data.filename.endsWith(".md") ? (
+ <>
+
+ Settings
+
+
+ >
+ ) : null}
+
-
+ >
);
}
}
@@ -932,4 +937,4 @@ export default withTheme(CarouselSidebar);
: "This file is currently not visible to others unless they have the link."}
> */
-}
+}
\ No newline at end of file
diff --git a/components/core/ConfirmationModal.js b/components/core/ConfirmationModal.js
new file mode 100644
index 00000000..b0ffc41e
--- /dev/null
+++ b/components/core/ConfirmationModal.js
@@ -0,0 +1,128 @@
+import * as React from "react";
+import * as Constants from "~/common/constants";
+
+import { css } from "@emotion/react";
+import { useState } from "react";
+
+import { ButtonPrimaryFull, ButtonSecondaryFull, ButtonWarningFull } from "~/components/system/components/Buttons.js";
+import { Input } from "~/components/system/components/Input.js";
+import { Boundary } from "~/components/system/components/fragments/Boundary.js";
+
+const STYLES_TRANSPARENT_BG = css `
+ background-color: ${Constants.system.bgBlurGrayBlack};
+ z-index: ${Constants.zindex.modal};
+ width: 100vw;
+ height: 100vh;
+ position: fixed;
+ left: 0;
+ top: 0;
+`;
+
+const STYLES_MAIN_MODAL = css `
+ background-color: ${Constants.system.white};
+ width: 380px;
+ height: auto;
+ position: fixed;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ border-radius: 8px;
+ padding: 24px;
+ text-align: left;
+`;
+
+const STYLES_HEADER = css `
+ color: ${Constants.system.black};
+ font-size: ${Constants.typescale.lvl1};
+ font-family: ${Constants.font.semiBold};
+`;
+
+const STYLES_SUB_HEADER = css `
+ color: ${Constants.system.textGray};
+ font-size: ${Constants.typescale.lvl0};
+ font-family: ${Constants.font.text};
+ margin-top: 16px;
+`;
+
+const STYLES_INPUT_HEADER = css `
+ color: ${Constants.system.black};
+ font-size: ${Constants.typescale.lvlN1};
+ font-family: ${Constants.font.semiBold};
+ font-weight: bold;
+ margin-top: 24px;
+ margin-bottom: 8px;
+`;
+
+export const ConfirmationModal = (props) => {
+ const [isEnabled, setIsEnabled] = useState(false);
+
+ const lang = {
+ deleteText: 'Delete',
+ confirmText: 'Confirm',
+ cancelText: 'Cancel'
+ }
+
+ const _handleChange = (e) => {
+ if (e.target.value === props.matchValue) {
+ setIsEnabled(true);
+ return;
+ }
+ setIsEnabled(false);
+ }
+
+ let deleteButton =
{props.buttonText || lang.deleteText};
+ if (isEnabled) {
+ deleteButton =
props.callback(true)}>{props.buttonText || lang.deleteText};
+ }
+
+ let confirmButton =
{props.buttonText || lang.confirmText};
+ if (isEnabled) {
+ confirmButton =
props.callback(true)}>{props.buttonText || lang.confirmText};
+ }
+
+ return (
+
+
props.callback(false)}>
+
+
{props.header}
+
{props.subHeader}
+ {props.type === "DELETE" &&
+ <>
+ {props.withValidation ? (
+ <>
+
{props.inputHeader}
+
+
props.callback(false)} style={{margin: '24px 0px 8px'}}>{lang.cancelText}
+ {deleteButton}
+ >
+ ) : (
+ <>
+
props.callback(false)} style={{ margin: '24px 0px 8px' }}>{lang.cancelText}
+
props.callback(true)}>{props.buttonText || lang.deleteText}
+ >
+ )}
+ >
+ }
+
+ {props.type === "CONFIRM" &&
+ <>
+ {props.withValidation ? (
+ <>
+
{props.inputHeader}
+
+
props.callback(false)} style={{ margin: '24px 0px 8px' }}>{lang.cancelText}
+ {confirmButton}
+ >
+ ) : (
+ <>
+
props.callback(false)} style={{ margin: '24px 0px 8px' }}>{lang.cancelText}
+
props.callback(true)}>{props.buttonText || lang.confirmText}
+ >
+ )}
+ >
+ }
+
+
+
+ );
+};
diff --git a/components/core/DataView.js b/components/core/DataView.js
index 117ba1e3..4adbae2f 100644
--- a/components/core/DataView.js
+++ b/components/core/DataView.js
@@ -20,10 +20,10 @@ import { GroupSelectable, Selectable } from "~/components/core/Selectable/";
import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview";
import FilePreviewBubble from "~/components/core/FilePreviewBubble";
import isEqual from "lodash/isEqual";
+import { ConfirmationModal } from "~/components/core/ConfirmationModal";
const STYLES_CONTAINER_HOVER = css`
display: flex;
-
:hover {
color: ${Constants.system.brand};
}
@@ -67,7 +67,6 @@ const STYLES_LINK = css`
text-overflow: ellipsis;
white-space: nowrap;
max-width: 320px;
-
@media (max-width: ${Constants.sizes.tablet}px) {
max-width: 120px;
}
@@ -86,7 +85,6 @@ const STYLES_ICON_BOX_HOVER = css`
align-items: center;
padding: 8px;
cursor: pointer;
-
:hover {
color: ${Constants.system.brand};
}
@@ -117,7 +115,6 @@ const STYLES_ACTION_BAR = css`
width: 90vw;
max-width: 878px;
height: 48px;
-
@media (max-width: ${Constants.sizes.mobile}px) {
display: none;
}
@@ -131,7 +128,6 @@ const STYLES_ACTION_BAR_CONTAINER = css`
display: flex;
justify-content: center;
z-index: ${Constants.zindex.header};
-
@media (max-width: ${Constants.sizes.mobile}px) {
display: none;
}
@@ -153,7 +149,6 @@ const STYLES_LEFT = css`
const STYLES_FILES_SELECTED = css`
font-family: ${Constants.font.semiBold};
color: ${Constants.system.white};
-
@media (max-width: ${Constants.sizes.mobile}px) {
display: none;
}
@@ -171,7 +166,6 @@ const STYLES_IMAGE_GRID = css`
grid-column-gap: 20px;
grid-row-gap: 20px;
width: 100%;
-
@media (max-width: ${Constants.sizes.mobile}px) {
grid-template-columns: repeat(2, 1fr);
}
@@ -185,11 +179,9 @@ const STYLES_IMAGE_BOX = css`
justify-content: center;
cursor: pointer;
position: relative;
-
@media (max-width: ${Constants.sizes.mobile}px) {
margin: 12px auto;
}
-
:hover {
box-shadow: 0px 0px 0px 1px ${Constants.system.lightBorder} inset,
0 0 40px 0 ${Constants.system.shadow};
@@ -223,12 +215,10 @@ const STYLES_TAG = css`
font-family: ${Constants.font.text};
padding: 2px 8px;
margin: 8px 8px 0 0;
-
span {
line-height: 1.5;
font-size: 14px;
}
-
&:hover {
background: ${Constants.system.gray30};
}
@@ -307,6 +297,7 @@ export default class DataView extends React.Component {
viewLimit: 40,
scrollDebounce: false,
imageSize: 100,
+ modalShow: false,
};
isShiftDown = false;
@@ -474,9 +465,9 @@ export default class DataView extends React.Component {
this.setState({ checked: {} });
};
- _handleDelete = (id) => {
- const message = `Are you sure you want to delete these files? They will be deleted from your collections as well`;
- if (!window.confirm(message)) {
+ _handleDelete = (res, id) => {
+ if (!res) {
+ this.setState({ modalShow: false });
return;
}
@@ -495,7 +486,7 @@ export default class DataView extends React.Component {
this.props.onUpdateViewer({ library });
UserBehaviors.deleteFiles(ids);
- this.setState({ checked: {} });
+ this.setState({ checked: {}, modalShow: false });
};
_handleSelect = (index) => {
@@ -600,7 +591,6 @@ export default class DataView extends React.Component {
return commonTags;
};
-
render() {
let numChecked = Object.keys(this.state.checked).length || 0;
// const header = (
@@ -637,6 +627,7 @@ export default class DataView extends React.Component {
//
//
// );
+
const footer = (
{numChecked ? (
@@ -684,11 +675,20 @@ export default class DataView extends React.Component {
this._handleDelete()}
+ onClick={() => this.setState({ modalShow: true })}
>
{Strings.pluralize("Delete file", numChecked)}
)}
+ {this.state.modalShow && (
+
+ )}
{
@@ -969,7 +969,7 @@ export default class DataView extends React.Component {
text: "Delete",
onClick: (e) => {
e.stopPropagation();
- this.setState({ menu: null }, () => this._handleDelete(each.id));
+ this.setState({ menu: null, modalShow: true });
},
},
]}
diff --git a/components/core/SlateLayout.js b/components/core/SlateLayout.js
index bb8a1b3d..c4637a42 100644
--- a/components/core/SlateLayout.js
+++ b/components/core/SlateLayout.js
@@ -24,6 +24,7 @@ import {
ButtonWarning,
} from "~/components/system/components/Buttons";
import { GroupSelectable, Selectable } from "~/components/core/Selectable/";
+import { ConfirmationModal } from "~/components/core/ConfirmationModal";
//NOTE(martina): sets 200px as the standard width for a 1080px wide layout with 20px margin btwn images.
//If the container is larger or smaller, it scales accordingly by that factor
@@ -328,6 +329,7 @@ export class SlateLayout extends React.Component {
tooltip: null,
keyboardTooltip: false,
signInModal: false,
+ modalShowDeleteFiles: false,
};
componentDidMount = async () => {
@@ -887,10 +889,9 @@ export class SlateLayout extends React.Component {
this.setState(state);
};
- _handleResetLayout = async () => {
- if (
- !window.confirm("Are you sure you want to reset your layout to the default column layout?")
- ) {
+ _handleResetLayout = async (res) => {
+ if (!res) {
+ this.setState({ modalShowResetLayout: false });
return;
}
let prevLayout = this.cloneLayout(this.state.layout);
@@ -907,6 +908,7 @@ export class SlateLayout extends React.Component {
],
layout,
zIndexMax: 1,
+ modalShowResetLayout: false,
});
};
@@ -1049,14 +1051,15 @@ export class SlateLayout extends React.Component {
e.dataTransfer.setData("DownloadURL", `${type}:${title}:${url}`);
};
- _handleDeleteFiles = async (e, i) => {
- const message = `Are you sure you want to delete these files? They will be deleted from your data and collections.`;
- if (!window.confirm(message)) {
+ _handleDeleteModal = () => {
+ this.setState({ modalShowDeleteFiles: true })
+ }
+
+ _handleDeleteFiles = async (res, i) => {
+ if (!res) {
+ this.setState({ modalShowDeleteFiles: false });
return;
}
-
- e.stopPropagation();
- e.preventDefault();
let ids = [];
if (i !== undefined) {
ids = [this.state.items[i].id.replace("data-", "")];
@@ -1078,7 +1081,7 @@ export class SlateLayout extends React.Component {
}
await UserBehaviors.deleteFiles(ids);
- this.setState({ checked: {} });
+ this.setState({ checked: {}, modalShowDeleteFiles: false });
};
_stopProp = (e) => {
@@ -1134,10 +1137,19 @@ export class SlateLayout extends React.Component {
Reset layout
) : (
-
+ { this.setState({ modalShowResetLayout: true }) }} style={{ marginRight: 16 }}>
Reset layout
)}
+ {this.state.modalShowResetLayout && (
+
+ )}
{this.state.prevLayouts.length ? (
Undo
@@ -1453,8 +1465,8 @@ export class SlateLayout extends React.Component {
onMouseLeave={() => this.setState({ tooltip: null })}
onClick={
this.state.items[i].ownerId === this.props.viewer.id
- ? (e) => {
- this._handleDeleteFiles(e, i);
+ ? () => {
+ this.setState({ modalShowDeleteFiles: true })
}
: () => {}
}
@@ -1475,6 +1487,7 @@ export class SlateLayout extends React.Component {
}}
/>
+
) : (
@@ -1674,6 +1687,15 @@ export class SlateLayout extends React.Component {
)}
+ {this.state.modalShowDeleteFiles && (
+
@@ -1710,7 +1732,7 @@ export class SlateLayout extends React.Component {
{Strings.pluralize("Delete file", numChecked)}
diff --git a/components/sidebars/SidebarSingleSlateSettings.js b/components/sidebars/SidebarSingleSlateSettings.js
index 99275e80..91dc98e9 100644
--- a/components/sidebars/SidebarSingleSlateSettings.js
+++ b/components/sidebars/SidebarSingleSlateSettings.js
@@ -10,6 +10,7 @@ import * as UserBehaviors from "~/common/user-behaviors";
import { RadioGroup } from "~/components/system/components/RadioGroup";
import { css } from "@emotion/react";
+import { ConfirmationModal } from "~/components/core/ConfirmationModal";
const SIZE_LIMIT = 1000000;
const DEFAULT_IMAGE =
@@ -52,6 +53,7 @@ export default class SidebarSingleSlateSettings extends React.Component {
name: this.props.data.data.name,
tags: this.props.data.data?.tags || [],
suggestions: this.props.viewer?.tags || [],
+ modalShow: false,
};
componentDidMount = () => {
@@ -107,12 +109,9 @@ export default class SidebarSingleSlateSettings extends React.Component {
});
};
- _handleDelete = async (e) => {
- if (
- !window.confirm(
- "Are you sure you want to delete this Collection? This action is irreversible."
- )
- ) {
+ _handleDelete = async (res) => {
+ if (!res) {
+ this.setState({ modalShow: false })
return;
}
@@ -130,6 +129,8 @@ export default class SidebarSingleSlateSettings extends React.Component {
if (Events.hasError(response)) {
return;
}
+
+ this.setState({ modalShow: false })
};
render() {
@@ -303,11 +304,20 @@ export default class SidebarSingleSlateSettings extends React.Component {
-
+ this.setState({ modalShow: true })} style={{ overflow: "hidden" }}>
Delete collection
+ {this.state.modalShow && (
+
+ )}
);
}
diff --git a/components/system/components/Buttons.js b/components/system/components/Buttons.js
index f5d97347..ff92f992 100644
--- a/components/system/components/Buttons.js
+++ b/components/system/components/Buttons.js
@@ -39,6 +39,13 @@ const STYLES_BUTTON_PRIMARY = css`
}
`;
+const STYLES_BUTTON_PRIMARY_DISABLED = css`
+ ${STYLES_BUTTON}
+ cursor: not-allowed;
+ background-color: ${Constants.system.bgBlue};
+ color: ${Constants.system.white};
+`;
+
const STYLES_BUTTON_PRIMARY_TRANSPARENT = css`
${STYLES_BUTTON}
cursor: pointer;
@@ -71,6 +78,17 @@ export const ButtonPrimary = (props) => {
);
}
+ if (props.disabled) {
+ return (
+
+ );
+ }
+
return (