mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 17:58:55 +00:00
added option for scrolling within modals, applied to login/signup modal, also added onModalOpen/onModalClose events
This commit is contained in:
1 parent
214f15aeb9
commit
400b9856d0
12 files changed
+114
-57
No files matched your search
+5
-3
@@ -19,6 +19,7 @@ export interface ActionButtonProps {
|
||||
toggle: (entityToken: string, entityType: string) => any;
|
||||
toolTipOff?: string;
|
||||
toolTipOn?: string;
|
||||
visible?: boolean;
|
||||
}
|
||||
|
||||
export default function ActionButton({
|
||||
@@ -34,6 +35,7 @@ export default function ActionButton({
|
||||
toggle,
|
||||
toolTipOff,
|
||||
toolTipOn,
|
||||
visible
|
||||
}: ActionButtonProps) {
|
||||
const { events, status } = useAnimationStatus();
|
||||
const onClick = () => {
|
||||
@@ -52,13 +54,13 @@ export default function ActionButton({
|
||||
placement: "bottom",
|
||||
theme: "fakeyou",
|
||||
trigger: "mouseenter",
|
||||
visible,
|
||||
}}
|
||||
>
|
||||
<button
|
||||
{...{
|
||||
className: `fy-action-button ${actionType}-action-button ${
|
||||
isToggled ? "action-button-toggled" : ""
|
||||
}`,
|
||||
className: `fy-action-button ${actionType}-action-button ${isToggled ? "action-button-toggled" : ""
|
||||
}`,
|
||||
disabled: busy,
|
||||
onClick,
|
||||
}}
|
||||
|
||||
+5
-6
@@ -39,11 +39,6 @@
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.fy-modal-body-square {
|
||||
// width: 75vh;
|
||||
// height: 75vh;
|
||||
}
|
||||
|
||||
.fy-modal-body-wide,
|
||||
.fy-modal-body-narrow,
|
||||
.fy-modal-body-small,
|
||||
@@ -83,4 +78,8 @@
|
||||
.fy-modal-no-padding {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.fy-modal-scrollable {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
+8
-6
@@ -3,7 +3,7 @@ import { a, easings, useTransition } from "@react-spring/web";
|
||||
import { ModalWidth } from "hooks";
|
||||
import "./ModalLayer.scss";
|
||||
|
||||
interface Props {
|
||||
interface ModalLayerProps {
|
||||
content?: React.ElementType | null;
|
||||
contentProps?: any;
|
||||
close: () => void;
|
||||
@@ -13,6 +13,7 @@ interface Props {
|
||||
modalOpen: boolean;
|
||||
onModalCloseEnd: (x: any) => void;
|
||||
padding?: boolean;
|
||||
scroll?: boolean;
|
||||
width?: ModalWidth;
|
||||
}
|
||||
|
||||
@@ -25,8 +26,9 @@ export default function ModalLayer({
|
||||
modalOpen,
|
||||
onModalCloseEnd,
|
||||
padding = true,
|
||||
scroll,
|
||||
width = "wide",
|
||||
}: Props) {
|
||||
}: ModalLayerProps) {
|
||||
const mainClassName = "fy-modal-layer";
|
||||
const tintTransition = useTransition(modalOpen, {
|
||||
config: {
|
||||
@@ -39,7 +41,7 @@ export default function ModalLayer({
|
||||
onRest: onModalCloseEnd,
|
||||
});
|
||||
|
||||
if (debug) console.log(`🐛 ModalLayer debug at ${debug}`, modalOpen);
|
||||
if (debug) { console.log(`🐛 ModalLayer debug at ${debug}`, modalOpen); }
|
||||
|
||||
return tintTransition(
|
||||
(tintStyle, modalIsOpen) =>
|
||||
@@ -61,9 +63,9 @@ export default function ModalLayer({
|
||||
>
|
||||
<div
|
||||
{...{
|
||||
className: `fy-modal-body-${width}${
|
||||
padding ? "" : " fy-modal-no-padding"
|
||||
}`,
|
||||
className: `fy-modal-body-${width}${padding ? "" : " fy-modal-no-padding"
|
||||
}${scroll ? " fy-modal-scrollable" : ""
|
||||
}`,
|
||||
}}
|
||||
>
|
||||
{Content && (
|
||||
|
||||
+4
-2
@@ -15,12 +15,13 @@ export interface ModalContextShared {
|
||||
}
|
||||
|
||||
export const ModalContext = createContext<ModalContextShared>({
|
||||
close: () => {},
|
||||
open: () => {},
|
||||
close: () => { },
|
||||
open: () => { },
|
||||
modalOpen: false,
|
||||
modalState: null,
|
||||
});
|
||||
|
||||
|
||||
// how this works
|
||||
//
|
||||
// When modalState is set via open(), modalOpen is set to true to via useEffect
|
||||
@@ -51,6 +52,7 @@ export default function ModalProvider({ children }: ModalProviderProps) {
|
||||
modalOpen,
|
||||
onModalCloseEnd,
|
||||
padding: modalState?.padding,
|
||||
scroll: modalState?.scroll,
|
||||
width: modalState?.width,
|
||||
}}
|
||||
/>
|
||||
|
||||
+12
-4
@@ -13,12 +13,17 @@ export interface AccountModalMessages {
|
||||
signupMessage?: string;
|
||||
}
|
||||
|
||||
export interface AccountModalEvents {
|
||||
onModalClose?: () => void;
|
||||
onModalOpen?: () => void;
|
||||
}
|
||||
|
||||
interface SessionContextType {
|
||||
canAccessStudio: () => boolean;
|
||||
canEditTtsModel: (creatorUserToken: string) => boolean;
|
||||
canEditMediaFile: (creatorUserToken?: string) => boolean;
|
||||
canBanUsers: () => boolean;
|
||||
loggedInOrModal: (acctMsgs: AccountModalMessages) => boolean;
|
||||
loggedInOrModal: (acctMsgs: AccountModalMessages, cfg?: AccountModalEvents) => boolean;
|
||||
loggedIn: boolean;
|
||||
modal: {
|
||||
close: () => void;
|
||||
@@ -61,8 +66,8 @@ export const SessionContext = createContext<SessionContextType>({
|
||||
studioAccessCheck: () => null,
|
||||
styleVideoAccessCheck: () => null,
|
||||
modal: {
|
||||
close: () => {},
|
||||
open: () => {},
|
||||
close: () => { },
|
||||
open: () => { },
|
||||
},
|
||||
userTokenMatch: () => false,
|
||||
sessionWrapper: SessionWrapper.emptySession(),
|
||||
@@ -85,14 +90,16 @@ export default function SessionProvider({
|
||||
const { close, killModal, modalOpen, modalState, onModalCloseEnd, open } =
|
||||
useModalState({});
|
||||
|
||||
const loggedInOrModal = (accountModalMessages: AccountModalMessages) => {
|
||||
const loggedInOrModal = (accountModalMessages: AccountModalMessages, events?: AccountModalEvents) => {
|
||||
if (user) {
|
||||
return true;
|
||||
} else {
|
||||
open({
|
||||
component: AccountModal,
|
||||
scroll: true,
|
||||
width: "small",
|
||||
props: { ...accountModalMessages },
|
||||
...events
|
||||
});
|
||||
return false;
|
||||
}
|
||||
@@ -157,6 +164,7 @@ export default function SessionProvider({
|
||||
lockTint: modalState?.lockTint,
|
||||
modalOpen,
|
||||
onModalCloseEnd,
|
||||
scroll: modalState?.scroll,
|
||||
width: modalState?.width,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -2,7 +2,7 @@ import useAnimationStatus, {
|
||||
AnimationEvents,
|
||||
AnimationStatus,
|
||||
} from "./useAnimationStatus";
|
||||
import useBatchContent from "./useBatchContent";
|
||||
import useBatchContent, { BatchInputProps, MakeBatchPropsParams } from "./useBatchContent";
|
||||
import useBookmarks, { MakeBookmarksProps } from "./useBookmarks";
|
||||
import useChanger from "./useChanger";
|
||||
import useCoverImgUpload from "./useCoverImgUpload";
|
||||
@@ -76,7 +76,9 @@ export {
|
||||
|
||||
export type {
|
||||
AnimationEvents,
|
||||
BatchInputProps,
|
||||
MakeBookmarksProps,
|
||||
MakeBatchPropsParams,
|
||||
MakeRatingsProps,
|
||||
ModalConfig,
|
||||
ModalWidth,
|
||||
|
||||
+14
-11
@@ -2,7 +2,7 @@ import { useState } from "react";
|
||||
import { FetchStatus } from "@storyteller/components/src/api/_common/SharedFetchTypes";
|
||||
import { useSession } from "hooks";
|
||||
|
||||
interface Props {
|
||||
interface UseBatchContentProps {
|
||||
checker: any;
|
||||
debug?: string;
|
||||
fetcher: any;
|
||||
@@ -26,20 +26,18 @@ interface Gather {
|
||||
|
||||
type BatchToggle = (entity_token: string, entity_type: string) => boolean;
|
||||
|
||||
export interface MakePropsParams {
|
||||
export interface MakeBatchPropsParams {
|
||||
entityToken: string;
|
||||
entityType: string;
|
||||
}
|
||||
|
||||
export interface BatchInputProps {
|
||||
busy: boolean;
|
||||
entityToken: string;
|
||||
entityType: string;
|
||||
export interface BatchInputProps extends MakeBatchPropsParams {
|
||||
busy?: boolean;
|
||||
isToggled: boolean;
|
||||
toggle: BatchToggle;
|
||||
}
|
||||
|
||||
export type MakeBatchProps = (x: MakePropsParams) => BatchInputProps;
|
||||
export type MakeBatchProps = (x: MakeBatchPropsParams) => BatchInputProps;
|
||||
|
||||
export default function useBatchContent({
|
||||
checker,
|
||||
@@ -47,15 +45,16 @@ export default function useBatchContent({
|
||||
fetcher,
|
||||
modLibrary = (current: any, res: any, entity_token: string) => current,
|
||||
onPass,
|
||||
onFail = { fetch: () => new Promise(() => {}) },
|
||||
onFail = { fetch: () => new Promise(() => { }) },
|
||||
resultsKey,
|
||||
toggleCheck,
|
||||
}: Props) {
|
||||
}: UseBatchContentProps) {
|
||||
const session = useSession();
|
||||
const [library, librarySet] = useState<Library>({});
|
||||
const [busyList, busyListSet] = useState<Library>({});
|
||||
const [status, statusSet] = useState(FetchStatus.ready);
|
||||
const [tokenType, tokenTypeSet] = useState("");
|
||||
const [modalOpen, modalOpenSet] = useState(false);
|
||||
|
||||
const dlog = (...dbg: any) => (debug ? console.log(...dbg) : {});
|
||||
|
||||
@@ -109,7 +108,10 @@ export default function useBatchContent({
|
||||
});
|
||||
|
||||
const toggle: BatchToggle = (entity_token, entity_type) => {
|
||||
if (session.loggedInOrModal({})) {
|
||||
if (session.loggedInOrModal({}, {
|
||||
onModalClose: () => { modalOpenSet(false); },
|
||||
onModalOpen: () => { modalOpenSet(true); },
|
||||
})) {
|
||||
let inLibrary = library[entity_token];
|
||||
statusSet(FetchStatus.in_progress);
|
||||
busyAdd(entity_token);
|
||||
@@ -150,12 +152,13 @@ export default function useBatchContent({
|
||||
|
||||
const toggled = (entity_token = "") => toggleCheck(library[entity_token]);
|
||||
|
||||
const makeProps = ({ entityToken, entityType }: MakePropsParams) => ({
|
||||
const makeProps = ({ entityToken, entityType }: MakeBatchPropsParams) => ({
|
||||
busy: busyList[entityToken],
|
||||
entityToken,
|
||||
entityType,
|
||||
isToggled: toggled(entityToken),
|
||||
toggle,
|
||||
...modalOpen ? { visible: false } : {}
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -1,2 +0,0 @@
|
||||
export { default } from "./useBatchContent";
|
||||
export type { BatchInputProps, MakeBatchProps, MakePropsParams } from "./useBatchContent";
|
||||
@@ -4,11 +4,11 @@ import { DeleteBookmark } from "@storyteller/components/src/api/bookmarks/Delete
|
||||
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
|
||||
import { faBookmark } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { faBookmark as faBookmarkOutline } from "@fortawesome/pro-regular-svg-icons";
|
||||
|
||||
import useBatchContent, {
|
||||
import {
|
||||
useBatchContent,
|
||||
BatchInputProps,
|
||||
MakePropsParams,
|
||||
} from "hooks/useBatchContent";
|
||||
MakeBatchPropsParams,
|
||||
} from "hooks";
|
||||
|
||||
export interface BookmarksProps extends BatchInputProps {
|
||||
actionType: "bookmark";
|
||||
@@ -18,21 +18,21 @@ export interface BookmarksProps extends BatchInputProps {
|
||||
labelOn: string | number;
|
||||
}
|
||||
|
||||
export type MakeBookmarksProps = (x: MakePropsParams) => BookmarksProps;
|
||||
export type MakeBookmarksProps = (x: MakeBatchPropsParams) => BookmarksProps;
|
||||
|
||||
export default function useBookmarks() {
|
||||
const toggleList =
|
||||
(toBookmark: boolean) =>
|
||||
(res: any, entity_token: string, entity_type: string, lib: any) => {
|
||||
return {
|
||||
...lib,
|
||||
[entity_token]: {
|
||||
entity_type,
|
||||
is_bookmarked: toBookmark,
|
||||
maybe_bookmark_token: toBookmark ? res.user_bookmark_token : null,
|
||||
},
|
||||
(res: any, entity_token: string, entity_type: string, lib: any) => {
|
||||
return {
|
||||
...lib,
|
||||
[entity_token]: {
|
||||
entity_type,
|
||||
is_bookmarked: toBookmark,
|
||||
maybe_bookmark_token: toBookmark ? res.user_bookmark_token : null,
|
||||
},
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
const bookmarks = useBatchContent({
|
||||
debug: "bookmarks",
|
||||
@@ -60,7 +60,7 @@ export default function useBookmarks() {
|
||||
const makeProps: MakeBookmarksProps = ({
|
||||
entityToken,
|
||||
entityType,
|
||||
}: MakePropsParams) => {
|
||||
}: MakeBatchPropsParams) => {
|
||||
return {
|
||||
...bookmarks.makeProps({ entityToken, entityType }),
|
||||
actionType: "bookmark",
|
||||
|
||||
@@ -7,7 +7,10 @@ export interface ModalConfig {
|
||||
component: React.ElementType;
|
||||
lockTint?: boolean;
|
||||
padding?: boolean;
|
||||
onModalClose?: () => void;
|
||||
onModalOpen?: () => void;
|
||||
props?: any;
|
||||
scroll?: boolean;
|
||||
width?: ModalWidth;
|
||||
}
|
||||
|
||||
@@ -28,6 +31,9 @@ export default function useModalState({ debug = "" }) {
|
||||
if (debug) {
|
||||
console.log(`🚪 useModalState open() at ${debug}`, { cfg });
|
||||
}
|
||||
if (cfg.onModalOpen) {
|
||||
cfg.onModalOpen();
|
||||
}
|
||||
modalStateSet(cfg);
|
||||
};
|
||||
|
||||
@@ -35,6 +41,9 @@ export default function useModalState({ debug = "" }) {
|
||||
if (debug) {
|
||||
console.log(`🔥 useModalState close() at ${debug}`);
|
||||
}
|
||||
if (modalState?.onModalClose) {
|
||||
modalState.onModalClose();
|
||||
}
|
||||
killModalSet(true);
|
||||
modalOpenSet(false);
|
||||
};
|
||||
|
||||
@@ -3,10 +3,11 @@ import { SetRating } from "@storyteller/components/src/api/user_ratings/SetRatin
|
||||
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
|
||||
import { faHeart } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { faHeart as faHeartOutline } from "@fortawesome/pro-regular-svg-icons";
|
||||
import useBatchContent, {
|
||||
import {
|
||||
useBatchContent,
|
||||
BatchInputProps,
|
||||
MakePropsParams,
|
||||
} from "hooks/useBatchContent";
|
||||
MakeBatchPropsParams,
|
||||
} from "hooks";
|
||||
|
||||
export interface RatingsProps extends BatchInputProps {
|
||||
actionType: "like";
|
||||
@@ -17,7 +18,7 @@ export interface RatingsProps extends BatchInputProps {
|
||||
labelOn: string | number;
|
||||
}
|
||||
|
||||
export type MakeRatingsProps = (x: MakePropsParams) => RatingsProps;
|
||||
export type MakeRatingsProps = (x: MakeBatchPropsParams) => RatingsProps;
|
||||
|
||||
export default function useRatings() {
|
||||
const fetch = (entity_token: string, entity_type: string, lib: any) => {
|
||||
@@ -59,8 +60,8 @@ export default function useRatings() {
|
||||
) => {
|
||||
let result = res.results
|
||||
? res.results.find((item: any, i: number) => {
|
||||
return (item.details || item)[tokenType] === entity_token;
|
||||
})
|
||||
return (item.details || item)[tokenType] === entity_token;
|
||||
})
|
||||
: res;
|
||||
|
||||
let { positive_rating_count } = (result.details || result).stats;
|
||||
@@ -76,7 +77,7 @@ export default function useRatings() {
|
||||
const makeProps: MakeRatingsProps = ({
|
||||
entityToken,
|
||||
entityType,
|
||||
}: MakePropsParams) => {
|
||||
}: MakeBatchPropsParams) => {
|
||||
const likeCount = ratings.library[entityToken]?.positive_rating_count || 0;
|
||||
return {
|
||||
...ratings.makeProps({ entityToken, entityType }),
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Container from "components/common/Container";
|
||||
import PageHeader from "components/layout/PageHeader";
|
||||
import { AITools } from "components/marketing";
|
||||
|
||||
export default function NotFound() {
|
||||
const [loaded, loadedSet] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loaded) {
|
||||
loadedSet(true);
|
||||
// @ts-ignore
|
||||
window.dataLayer.push({
|
||||
"event": "fe_page_not_found",
|
||||
"page": "*",
|
||||
"user_id": "$user_id"
|
||||
});
|
||||
}
|
||||
}, [loaded]);
|
||||
|
||||
return (
|
||||
<Container type="panel" className="mb-5">
|
||||
<PageHeader
|
||||
title="This page couldn't be found, maybe try one of our AI media creation tools?"
|
||||
titleH2={true}
|
||||
panel={false}
|
||||
/>
|
||||
<AITools />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user