diff --git a/frontend/apps/editor3d/app/components/reusable/ButtonLink/ButtonLink.tsx b/frontend/apps/editor3d/app/components/reusable/ButtonLink/ButtonLink.tsx index 5d96f64879..ad7ec70a1b 100644 --- a/frontend/apps/editor3d/app/components/reusable/ButtonLink/ButtonLink.tsx +++ b/frontend/apps/editor3d/app/components/reusable/ButtonLink/ButtonLink.tsx @@ -1,4 +1,4 @@ -import { Link, LinkProps } from "@remix-run/react"; +import { Link, LinkProps } from "react-router-dom"; import { IconDefinition } from "@fortawesome/fontawesome-svg-core"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { twMerge } from "tailwind-merge"; diff --git a/frontend/apps/editor3d/app/components/reusable/Typography.tsx b/frontend/apps/editor3d/app/components/reusable/Typography.tsx index b6a0df40ec..ed5d9a2cbd 100644 --- a/frontend/apps/editor3d/app/components/reusable/Typography.tsx +++ b/frontend/apps/editor3d/app/components/reusable/Typography.tsx @@ -1,4 +1,4 @@ -import { NavLink, NavLinkProps } from "@remix-run/react"; +import { NavLink, NavLinkProps } from "react-router-dom"; import { LabelHTMLAttributes, ReactNode } from "react"; import { twMerge } from "tailwind-merge"; diff --git a/frontend/apps/editor3d/app/components/signaled/TopBar/AuthButtons.tsx b/frontend/apps/editor3d/app/components/signaled/TopBar/AuthButtons.tsx index 3af31d4e03..473cb21fe9 100644 --- a/frontend/apps/editor3d/app/components/signaled/TopBar/AuthButtons.tsx +++ b/frontend/apps/editor3d/app/components/signaled/TopBar/AuthButtons.tsx @@ -16,10 +16,17 @@ export const AuthButtons = () => { } else { return ( <> - + Login - Sign Up + Sign Up ); } diff --git a/frontend/apps/editor3d/app/components/signaled/TopBar/TopBar.tsx b/frontend/apps/editor3d/app/components/signaled/TopBar/TopBar.tsx index 8ae1bdba41..c7b551c669 100644 --- a/frontend/apps/editor3d/app/components/signaled/TopBar/TopBar.tsx +++ b/frontend/apps/editor3d/app/components/signaled/TopBar/TopBar.tsx @@ -1,9 +1,9 @@ -import { useLocation, useParams } from "@remix-run/react"; import { faChevronLeft, faChevronRight, faImages, } from "@fortawesome/pro-solid-svg-icons"; +import { useLocation, useParams } from "react-router-dom"; import { Button, ButtonLink } from "~/components"; import { AuthButtons } from "./AuthButtons"; import { SceneTitleInput } from "./SceneTitleInput"; diff --git a/frontend/apps/editor3d/app/hoc/withProtectedRoute.tsx b/frontend/apps/editor3d/app/hoc/withProtectedRoute.tsx index 5e19b9bbcb..68db6e20bb 100644 --- a/frontend/apps/editor3d/app/hoc/withProtectedRoute.tsx +++ b/frontend/apps/editor3d/app/hoc/withProtectedRoute.tsx @@ -1,5 +1,5 @@ import { ComponentType, useEffect, useRef } from "react"; -import { useNavigate, useLocation } from "@remix-run/react"; +import { useNavigate, useLocation } from "react-router-dom"; import { useSignals, useSignalEffect } from "@preact/signals-react/runtime"; import { LoadingDots } from "~/components"; import { authentication, persistLogin } from "~/signals"; diff --git a/frontend/apps/editor3d/app/index.tsx b/frontend/apps/editor3d/app/index.tsx new file mode 100644 index 0000000000..9486c44927 --- /dev/null +++ b/frontend/apps/editor3d/app/index.tsx @@ -0,0 +1,121 @@ +import { StrictMode } from 'react'; +import { useSignals, useSignalEffect } from "@preact/signals-react/runtime"; +import { useEffect } from "react"; +import { BrowserRouter } from 'react-router-dom'; +import * as ReactDOM from 'react-dom/client'; +import { authentication, persistLogin } from "~/signals"; +import { PageEnigma } from './pages/PageEnigma/PageEnigma'; +import { createRoot } from "react-dom/client"; +//import App from './app/app'; +//import { App } from './root'; + +import { + Links, + Meta, + Outlet, + Scripts, + ScrollRestoration, + useLoaderData, +} from "@remix-run/react"; + +import "./styles/normalize.css"; +import "./styles/tailwind.css"; +import "./styles/base.css"; +import "@fortawesome/fontawesome-svg-core/styles.css"; + +import { config } from "@fortawesome/fontawesome-svg-core"; + +import EnvironmentVariables from "~/Classes/EnvironmentVariables"; +import { pageHeight, pageWidth } from "~/signals"; + +import { showWizard } from "~/pages/PageEnigma/Wizard/signals/wizard"; +import { BuildEnvironmentType, GetBuildEnvironment } from "./BuildEnvironment"; + +config.autoAddCss = false; /* eslint-disable import/first */ + +//const root = ReactDOM.createRoot( +// document.getElementById('root') as HTMLElement +//); +// +//root.render( +// +// +// +// +// +//); + +//createRoot(document.getElementById("root")!).render(); + +// TODO(bt,2025-04-19): Make these configurable +const ENV = { + BASE_API: "https://api.storyteller.ai", + GOOGLE_API: "https://studio.storyteller.ai", + FUNNEL_API: "https://studio.storyteller.ai", + CDN_API: "https://cdn-2.fakeyou.com", + GRAVATAR_API: "https://studio.storyteller.ai", + DEPLOY_PRIME_URL: "https://studio.storyteller.ai", +}; + +const GlobalSettingsManager = ({ env }: { env: Record }) => { + useSignals(); + useSignalEffect(() => { + persistLogin(); + }); + + /// Initizations that depends on ENV vars /// + function PostHogInit() { + const data = EnvironmentVariables.values; + const apiKey = data.REACT_APP_PUBLIC_POSTHOG_KEY as string; + //posthog.init(apiKey, { + // //HACK: This is the default host from Netlify, but need to figure out why it isn't working on prod. + // // api_host: data.DEPLOY_PRIME_URL + "/ingest" as string, + // api_host: "https://studio.storyteller.ai/ingest" as string, + // ui_host: data.REACT_APP_PUBLIC_POSTHOG_UI as string, + //}); + } + useEffect(() => { + EnvironmentVariables.initialize(env); + PostHogInit(); + }, [env]); + + /// Initizations that run only once on 1ST mount /// + function setPage() { + // TODO address this issue with zooming + pageHeight.value = window.innerHeight; + pageWidth.value = window.innerWidth; + } + + function initWizard() { + if (showWizard.value) { + return; + } + const wizard = localStorage.getItem("storyteller-wizard"); + showWizard.value = wizard ? "" : "initial"; + localStorage.setItem("storyteller-wizard", "shown"); + } + + useEffect(() => { + initWizard(); + setPage(); + window.addEventListener("resize", setPage); + return () => { + window.removeEventListener("resize", setPage); + }; + }, []); + + return null; +}; + +// TODO: Replace environment variables from `root.tsx` +createRoot(document.getElementById("root")!).render( + <> + + + +
+ + + + +); diff --git a/frontend/apps/editor3d/app/login.tsx b/frontend/apps/editor3d/app/login.tsx new file mode 100644 index 0000000000..8bd06a595e --- /dev/null +++ b/frontend/apps/editor3d/app/login.tsx @@ -0,0 +1,185 @@ +import { useRef } from "react"; +import { BrowserRouter } from 'react-router-dom'; +import { StrictMode } from 'react'; +import { useNavigate, useSearchParams } from "react-router-dom"; +import { useSignalEffect, useSignals } from "@preact/signals-react/runtime"; + +import { faKey, faUser } from "@fortawesome/pro-solid-svg-icons"; + +import { AUTH_STATUS } from "~/enums"; +import { authentication, login, logout } from "~/signals"; +import { createRoot } from "react-dom/client"; + +import { + Button, + H1, + Input, + Link, + P, + LoadingDots, + ConfirmationModal, +} from "~/components"; + +import "./styles/normalize.css"; +import "./styles/tailwind.css"; +import "./styles/base.css"; +import "@fortawesome/fontawesome-svg-core/styles.css"; + +import { config } from "@fortawesome/fontawesome-svg-core"; +import { GlobalSettingsManager } from "./pages/PageEnigma/GlobalSettingsManager"; + +config.autoAddCss = false; /* eslint-disable import/first */ + +// TODO(bt,2025-04-19): Make these configurable +const ENV = { + BASE_API: "https://api.storyteller.ai", + GOOGLE_API: "https://studio.storyteller.ai", + FUNNEL_API: "https://studio.storyteller.ai", + CDN_API: "https://cdn-2.fakeyou.com", + GRAVATAR_API: "https://studio.storyteller.ai", + DEPLOY_PRIME_URL: "https://studio.storyteller.ai", +}; + +export default function LoginScreen() { + useSignals(); + const navigate = useNavigate(); + const [searchParams] = useSearchParams(); + + const formRef = useRef(null); + const { status: authStatus } = authentication; + const authLoaderMessage = getAuthLoaderMessage(); + const shouldShowLoader = checkShouldShowLoader(); + + const showNoAccessModal = authStatus.value === AUTH_STATUS.NO_ACCESS; + + const handleOnSumbit = (ev: React.FormEvent) => { + ev.preventDefault(); + if (formRef.current) { + const form = new FormData(formRef.current); + const usernameOrEmail = form.get("usernameOrEmail")?.toString(); + const password = form.get("password")?.toString(); + if (usernameOrEmail && password && login) { + login({ + usernameOrEmail, + password, + }); + } + } + }; // end handleOnSubmit + + useSignalEffect(() => { + const redirectPath = searchParams.get("redirect"); + if (authStatus.value === AUTH_STATUS.LOGGED_IN) { + navigate(redirectPath ? redirectPath : "/"); + } + }); + + return ( +
+
+

