mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-29 13:02:51 -04:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8997666ea0 | ||
|
|
c3680a8e25 |
@@ -2,12 +2,13 @@
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "enables the default permissions",
|
||||
"windows": [
|
||||
"main"
|
||||
],
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"log:default",
|
||||
"core:window:allow-minimize",
|
||||
"core:window:allow-toggle-maximize",
|
||||
"core:window:allow-close",
|
||||
"upload:allow-download",
|
||||
"upload:default",
|
||||
"http:allow-fetch",
|
||||
@@ -24,4 +25,4 @@
|
||||
},
|
||||
"dialog:default"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,3 +3,7 @@
|
||||
frontendDist = "../../../frontend/apps/editor3d/dist"
|
||||
beforeDevCommand = "npx nx run editor3d:dev"
|
||||
devUrl = "http://localhost:5173"
|
||||
|
||||
[[app.windows]]
|
||||
decorations = true
|
||||
title = "ArtCraft"
|
||||
@@ -4,5 +4,16 @@
|
||||
"beforeDevCommand": "echo 'no dev'",
|
||||
"devUrl": "http://localhost:5173",
|
||||
"beforeBuildCommand": "npx nx run editor3d:build"
|
||||
},
|
||||
"app": {
|
||||
"windows": [
|
||||
{
|
||||
"title": "ArtCraft",
|
||||
"resizable": true,
|
||||
"fullscreen": false,
|
||||
"dragDropEnabled": false,
|
||||
"decorations": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,3 +4,7 @@ frontendDist = "../../../frontend/apps/editor3d/dist"
|
||||
#beforeDevCommand = "nx run editor3d:dev"
|
||||
beforeDevCommand = "echo 'no dev'"
|
||||
devUrl = "http://localhost:5173"
|
||||
|
||||
[[app.windows]]
|
||||
decorations = true
|
||||
title = "ArtCraft"
|
||||
|
||||
@@ -4,5 +4,16 @@
|
||||
"beforeDevCommand": "echo 'no dev'",
|
||||
"devUrl": "http://localhost:5173",
|
||||
"beforeBuildCommand": "npx nx run editor3d:build"
|
||||
},
|
||||
"app": {
|
||||
"windows": [
|
||||
{
|
||||
"title": "ArtCraft",
|
||||
"resizable": true,
|
||||
"fullscreen": false,
|
||||
"dragDropEnabled": false,
|
||||
"decorations": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"height": 1300,
|
||||
"resizable": true,
|
||||
"fullscreen": false,
|
||||
"decorations": false,
|
||||
"dragDropEnabled": false
|
||||
}
|
||||
],
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
"width": 2400,
|
||||
"height": 1300,
|
||||
"resizable": true,
|
||||
"fullscreen": false
|
||||
"fullscreen": false,
|
||||
"decorations": false
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
|
||||
@@ -21,7 +21,7 @@ export const AuthButtons = ({
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-center gap-3.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-white/20">|</span>
|
||||
<Button
|
||||
className="h-[38px]"
|
||||
|
||||
@@ -7,8 +7,13 @@ import {
|
||||
faPaintbrush,
|
||||
faImage,
|
||||
faPenNib,
|
||||
// faGem,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import {
|
||||
faWindowRestore,
|
||||
faSquare,
|
||||
faXmark,
|
||||
faDash,
|
||||
} from "@fortawesome/pro-regular-svg-icons";
|
||||
import { Button } from "@storyteller/ui-button";
|
||||
import { AuthButtons } from "./AuthButtons";
|
||||
import { SceneTitleInput } from "./SceneTitleInput";
|
||||
@@ -39,6 +44,10 @@ import {
|
||||
// import { usePricingModalStore } from "@storyteller/ui-pricing-modal"; - Uncomment for pricing modal - BFlat
|
||||
import toast from "react-hot-toast";
|
||||
import { gtagEvent } from "@storyteller/google-analytics";
|
||||
import {
|
||||
useTauriWindowControls,
|
||||
useTauriPlatform,
|
||||
} from "@storyteller/tauri-utils";
|
||||
|
||||
interface Props {
|
||||
pageName: string;
|
||||
@@ -78,7 +87,7 @@ const appMenuTabs: MenuIconItem[] = [
|
||||
id: "EDIT",
|
||||
label: "Edit Image",
|
||||
icon: <FontAwesomeIcon icon={faPenNib} />,
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
export const topNavMediaId = signal<string>("");
|
||||
@@ -89,10 +98,14 @@ export const TopBar = ({ pageName, loginSignUpPressed }: Props) => {
|
||||
|
||||
const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false);
|
||||
|
||||
const { isDesktop, isMaximized, minimize, toggleMaximize, close } =
|
||||
useTauriWindowControls();
|
||||
const platform = useTauriPlatform();
|
||||
|
||||
const handleOpenGalleryModal = () => {
|
||||
galleryModalVisibleViewMode.value = true;
|
||||
galleryModalVisibleDuringDrag.value = true;
|
||||
gtagEvent("open_gallery_modal", { "tab": tabStore.activeTabId });
|
||||
gtagEvent("open_gallery_modal", { tab: tabStore.activeTabId });
|
||||
};
|
||||
|
||||
const tabStore = useTabStore();
|
||||
@@ -128,13 +141,17 @@ export const TopBar = ({ pageName, loginSignUpPressed }: Props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className="fixed left-0 top-0 z-[60] w-full border-b border-white/5 bg-ui-background">
|
||||
<header
|
||||
className="fixed left-0 top-0 z-[60] w-full border-b border-white/5 bg-ui-background"
|
||||
data-tauri-drag-region
|
||||
>
|
||||
<nav
|
||||
className="mx-auto grid h-[56px] w-screen grid-cols-3 items-center justify-between px-3"
|
||||
className="mx-auto grid h-[56px] w-screen grid-cols-3 items-center justify-between ps-3"
|
||||
aria-label="navigation"
|
||||
>
|
||||
<div className="flex items-center gap-7">
|
||||
<div>
|
||||
<div className="flex items-center gap-3">
|
||||
|
||||
<div className="mr-2">
|
||||
<span className="sr-only">ArtCraft</span>
|
||||
<img
|
||||
className="h-[24px] w-auto"
|
||||
@@ -147,7 +164,7 @@ export const TopBar = ({ pageName, loginSignUpPressed }: Props) => {
|
||||
activeMenu={tabStore.activeTabId}
|
||||
disabled={disableTabSwitcher()}
|
||||
onMenuChange={(tabId) => {
|
||||
gtagEvent("switch_tab", { "tab": tabId });
|
||||
gtagEvent("switch_tab", { tab: tabId });
|
||||
|
||||
// Prevent a second input if the switcher is throttled.
|
||||
if (switcherThrottle.current) {
|
||||
@@ -170,11 +187,13 @@ export const TopBar = ({ pageName, loginSignUpPressed }: Props) => {
|
||||
setDisableSwitcher(false);
|
||||
}, SWITCHER_THROTTLE_TIME);
|
||||
}}
|
||||
className="w-fit"
|
||||
className="no-drag w-fit"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-center gap-2 font-medium">
|
||||
<div
|
||||
className={`${tabStore.activeTabId === "3D" ? "no-drag" : ""} flex items-center justify-center gap-2 font-medium`}
|
||||
>
|
||||
{tabStore.activeTabId === "3D" ? (
|
||||
<SceneTitleInput pageName={pageName} />
|
||||
) : (
|
||||
@@ -188,8 +207,8 @@ export const TopBar = ({ pageName, loginSignUpPressed }: Props) => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-3.5 pr-2">
|
||||
<div className="flex gap-2">
|
||||
<div className="flex justify-end gap-2">
|
||||
<div className="no-drag flex gap-2">
|
||||
{/* - Uncomment for pricing modal - BFlat */}
|
||||
{/* <Button
|
||||
variant="primary"
|
||||
@@ -220,7 +239,37 @@ export const TopBar = ({ pageName, loginSignUpPressed }: Props) => {
|
||||
|
||||
<Activity />
|
||||
</div>
|
||||
<AuthButtons loginSignUpPressed={loginSignUpPressed} />
|
||||
<div className="no-drag">
|
||||
<AuthButtons loginSignUpPressed={loginSignUpPressed} />
|
||||
</div>
|
||||
{isDesktop && platform !== "macos" && (
|
||||
<div className="no-drag flex items-center">
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="h-[32px] w-[44px] rounded-none bg-transparent text-white/70 hover:bg-white/10 hover:text-white"
|
||||
onClick={minimize}
|
||||
>
|
||||
<FontAwesomeIcon icon={faDash} className="text-xs" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="h-[32px] w-[44px] rounded-none bg-transparent text-white/70 hover:bg-white/10 hover:text-white"
|
||||
onClick={toggleMaximize}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={isMaximized ? faWindowRestore : faSquare}
|
||||
className="text-xs"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="h-[32px] w-[44px] rounded-none bg-transparent text-white/70 hover:bg-red/40 hover:text-white"
|
||||
onClick={close}
|
||||
>
|
||||
<FontAwesomeIcon icon={faXmark} className="text-lg" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
@@ -37,7 +37,7 @@ const TextToImage = ({ imageMediaId, imageUrl }: TextToImageProps) => {
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="flex h-[calc(100vh-56px)] w-full rounded-lg bg-[#121212]"
|
||||
className="flex h-[calc(100vh-56px)] w-full bg-[#121212]"
|
||||
>
|
||||
<div className="h-full w-full p-4">
|
||||
<div className="flex h-full w-full flex-col items-center justify-center rounded-md pb-12">
|
||||
|
||||
@@ -37,7 +37,7 @@ const ImageToVideo = ({ imageMediaId, imageUrl }: ImageToVideoProps) => {
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="flex h-[calc(100vh-56px)] w-full rounded-lg bg-[#121212]"
|
||||
className="flex h-[calc(100vh-56px)] w-full bg-[#121212]"
|
||||
>
|
||||
<div className="h-full w-full p-4">
|
||||
<div className="flex h-full w-full flex-col items-center justify-center rounded-md pb-12">
|
||||
|
||||
@@ -46,6 +46,23 @@ body {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Tauri custom titlebar drag regions */
|
||||
[data-tauri-drag-region] {
|
||||
-webkit-app-region: drag;
|
||||
app-region: drag;
|
||||
}
|
||||
|
||||
.tauri-no-drag,
|
||||
[data-tauri-drag-region] .no-drag,
|
||||
[data-tauri-drag-region] button,
|
||||
[data-tauri-drag-region] a,
|
||||
[data-tauri-drag-region] input,
|
||||
[data-tauri-drag-region] textarea,
|
||||
[data-tauri-drag-region] select {
|
||||
-webkit-app-region: no-drag;
|
||||
app-region: no-drag;
|
||||
}
|
||||
|
||||
img {
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
|
||||
@@ -84,7 +84,7 @@ export const MenuIconSelector: React.FC<MenuIconSelectorProps> = ({
|
||||
>
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="relative flex gap-1 bg-white/10 border-white/10 border rounded-xl px-1 py-1 min-w-max"
|
||||
className="relative flex gap-1 bg-white/10 border-white/10 border rounded-xl px-1 py-0.5 min-w-max"
|
||||
style={{ minWidth: 0 }}
|
||||
onMouseLeave={() => setHoveredIndex(-1)}
|
||||
>
|
||||
|
||||
@@ -3,19 +3,16 @@
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "../button"
|
||||
},
|
||||
{
|
||||
"path": "../modal"
|
||||
"path": "../../common"
|
||||
},
|
||||
{
|
||||
"path": "../../tauri-events"
|
||||
},
|
||||
{
|
||||
"path": "../../tauri-api"
|
||||
"path": "../button"
|
||||
},
|
||||
{
|
||||
"path": "../../common"
|
||||
"path": "../modal"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
|
||||
@@ -44,19 +44,16 @@
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../button/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../modal/tsconfig.lib.json"
|
||||
"path": "../../common/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../../tauri-events/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../../tauri-api/tsconfig.lib.json"
|
||||
"path": "../button/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../../common/tsconfig.lib.json"
|
||||
"path": "../modal/tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,6 +2,18 @@
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "../components/toaster"
|
||||
},
|
||||
{
|
||||
"path": "../tauri-api"
|
||||
},
|
||||
{
|
||||
"path": "../soundboard"
|
||||
},
|
||||
{
|
||||
"path": "../common"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
|
||||
@@ -41,5 +41,19 @@
|
||||
"src/**/*.jsx",
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../components/toaster/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../tauri-api/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../soundboard/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../common/tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
export * from './api';
|
||||
export { FetchProxy } from './FetchProxy';
|
||||
export { IsDesktopApp } from './IsDesktopApp';
|
||||
export * from "./api";
|
||||
export { FetchProxy } from "./FetchProxy";
|
||||
export { IsDesktopApp } from "./IsDesktopApp";
|
||||
export {
|
||||
useTauriWindowControls,
|
||||
minimizeCurrentWindow,
|
||||
toggleMaximizeCurrentWindow,
|
||||
closeCurrentWindow,
|
||||
isCurrentWindowMaximized,
|
||||
} from "./useWindowControls";
|
||||
export { useTauriPlatform } from "./usePlatform";
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { IsDesktopApp } from "./IsDesktopApp";
|
||||
|
||||
export type TauriPlatform = "windows" | "macos" | "linux";
|
||||
|
||||
export function useTauriPlatform(): TauriPlatform | undefined {
|
||||
const [platform, setPlatform] = useState<TauriPlatform | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!IsDesktopApp()) return;
|
||||
if (typeof navigator !== "undefined") {
|
||||
const ua = navigator.userAgent || "";
|
||||
if (/Macintosh|Mac OS X/i.test(ua)) setPlatform("macos");
|
||||
else if (/Windows/i.test(ua)) setPlatform("windows");
|
||||
else setPlatform("linux");
|
||||
}
|
||||
}, []);
|
||||
|
||||
return platform;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { IsDesktopApp } from "./IsDesktopApp";
|
||||
|
||||
async function getCurrentWindowSafe() {
|
||||
const { getCurrentWindow } = await import("@tauri-apps/api/window");
|
||||
return getCurrentWindow();
|
||||
}
|
||||
|
||||
export function useTauriWindowControls() {
|
||||
const isDesktop = IsDesktopApp();
|
||||
const [isMaximized, setIsMaximized] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDesktop) return;
|
||||
let unlistenMax: (() => void) | undefined;
|
||||
let unlistenUnmax: (() => void) | undefined;
|
||||
let unlistenResize: (() => void) | undefined;
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const win = await getCurrentWindowSafe();
|
||||
setIsMaximized(await win.isMaximized());
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
const { listen } = await import("@tauri-apps/api/event");
|
||||
unlistenMax = await listen("tauri://maximize", () =>
|
||||
setIsMaximized(true)
|
||||
);
|
||||
unlistenUnmax = await listen("tauri://unmaximize", () =>
|
||||
setIsMaximized(false)
|
||||
);
|
||||
unlistenResize = await listen("tauri://resize", async () => {
|
||||
try {
|
||||
const win = await getCurrentWindowSafe();
|
||||
setIsMaximized(await win.isMaximized());
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
})();
|
||||
|
||||
return () => {
|
||||
if (unlistenMax) unlistenMax();
|
||||
if (unlistenUnmax) unlistenUnmax();
|
||||
if (unlistenResize) unlistenResize();
|
||||
};
|
||||
}, [isDesktop]);
|
||||
|
||||
const minimize = useCallback(async () => {
|
||||
if (!isDesktop) return;
|
||||
const win = await getCurrentWindowSafe();
|
||||
await win.minimize();
|
||||
}, [isDesktop]);
|
||||
|
||||
const toggleMaximize = useCallback(async () => {
|
||||
if (!isDesktop) return;
|
||||
const win = await getCurrentWindowSafe();
|
||||
await win.toggleMaximize();
|
||||
}, [isDesktop]);
|
||||
|
||||
const close = useCallback(async () => {
|
||||
if (!isDesktop) return;
|
||||
const win = await getCurrentWindowSafe();
|
||||
await win.close();
|
||||
}, [isDesktop]);
|
||||
|
||||
return { isDesktop, isMaximized, minimize, toggleMaximize, close };
|
||||
}
|
||||
|
||||
export async function minimizeCurrentWindow() {
|
||||
const win = await getCurrentWindowSafe();
|
||||
return win.minimize();
|
||||
}
|
||||
|
||||
export async function toggleMaximizeCurrentWindow() {
|
||||
const win = await getCurrentWindowSafe();
|
||||
return win.toggleMaximize();
|
||||
}
|
||||
|
||||
export async function closeCurrentWindow() {
|
||||
const win = await getCurrentWindowSafe();
|
||||
return win.close();
|
||||
}
|
||||
|
||||
export async function isCurrentWindowMaximized(): Promise<boolean> {
|
||||
const win = await getCurrentWindowSafe();
|
||||
return win.isMaximized();
|
||||
}
|
||||
Reference in New Issue
Block a user