+ Login to Storyteller +

+
+
+
+ + +
+ + Forgot your password? + +
+

Don't have an account?

+ Sign Up +
+
+ + +
+ + { + handleClose(); + if (window) { + window.open("https://storyteller.ai/beta-key/redeem", "_blank"); + } + }} + /> +
+
+ ); +} + +const handleClose = () => { + if (authentication.status.value !== AUTH_STATUS.LOGGED_OUT) { + logout(); + } +}; + +const checkShouldShowLoader = () => { + return ( + authentication.status.value === AUTH_STATUS.LOGGING || + authentication.status.value === AUTH_STATUS.LOGGED_IN + ); +}; + +const getAuthLoaderMessage = () => { + if (authentication.status.value === AUTH_STATUS.LOGGED_IN) { + return "Authenticated, Redirecting..."; + } + if (authentication.status.value === AUTH_STATUS.GET_USER_INFO) { + return "Getting User Info..."; + } + return "Getting Session..."; +}; + + +// TODO: Replace environment variables from `root.tsx` +createRoot(document.getElementById("root")!).render( + <> + + + + + + + +); diff --git a/frontend/apps/editor3d/app/pages/Page404/index.tsx b/frontend/apps/editor3d/app/pages/Page404/index.tsx index c9d910023d..69ae9ebcb6 100644 --- a/frontend/apps/editor3d/app/pages/Page404/index.tsx +++ b/frontend/apps/editor3d/app/pages/Page404/index.tsx @@ -1,6 +1,6 @@ import { faChevronLeft } from "@fortawesome/pro-solid-svg-icons"; import { P, H1, ButtonLink } from "~/components"; -import { json } from "@remix-run/router"; +import { json } from "react-router-dom"; export const loader = () => { return json(null, { status: 404 }); diff --git a/frontend/apps/editor3d/app/pages/PageEnigma/GlobalSettingsManager.tsx b/frontend/apps/editor3d/app/pages/PageEnigma/GlobalSettingsManager.tsx new file mode 100644 index 0000000000..b228e5cd21 --- /dev/null +++ b/frontend/apps/editor3d/app/pages/PageEnigma/GlobalSettingsManager.tsx @@ -0,0 +1,57 @@ +import { useSignals, useSignalEffect } from "@preact/signals-react/runtime"; +import EnvironmentVariables from "~/Classes/EnvironmentVariables"; +import { persistLogin } from "~/signals"; +import { pageHeight, pageWidth } from "~/signals"; +import { useEffect } from "react"; +import { showWizard } from "~/pages/PageEnigma/Wizard/signals/wizard"; + + +export const GlobalSettingsManager = ({ env }: { env: Record }) => { + useSignals(); + useSignalEffect(() => { + persistLogin(); + }); + + /// Initizations that depends on ENV vars /// + function PostHogInit() { + const data = EnvironmentVariables.values; + const apiKey = data.REACT_APP_PUBLIC_POSTHOG_KEY as string; + //posthog.init(apiKey, { + // //HACK: This is the default host from Netlify, but need to figure out why it isn't working on prod. + // // api_host: data.DEPLOY_PRIME_URL + "/ingest" as string, + // api_host: "https://studio.storyteller.ai/ingest" as string, + // ui_host: data.REACT_APP_PUBLIC_POSTHOG_UI as string, + //}); + } + useEffect(() => { + EnvironmentVariables.initialize(env); + PostHogInit(); + }, [env]); + + /// Initizations that run only once on 1ST mount /// + function setPage() { + // TODO address this issue with zooming + pageHeight.value = window.innerHeight; + pageWidth.value = window.innerWidth; + } + + function initWizard() { + if (showWizard.value) { + return; + } + const wizard = localStorage.getItem("storyteller-wizard"); + showWizard.value = wizard ? "" : "initial"; + localStorage.setItem("storyteller-wizard", "shown"); + } + + useEffect(() => { + initWizard(); + setPage(); + window.addEventListener("resize", setPage); + return () => { + window.removeEventListener("resize", setPage); + }; + }, []); + + return null; +}; diff --git a/frontend/apps/editor3d/app/pages/PageEnigma/comps/ControlsTopButtons/ControlsTopButtons.tsx b/frontend/apps/editor3d/app/pages/PageEnigma/comps/ControlsTopButtons/ControlsTopButtons.tsx index f181948b3e..1ded1d16a1 100644 --- a/frontend/apps/editor3d/app/pages/PageEnigma/comps/ControlsTopButtons/ControlsTopButtons.tsx +++ b/frontend/apps/editor3d/app/pages/PageEnigma/comps/ControlsTopButtons/ControlsTopButtons.tsx @@ -1,5 +1,5 @@ import { useContext, useState, useCallback } from "react"; -import { useParams, useLocation, useNavigate } from "@remix-run/react"; +import { useParams, useLocation, useNavigate } from "react-router-dom"; import { useSignals, useSignalEffect } from "@preact/signals-react/runtime"; import { faCheckSquare, diff --git a/frontend/apps/editor3d/app/pages/PageEnigma/comps/Timeline/PremiumLockTimeline.tsx b/frontend/apps/editor3d/app/pages/PageEnigma/comps/Timeline/PremiumLockTimeline.tsx index 23ffee1736..af2616e4e1 100644 --- a/frontend/apps/editor3d/app/pages/PageEnigma/comps/Timeline/PremiumLockTimeline.tsx +++ b/frontend/apps/editor3d/app/pages/PageEnigma/comps/Timeline/PremiumLockTimeline.tsx @@ -1,4 +1,4 @@ -import { Link } from "@remix-run/react"; +import { Link } from "react-router-dom"; import { fullWidth, timelineHeight } from "../../signals"; interface PremiumLockTimelineProps { diff --git a/frontend/apps/editor3d/app/routes/$sceneToken.tsx b/frontend/apps/editor3d/app/routes/$sceneToken.tsx index da212591e2..db0b4754ab 100644 --- a/frontend/apps/editor3d/app/routes/$sceneToken.tsx +++ b/frontend/apps/editor3d/app/routes/$sceneToken.tsx @@ -1,5 +1,5 @@ import type { HeadersFunction } from "@remix-run/deno"; -import { useParams } from "@remix-run/react"; +import { useParams } from "react-router-dom"; import { withProtectionRoute } from "~/hoc/withProtectedRoute"; import { PageEnigma } from "~/pages/PageEnigma"; diff --git a/frontend/apps/editor3d/app/routes/Login.tsx b/frontend/apps/editor3d/app/routes/Login.tsx index 4a952cd6d1..a53d27aa9c 100644 --- a/frontend/apps/editor3d/app/routes/Login.tsx +++ b/frontend/apps/editor3d/app/routes/Login.tsx @@ -1,5 +1,5 @@ import { useRef } from "react"; -import { useNavigate, useSearchParams } from "@remix-run/react"; +import { useNavigate, useSearchParams } from "react-router-dom"; import { useSignalEffect, useSignals } from "@preact/signals-react/runtime"; import { faKey, faUser } from "@fortawesome/pro-solid-svg-icons"; @@ -90,7 +90,10 @@ export default function LoginScreen() {

Don't have an account?

- Sign Up + Sign Up
diff --git a/frontend/apps/editor3d/app/routes/Signup.tsx b/frontend/apps/editor3d/app/routes/Signup.tsx index 765b3b502c..d91c42132f 100644 --- a/frontend/apps/editor3d/app/routes/Signup.tsx +++ b/frontend/apps/editor3d/app/routes/Signup.tsx @@ -4,7 +4,7 @@ import { addToast, authentication, signUp } from "~/signals"; import { FormEvent, useRef, useState } from "react"; import { AUTH_STATUS, ToastTypes } from "~/enums"; import { useSignalEffect, useSignals } from "@preact/signals-react/runtime"; -import { useNavigate, useSearchParams } from "@remix-run/react"; +import { useNavigate, useSearchParams } from "react-router-dom"; const regEx = /^(([^<>()[\].,;:\s@"]+(.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i; diff --git a/frontend/apps/editor3d/app/signals/authentication/fetchers.ts b/frontend/apps/editor3d/app/signals/authentication/fetchers.ts index a46f2c4372..1c4bf29d27 100644 --- a/frontend/apps/editor3d/app/signals/authentication/fetchers.ts +++ b/frontend/apps/editor3d/app/signals/authentication/fetchers.ts @@ -46,6 +46,8 @@ export const login = async ({ // in storyteller studio, only having a sesison is not enough, // we need session info and active subscription info as well getUserInfoAndSubcriptions(); + + window.location.href = "/"; // TODO(bt,2025-04-19): Once we have in-page routing, get rid of this. }; export const signUp = async ({ diff --git a/frontend/apps/editor3d/app/signup.tsx b/frontend/apps/editor3d/app/signup.tsx new file mode 100644 index 0000000000..0b762e7fe2 --- /dev/null +++ b/frontend/apps/editor3d/app/signup.tsx @@ -0,0 +1,185 @@ +import { faEnvelope, faKey, faUser } from "@fortawesome/pro-solid-svg-icons"; +import { GlobalSettingsManager } from "./pages/PageEnigma/GlobalSettingsManager"; +import { StrictMode } from 'react'; +import { Button, H1, Input, Link, P } from "~/components"; +import { addToast, authentication, signUp } from "~/signals"; +import { FormEvent, useRef, useState } from "react"; +import { AUTH_STATUS, ToastTypes } from "~/enums"; +import { useSignalEffect, useSignals } from "@preact/signals-react/runtime"; +import { useNavigate, useSearchParams } from "react-router-dom"; +import { createRoot } from "react-dom/client"; +import { BrowserRouter } from 'react-router-dom'; + +import "./styles/normalize.css"; +import "./styles/tailwind.css"; +import "./styles/base.css"; +import "@fortawesome/fontawesome-svg-core/styles.css"; + +import { config } from "@fortawesome/fontawesome-svg-core"; + +config.autoAddCss = false; /* eslint-disable import/first */ + +const regEx = + /^(([^<>()[\].,;:\s@"]+(.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i; + +// TODO(bt,2025-04-19): Make these configurable +const ENV = { + BASE_API: "https://api.storyteller.ai", + GOOGLE_API: "https://studio.storyteller.ai", + FUNNEL_API: "https://studio.storyteller.ai", + CDN_API: "https://cdn-2.fakeyou.com", + GRAVATAR_API: "https://studio.storyteller.ai", + DEPLOY_PRIME_URL: "https://studio.storyteller.ai", +}; + +export default function SignUpScreen() { + useSignals(); + const navigate = useNavigate(); + const formRef = useRef(null); + const [usernameError, setUsernameError] = useState(""); + const [emailError, setEmailError] = useState(""); + const [passwordError, setPasswordError] = useState(""); + const [passwordConfirmationError, setPasswordConfirmationError] = + useState(""); + const [searchParams] = useSearchParams(); + const { status: authStatus } = authentication; + + const handleOnSubmit = (ev: FormEvent) => { + ev.preventDefault(); + if (formRef.current) { + const form = new FormData(formRef.current); + const email = form.get("email")?.toString(); + const password = form.get("password")?.toString(); + const passwordConfirmation = form + .get("password-confirmation") + ?.toString(); + const username = form.get("username")?.toString(); + setUsernameError(""); + if (!username || username.length < 6) { + setUsernameError("Username must be at least 6 characters long"); + } + setEmailError(""); + if (!email || !email.match(regEx)) { + setEmailError("Email must be a valid email address"); + } + setPasswordError(""); + if (!password || password.length < 8) { + setPasswordError("Password must be at least 8 characters long"); + } + setPasswordConfirmationError(""); + if (!passwordError && passwordConfirmation !== password) { + setPasswordConfirmationError("Passwords do not match"); + } + + if ( + !usernameError && + !passwordError && + !emailError && + !passwordConfirmationError && + signUp + ) { + signUp({ + username: username!, + email: email!, + password: password!, + passwordConfirmation: passwordConfirmation!, + }).then((error) => { + console.log("Error occured", error); + if (error) { + addToast(ToastTypes.ERROR, error); + } + }); + } + } + }; // end handleOnSubmit + + useSignalEffect(() => { + const redirectPath = searchParams.get("redirect"); + if (authStatus.value === AUTH_STATUS.LOGGED_IN) { + navigate(redirectPath ? redirectPath : "/"); + return; + } + if (authStatus.value === AUTH_STATUS.NO_ACCESS) { + window.open("https://storyteller.ai/", "_self"); + return; + } + }); + + return ( +
+
+

Sign Up to Storyteller

+
+
+
+ +
+ +
+ +
+ +
+
+ +
+
+

Already have an account?

+ Log in instead +
+
+
+
+ ); +} + + +// TODO: Replace environment variables from `root.tsx` +createRoot(document.getElementById("root")!).render( + <> + + + + + + + +); diff --git a/frontend/apps/editor3d/app/utilities.ts b/frontend/apps/editor3d/app/utilities.ts index c78e7fa1b8..0193c4c4e9 100644 --- a/frontend/apps/editor3d/app/utilities.ts +++ b/frontend/apps/editor3d/app/utilities.ts @@ -1,4 +1,4 @@ -import { Params } from "@remix-run/react"; +import { Params } from "react-router-dom"; import { JobStatus } from "./enums"; import deepEqual from "deep-equal"; diff --git a/frontend/apps/editor3d/index.html b/frontend/apps/editor3d/index.html new file mode 100644 index 0000000000..81c86cd95e --- /dev/null +++ b/frontend/apps/editor3d/index.html @@ -0,0 +1,16 @@ + + + + + MyApp + + + + + + + +
+ + + diff --git a/frontend/apps/editor3d/login.html b/frontend/apps/editor3d/login.html new file mode 100644 index 0000000000..dea0fea239 --- /dev/null +++ b/frontend/apps/editor3d/login.html @@ -0,0 +1,16 @@ + + + + + Login + + + + + + + +
+ + + diff --git a/frontend/apps/editor3d/package.json b/frontend/apps/editor3d/package.json index 23184eba48..610c9b1eae 100644 --- a/frontend/apps/editor3d/package.json +++ b/frontend/apps/editor3d/package.json @@ -14,9 +14,10 @@ } }, "scripts": { - "build": "remix vite:build", - "dev": "echo 'editor3d' && remix vite:dev", - "staging-build": "remix vite:build", + "build": "vite build", + "preview": "vite preview --port 8080", + "dev": "echo 'editor3d' && vite dev", + "staging-build": "vite build", "lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint playground/* .", "start": "netlify serve", "typecheck": "tsc", @@ -65,6 +66,8 @@ "react-drag-drop-files": "^2.3.10", "react-helmet": "^6.1.0", "react-image-crop": "^11.0.5", + "react-router": "^6.26.1", + "react-router-dom": "^6.26.1", "react-virtualized": "^9.22.6", "tailwind-merge": "^2.2.2", "terser": "^5.30.3", diff --git a/frontend/apps/editor3d/remix.config.ts b/frontend/apps/editor3d/remix.config.ts deleted file mode 100644 index 1069800ddf..0000000000 --- a/frontend/apps/editor3d/remix.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { AppConfig } from '@remix-run/dev'; - -module.exports = { - ignoredRouteFiles: ["**/.*"], - tailwind: true, - serverModuleFormat: "cjs", -} satisfies AppConfig; \ No newline at end of file diff --git a/frontend/apps/editor3d/script/netlify_build.sh b/frontend/apps/editor3d/script/netlify_build.sh index 33d8afb80a..81085ae0a5 100755 --- a/frontend/apps/editor3d/script/netlify_build.sh +++ b/frontend/apps/editor3d/script/netlify_build.sh @@ -11,15 +11,15 @@ nx build editor3d --verbose echo "Change to project dir" pushd apps/editor3d/ -echo "List build directory files" -ls -lA build/ +#echo "List build directory files" +#ls -lA build/ -echo "Make output directory" -mkdir dist/ +#echo "Make output directory" +#mkdir dist/ echo "Copy files to putput directory" -cp -r build/server/* dist/ -cp -r build/client/* dist/ +#cp -r build/server/* dist/ +#cp -r build/client/* dist/ cp _headers dist/ #cp _redirects dist/ #cp "404.html" dist/ diff --git a/frontend/apps/editor3d/signup.html b/frontend/apps/editor3d/signup.html new file mode 100644 index 0000000000..b668ef3a6c --- /dev/null +++ b/frontend/apps/editor3d/signup.html @@ -0,0 +1,16 @@ + + + + + Signup + + + + + + + +
+ + + diff --git a/frontend/apps/editor3d/tsconfig.json b/frontend/apps/editor3d/tsconfig.json index 5c348b8c23..490787456a 100644 --- a/frontend/apps/editor3d/tsconfig.json +++ b/frontend/apps/editor3d/tsconfig.json @@ -21,9 +21,6 @@ "noEmit": true }, "references": [ - { - "path": "../../libs/api" - }, { "path": "../../libs/login" } diff --git a/frontend/apps/editor3d/vite.config.ts b/frontend/apps/editor3d/vite.config.ts index bc8d6ac52e..e3fe396f3f 100644 --- a/frontend/apps/editor3d/vite.config.ts +++ b/frontend/apps/editor3d/vite.config.ts @@ -1,9 +1,9 @@ -import { vitePlugin as remix } from "@remix-run/dev"; import { defineConfig } from "vite"; import tsconfigPaths from "vite-tsconfig-paths"; import { netlifyPlugin } from "@netlify/remix-edge-adapter/plugin"; import { viteCommonjs, esbuildCommonjs } from '@originjs/vite-plugin-commonjs' import path from 'path' +import { dirname, resolve } from 'node:path' export default defineConfig({ root: __dirname, @@ -34,8 +34,17 @@ export default defineConfig({ // globals: {}, // }, //}, + build: { + rollupOptions: { + input: { + index: resolve(__dirname, 'index.html'), + login: resolve(__dirname, 'login.html'), + signup: resolve(__dirname, 'signup.html'), + //nested: resolve(__dirname, 'nested/index.html'), + }, + }, + }, plugins: [ - remix(), netlifyPlugin(), tsconfigPaths(), //viteCommonjs({ diff --git a/frontend/apps/my-app/index.html b/frontend/apps/my-app/index.html new file mode 100644 index 0000000000..dd8b10918b --- /dev/null +++ b/frontend/apps/my-app/index.html @@ -0,0 +1,16 @@ + + + + + MyApp + + + + + + + +
+ + + diff --git a/frontend/apps/my-app/package.json b/frontend/apps/my-app/package.json new file mode 100644 index 0000000000..646cb266d6 --- /dev/null +++ b/frontend/apps/my-app/package.json @@ -0,0 +1,5 @@ +{ + "name": "@frontend/my-app", + "version": "0.0.1", + "private": true +} diff --git a/frontend/apps/my-app/public/favicon.ico b/frontend/apps/my-app/public/favicon.ico new file mode 100644 index 0000000000..317ebcb233 Binary files /dev/null and b/frontend/apps/my-app/public/favicon.ico differ diff --git a/frontend/apps/my-app/src/app/app.module.css b/frontend/apps/my-app/src/app/app.module.css new file mode 100644 index 0000000000..7b88fbabf8 --- /dev/null +++ b/frontend/apps/my-app/src/app/app.module.css @@ -0,0 +1 @@ +/* Your styles goes here. */ diff --git a/frontend/apps/my-app/src/app/app.spec.tsx b/frontend/apps/my-app/src/app/app.spec.tsx new file mode 100644 index 0000000000..d285ad62bc --- /dev/null +++ b/frontend/apps/my-app/src/app/app.spec.tsx @@ -0,0 +1,16 @@ +import { render } from '@testing-library/react'; +import { BrowserRouter } from 'react-router-dom'; + +import App from './app'; + +describe('App', () => { + it('should render successfully', () => { + const { baseElement } = render(); + expect(baseElement).toBeTruthy(); + }); + + it('should have a greeting as the title', () => { + const { getAllByText } = render(); + expect(getAllByText(new RegExp('Welcome @frontend/my-app', 'gi')).length > 0).toBeTruthy(); + }); +}); diff --git a/frontend/apps/my-app/src/app/app.tsx b/frontend/apps/my-app/src/app/app.tsx new file mode 100644 index 0000000000..4d497d8aba --- /dev/null +++ b/frontend/apps/my-app/src/app/app.tsx @@ -0,0 +1,45 @@ +// Uncomment this line to use CSS modules +// import styles from './app.module.css'; +import NxWelcome from "./nx-welcome"; + +import { Route, Routes, Link } from 'react-router-dom'; + +export function App() { + return ( +
+ + + {/* START: routes */} + {/* These routes and navigation have been generated for you */} + {/* Feel free to move and update them to fit your needs */} +
+
+
+
+
    +
  • Home
  • +
  • Page 2
  • +
+
+ + This is the generated root route. Click here for page 2.
+ } + /> + Click here to go back to root page. + } + /> + + {/* END: routes */} + + ); +} + +export default App; + + diff --git a/frontend/apps/my-app/src/app/nx-welcome.tsx b/frontend/apps/my-app/src/app/nx-welcome.tsx new file mode 100644 index 0000000000..63cc7d12c2 --- /dev/null +++ b/frontend/apps/my-app/src/app/nx-welcome.tsx @@ -0,0 +1,857 @@ +/* + * * * * * * * * * * * * * * * * * * * * * * * * * * * * + This is a starter component and can be deleted. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * + Delete this file and get started with your project! + * * * * * * * * * * * * * * * * * * * * * * * * * * * * + */ +export function NxWelcome({ title }: { title: string }) { + return ( + <> +