mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-03 00:47:53 +00:00
webapp: mount pagescene at /pagescene with sidebar-aware viewport
Adds /pagescene (and /pagescene/:sceneToken) under the webapp's public chrome (inside ProtectedLayout, outside RequireAuth) so anonymous users can view scenes too. Adapter implementation mirrors the website's, with two webapp-specific tweaks: imports the local useSession / showToast / invalidateSession helpers, and getViewportSize returns the wrapper's live ResizeObserver-measured rect so DnD hit-testing matches the visible canvas (not window.innerWidth). Sidebar handling: the lib's position-fixed UI is scoped to a wrapper div with transform: translateZ(0), which creates a new containing block. The wrapper renders inside SidebarInset's flex flow, so the editor sits naturally to the right of the sidebar and below the topbar; expanded- sidebar behavior is deferred (currently shrinks the page further per the flex layout). Sidebar nav gets an "Edit 3D" entry between Image and Video. Tailwind config gets brand-primary/secondary/tertiary, action color, red/green/ blue DEFAULTs; styles.css adds .bg-ui-panel-gradient, .prevent-select, .dot-typing — same gap-fills landed on the website. No new endpoints. tsconfig churn from nx sync.
This commit is contained in:
1 parent
61c1aa720d
commit
2178afd736
11 files changed
+520
-30
No files matched your search
@@ -15,6 +15,7 @@ import { ToastContainer } from "../components/toast/toast";
|
||||
import CreateImage from "../pages/create-image";
|
||||
import CreateVideo from "../pages/create-video";
|
||||
import CreateVFX from "../pages/create-vfx";
|
||||
import PageScene from "../pages/pagescene";
|
||||
import Pricing from "../pages/pricing";
|
||||
import Support from "../pages/support/support";
|
||||
import Login from "../pages/login";
|
||||
@@ -120,6 +121,8 @@ export function App() {
|
||||
<Route path="/create-image" element={<CreateImage />} />
|
||||
<Route path="/create-video" element={<CreateVideo />} />
|
||||
<Route path="/background-change" element={<CreateVFX />} />
|
||||
<Route path="/pagescene" element={<PageScene />} />
|
||||
<Route path="/pagescene/:sceneToken" element={<PageScene />} />
|
||||
<Route path="/support" element={<Support />} />
|
||||
<Route path="/pricing" element={<Pricing />} />
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
faHouse,
|
||||
faVideo,
|
||||
faImage,
|
||||
faCube,
|
||||
faWandMagicSparkles,
|
||||
faGrid2,
|
||||
faGraduationCap,
|
||||
@@ -41,6 +42,7 @@ const PRIMARY_ITEMS: NavItem[] = [{ label: "Home", href: "/", icon: faHouse }];
|
||||
|
||||
const CREATE_ITEMS: NavItem[] = [
|
||||
{ label: "Image", href: "/create-image", icon: faImage },
|
||||
{ label: "Edit 3D", href: "/pagescene", icon: faCube },
|
||||
{ label: "Video", href: "/create-video", icon: faVideo },
|
||||
{
|
||||
label: "BG Change",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from "./pagescene";
|
||||
@@ -0,0 +1,80 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import {
|
||||
Stage3D,
|
||||
usePageSceneStore,
|
||||
} from "@storyteller/ui-pagescene";
|
||||
import { useSession } from "../../lib/session";
|
||||
import { useWebAppPageSceneAdapter } from "./web-adapter";
|
||||
|
||||
// Stage3D renders its UI with `position: fixed` so its children
|
||||
// (toolbar, prompt editor, history stack, gallery panel) overlay each
|
||||
// other within the editor viewport. Inside the webapp's
|
||||
// SidebarProvider/SidebarInset layout, those `fixed` elements would
|
||||
// escape to the browser viewport and overlap the sidebar/topbar. The
|
||||
// wrapper below applies `transform: translateZ(0)` to create a new
|
||||
// containing block for fixed-positioned descendants, scoping the lib's
|
||||
// UI to the wrapper's box — which is sized by the flex parent
|
||||
// (SidebarInset gives us the area below the topbar and right of the
|
||||
// sidebar).
|
||||
//
|
||||
// As a side effect this also gives us a clean rect to feed the adapter's
|
||||
// `getViewportSize` so DnD hit-testing matches the visible canvas.
|
||||
|
||||
export default function PageScene() {
|
||||
const { sceneToken } = useParams<{ sceneToken?: string }>();
|
||||
const { user } = useSession();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Mirror current user token into lib store so ownership-based gating
|
||||
// (read-only mode, save button visibility) reacts to auth changes.
|
||||
useEffect(() => {
|
||||
usePageSceneStore.getState().setCurrentUserToken(user?.user_token);
|
||||
}, [user?.user_token]);
|
||||
|
||||
const navigateToImageTo3D = useCallback(() => {
|
||||
navigate("/create-image");
|
||||
}, [navigate]);
|
||||
|
||||
// Track the wrapper's rendered size so the adapter's getViewportSize
|
||||
// returns the actual usable area (not window dimensions, which would
|
||||
// include sidebar + topbar).
|
||||
const wrapperRef = useRef<HTMLDivElement | null>(null);
|
||||
const sizeRef = useRef({ width: window.innerWidth, height: window.innerHeight });
|
||||
const [, forceRender] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const node = wrapperRef.current;
|
||||
if (!node) return;
|
||||
const observer = new ResizeObserver((entries) => {
|
||||
const entry = entries[0];
|
||||
if (!entry) return;
|
||||
const { width, height } = entry.contentRect;
|
||||
sizeRef.current = { width, height };
|
||||
// Nudge a re-render so any consumer that reads sizeRef during render
|
||||
// sees the new values; the adapter itself reads through the ref.
|
||||
forceRender((n) => (n + 1) % 1024);
|
||||
});
|
||||
observer.observe(node);
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
const getViewportSize = useCallback(() => sizeRef.current, []);
|
||||
|
||||
const adapter = useWebAppPageSceneAdapter({
|
||||
userToken: user?.user_token,
|
||||
initialSceneToken: sceneToken,
|
||||
navigateToImageTo3D,
|
||||
getViewportSize,
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
className="relative h-full w-full"
|
||||
style={{ transform: "translateZ(0)" }}
|
||||
>
|
||||
<Stage3D adapter={adapter} sceneToken={sceneToken} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
// PageSceneAdapter implementation for the artcraft webapp.
|
||||
//
|
||||
// Mirrors the artcraft-website's adapter but plugs into the webapp's
|
||||
// local session + toast helpers. Built once per <PageScene> mount via
|
||||
// useMemo, keyed on `userToken` + `initialSceneToken` so signing in
|
||||
// mid-session re-arms ownership-based UI gating without unmounting the
|
||||
// editor.
|
||||
//
|
||||
// Anonymous-friendly: when there's no signed-in user, getCurrentUserToken
|
||||
// returns undefined; the lib's read-only gating keeps Save hidden.
|
||||
|
||||
import { useMemo } from "react";
|
||||
import {
|
||||
GetCdnOrigin,
|
||||
MediaFilesApi,
|
||||
MediaUploadApi,
|
||||
StorytellerApiHostStore,
|
||||
UploadImageMedia,
|
||||
UsersApi,
|
||||
} from "@storyteller/api";
|
||||
import type { PageSceneAdapter } from "@storyteller/ui-pagescene";
|
||||
import { ToastTypes } from "@storyteller/ui-pagescene";
|
||||
import {
|
||||
UploadModal3D,
|
||||
UploadModalImage,
|
||||
UploadModalSplat,
|
||||
UploaderStates,
|
||||
} from "@storyteller/ui-upload-modal";
|
||||
import { showToast } from "../../components/toast/toast";
|
||||
import { invalidateSession } from "../../lib/session";
|
||||
|
||||
const apiHost = () =>
|
||||
StorytellerApiHostStore.getInstance().getApiSchemeAndHost();
|
||||
|
||||
// ─── Scene file IO ─────────────────────────────────────────────────────────
|
||||
|
||||
const saveSceneViaApi = async (
|
||||
saveJson: string,
|
||||
sceneTitle: string,
|
||||
sceneToken: string | undefined,
|
||||
sceneThumbnail: Blob | undefined,
|
||||
): Promise<string> => {
|
||||
const blob = new Blob([saveJson], { type: "application/json" });
|
||||
const uploadApi = new MediaUploadApi();
|
||||
const uuid = crypto.randomUUID();
|
||||
const fileName = `${sceneTitle}.glb`;
|
||||
|
||||
const uploadResp = sceneToken
|
||||
? await uploadApi.UploadSavedScene({ blob, fileName, uuid, mediaToken: sceneToken })
|
||||
: await uploadApi.UploadNewScene({
|
||||
blob,
|
||||
fileName,
|
||||
uuid,
|
||||
maybe_title: sceneTitle,
|
||||
});
|
||||
|
||||
if (!uploadResp.success || !uploadResp.data) {
|
||||
showToast("error", uploadResp.errorMessage ?? "Failed to save scene");
|
||||
return "";
|
||||
}
|
||||
|
||||
const newToken = uploadResp.data;
|
||||
if (sceneThumbnail) {
|
||||
try {
|
||||
const coverResp = await uploadApi.UploadImage({
|
||||
blob: sceneThumbnail,
|
||||
fileName: "render.png",
|
||||
uuid: crypto.randomUUID(),
|
||||
maybe_title: "Screenshot",
|
||||
});
|
||||
if (coverResp.success && coverResp.data) {
|
||||
await new MediaFilesApi().UpdateCoverImage({
|
||||
mediaFileToken: newToken,
|
||||
imageToken: coverResp.data,
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
// Cover image is best-effort — the scene is still saved.
|
||||
}
|
||||
}
|
||||
return newToken;
|
||||
};
|
||||
|
||||
const loadSceneViaApi = async (token: string): Promise<unknown> => {
|
||||
const mediaApi = new MediaFilesApi();
|
||||
const meta = await mediaApi.GetMediaFileByToken({ mediaFileToken: token });
|
||||
const cdnUrl = meta.data?.media_links?.cdn_url;
|
||||
if (!cdnUrl) throw new Error("Scene CDN URL missing");
|
||||
|
||||
const fileResp = await fetch(cdnUrl);
|
||||
if (!fileResp.ok) throw new Error(`Scene fetch HTTP ${fileResp.status}`);
|
||||
const text = await fileResp.text();
|
||||
return JSON.parse(text);
|
||||
};
|
||||
|
||||
// ─── Adapter ───────────────────────────────────────────────────────────────
|
||||
|
||||
export interface WebAppPageSceneAdapterOptions {
|
||||
userToken: string | undefined;
|
||||
initialSceneToken: string | undefined;
|
||||
navigateToImageTo3D: () => void;
|
||||
// Wrapper size — kept in a ref so the closure sees live values without
|
||||
// rebuilding the adapter on every resize.
|
||||
getViewportSize: () => { width: number; height: number };
|
||||
}
|
||||
|
||||
export const useWebAppPageSceneAdapter = (
|
||||
options: WebAppPageSceneAdapterOptions,
|
||||
): PageSceneAdapter => {
|
||||
const { userToken, initialSceneToken, navigateToImageTo3D, getViewportSize } = options;
|
||||
|
||||
return useMemo<PageSceneAdapter>(
|
||||
() => ({
|
||||
enqueueGeneration: async () => ({ status: "fail" }),
|
||||
|
||||
saveScene: ({ saveJson, sceneTitle, sceneToken, sceneThumbnail }) =>
|
||||
saveSceneViaApi(saveJson, sceneTitle, sceneToken, sceneThumbnail),
|
||||
|
||||
loadScene: loadSceneViaApi,
|
||||
|
||||
fetchAsset: (url: string) => fetch(url, { mode: "cors" }),
|
||||
|
||||
getCdnOrigin: () => GetCdnOrigin(),
|
||||
getApiSchemeAndHost: apiHost,
|
||||
getCurrentUserToken: () => userToken,
|
||||
|
||||
getCdnUrl: (bucketPath, _width, _quality) =>
|
||||
`${GetCdnOrigin()}${bucketPath}`,
|
||||
|
||||
// The wrapper around <Stage3D> creates a fixed-positioning containing
|
||||
// block sized via the webapp's SidebarInset flex layout. Return its
|
||||
// live size so the lib's DnD hit-testing matches what the user sees,
|
||||
// not raw `window.innerWidth/innerHeight`.
|
||||
getViewportSize,
|
||||
|
||||
listUserMediaFiles: async (query) => {
|
||||
if (!userToken) {
|
||||
return { success: false, data: [], pagination: undefined };
|
||||
}
|
||||
const api = new MediaFilesApi();
|
||||
const response = await api.ListUserMediaFiles({
|
||||
username: userToken,
|
||||
page_size: query.pageSize,
|
||||
page_index: query.pageIndex,
|
||||
// Lib's FilterEngineCategories has a SPLAT variant that the API
|
||||
// enum doesn't yet — cast through unknown is safe at runtime
|
||||
// since the wire format is the same string.
|
||||
filter_engine_categories:
|
||||
query.filterEngineCategories as unknown as never,
|
||||
filter_media_type: query.filterMediaTypes as unknown as never,
|
||||
});
|
||||
return {
|
||||
success: response.success,
|
||||
data: response.data as never,
|
||||
pagination: response.pagination,
|
||||
errorMessage: response.errorMessage,
|
||||
};
|
||||
},
|
||||
|
||||
listFeaturedMediaFiles: async (query) => {
|
||||
const api = new MediaFilesApi();
|
||||
const response = await api.ListFeaturedMediaFiles({
|
||||
page_size: query.pageSize,
|
||||
cursor: query.cursor,
|
||||
filter_engine_categories:
|
||||
query.filterEngineCategories as unknown as never,
|
||||
filter_media_type: query.filterMediaTypes as unknown as never,
|
||||
});
|
||||
return {
|
||||
success: response.success,
|
||||
data: response.data as never,
|
||||
pagination: response.pagination,
|
||||
errorMessage: response.errorMessage,
|
||||
};
|
||||
},
|
||||
|
||||
showToast: (level: ToastTypes, message: string) => {
|
||||
showToast(level === ToastTypes.ERROR ? "error" : "success", message);
|
||||
},
|
||||
|
||||
getMediaUrlByToken: async (token) => {
|
||||
const api = new MediaFilesApi();
|
||||
const response = await api.GetMediaFileByToken({ mediaFileToken: token });
|
||||
return response.data?.media_links?.cdn_url ?? "";
|
||||
},
|
||||
|
||||
renderAssetBrowser: () => null,
|
||||
renderSceneLoader: () => null,
|
||||
renderAssetUploader: (props) => (
|
||||
<UploadModal3D
|
||||
isOpen={props.isOpen}
|
||||
onClose={props.onClose}
|
||||
onSuccess={props.onSuccess}
|
||||
title={props.title}
|
||||
titleIcon={props.titleIcon}
|
||||
/>
|
||||
),
|
||||
renderImageUploader: (props) => (
|
||||
<UploadModalImage
|
||||
isOpen={props.isOpen}
|
||||
onClose={props.onClose}
|
||||
onSuccess={props.onSuccess}
|
||||
title={props.title}
|
||||
titleIcon={props.titleIcon}
|
||||
/>
|
||||
),
|
||||
renderSplatUploader: (props) => (
|
||||
<UploadModalSplat
|
||||
isOpen={props.isOpen}
|
||||
onClose={props.onClose}
|
||||
onSuccess={props.onSuccess}
|
||||
title={props.title}
|
||||
titleIcon={props.titleIcon}
|
||||
/>
|
||||
),
|
||||
|
||||
uploadImage: UploadImageMedia,
|
||||
|
||||
uploadPlaneFromMediaToken: async ({ title, mediaToken, progressCallback }) => {
|
||||
progressCallback({ status: UploaderStates.uploadingAsset });
|
||||
const mediaApi = new MediaFilesApi();
|
||||
const fileResp = await mediaApi.GetMediaFileByToken({ mediaFileToken: mediaToken });
|
||||
if (!fileResp.success || !fileResp.data) {
|
||||
progressCallback({
|
||||
status: UploaderStates.assetError,
|
||||
errorMessage:
|
||||
fileResp.errorMessage ?? "Could not fetch media file by token.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (title && fileResp.data.maybe_title !== title) {
|
||||
const renameResp = await mediaApi.RenameMediaFileByToken({
|
||||
mediaToken,
|
||||
name: title,
|
||||
});
|
||||
if (!renameResp.success) {
|
||||
progressCallback({
|
||||
status: UploaderStates.assetError,
|
||||
errorMessage:
|
||||
renameResp.errorMessage ?? "Could not rename media file.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
progressCallback({ status: UploaderStates.success });
|
||||
},
|
||||
|
||||
navigateToImageTo3D,
|
||||
|
||||
performLogout: async () => {
|
||||
try {
|
||||
await new UsersApi().Logout();
|
||||
} catch {
|
||||
// Best-effort logout — clear local state regardless.
|
||||
}
|
||||
invalidateSession();
|
||||
window.location.href = "/";
|
||||
},
|
||||
|
||||
initialSceneToken,
|
||||
}),
|
||||
[userToken, initialSceneToken, navigateToImageTo3D, getViewportSize],
|
||||
);
|
||||
};
|
||||
@@ -98,6 +98,84 @@
|
||||
filter: invert(1);
|
||||
}
|
||||
|
||||
/* Gradient panel surface used by pagescene + lib components. */
|
||||
.bg-ui-panel-gradient {
|
||||
background:
|
||||
radial-gradient(60.68% 60.68% at 50% 0%,
|
||||
rgba(255, 255, 255, 0.08) 0%,
|
||||
rgba(0, 0, 0, 0) 70%),
|
||||
#1f1f1f;
|
||||
background-color: #1f1f1f;
|
||||
}
|
||||
|
||||
.prevent-select {
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* three-dots loading spinners — used inside upload-modal + pagescene. */
|
||||
.dot-typing {
|
||||
position: relative;
|
||||
left: -9999px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: #ffffff30;
|
||||
color: #ffffff30;
|
||||
box-shadow:
|
||||
9984px 0 0 0 #ffffff30,
|
||||
9999px 0 0 0 #ffffff30,
|
||||
10014px 0 0 0 #ffffff30;
|
||||
animation: dot-typing 1.5s infinite linear;
|
||||
}
|
||||
|
||||
@keyframes dot-typing {
|
||||
0% {
|
||||
box-shadow:
|
||||
9984px 0 0 0 #ffffff30,
|
||||
9999px 0 0 0 #ffffff30,
|
||||
10014px 0 0 0 #ffffff30;
|
||||
}
|
||||
16.667% {
|
||||
box-shadow:
|
||||
9984px -10px 0 0 #ffffff30,
|
||||
9999px 0 0 0 #ffffff30,
|
||||
10014px 0 0 0 #ffffff30;
|
||||
}
|
||||
33.333% {
|
||||
box-shadow:
|
||||
9984px 0 0 0 #ffffff30,
|
||||
9999px 0 0 0 #ffffff30,
|
||||
10014px 0 0 0 #ffffff30;
|
||||
}
|
||||
50% {
|
||||
box-shadow:
|
||||
9984px 0 0 0 #ffffff30,
|
||||
9999px -10px 0 0 #ffffff30,
|
||||
10014px 0 0 0 #ffffff30;
|
||||
}
|
||||
66.667% {
|
||||
box-shadow:
|
||||
9984px 0 0 0 #ffffff30,
|
||||
9999px 0 0 0 #ffffff30,
|
||||
10014px 0 0 0 #ffffff30;
|
||||
}
|
||||
83.333% {
|
||||
box-shadow:
|
||||
9984px 0 0 0 #ffffff30,
|
||||
9999px 0 0 0 #ffffff30,
|
||||
10014px -10px 0 0 #ffffff30;
|
||||
}
|
||||
100% {
|
||||
box-shadow:
|
||||
9984px 0 0 0 #ffffff30,
|
||||
9999px 0 0 0 #ffffff30,
|
||||
10014px 0 0 0 #ffffff30;
|
||||
}
|
||||
}
|
||||
|
||||
.glass {
|
||||
@apply relative border border-white/10 shadow-lg backdrop-blur-xl transition-colors duration-300;
|
||||
@apply bg-ui-controls/85 !important;
|
||||
|
||||
@@ -37,10 +37,10 @@ module.exports = {
|
||||
white: colors.white,
|
||||
gray: colors.gray,
|
||||
black: colors.black,
|
||||
red: colors.red,
|
||||
blue: colors.blue,
|
||||
red: { ...colors.red, DEFAULT: "#D33242" },
|
||||
blue: { ...colors.blue, DEFAULT: "#2E70FF" },
|
||||
orange: colors.orange,
|
||||
green: colors.green,
|
||||
green: { ...colors.green, DEFAULT: "#308752" },
|
||||
emerald: colors.emerald,
|
||||
teal: colors.teal,
|
||||
yellow: colors.yellow,
|
||||
@@ -75,6 +75,62 @@ module.exports = {
|
||||
900: "#64373f",
|
||||
950: "#361b1e",
|
||||
},
|
||||
"brand-primary": {
|
||||
DEFAULT: "#2d81ff",
|
||||
50: "#eef6ff",
|
||||
100: "#d9ebff",
|
||||
200: "#bcdcff",
|
||||
300: "#8ec7ff",
|
||||
400: "#59a7ff",
|
||||
500: "#2d81ff",
|
||||
600: "#1b63f5",
|
||||
700: "#144ee1",
|
||||
800: "#173fb6",
|
||||
900: "#19398f",
|
||||
950: "#142457",
|
||||
},
|
||||
"brand-secondary": {
|
||||
DEFAULT: "#3E3E41",
|
||||
50: "#f6f6f6",
|
||||
100: "#e7e7e7",
|
||||
200: "#d1d1d1",
|
||||
300: "#b0b0b0",
|
||||
400: "#888888",
|
||||
500: "#6d6d6d",
|
||||
600: "#5d5d5d",
|
||||
700: "#4f4f4f",
|
||||
800: "#454545",
|
||||
900: "#3d3d3d",
|
||||
950: "#3E3E41",
|
||||
},
|
||||
"brand-tertiary": {
|
||||
DEFAULT: "#1cb6be",
|
||||
50: "#eefdfc",
|
||||
100: "#d4f9f8",
|
||||
200: "#aef3f3",
|
||||
300: "#62e4e6",
|
||||
400: "#38d3d8",
|
||||
500: "#1cb6be",
|
||||
600: "#1a94a0",
|
||||
700: "#1c7682",
|
||||
800: "#1f616b",
|
||||
900: "#1e505b",
|
||||
950: "#0e353e",
|
||||
},
|
||||
action: {
|
||||
DEFAULT: "#3E3E41",
|
||||
50: "#f6f6f6",
|
||||
100: "#e7e7e7",
|
||||
200: "#d1d1d1",
|
||||
300: "#b0b0b0",
|
||||
400: "#888888",
|
||||
500: "#6d6d6d",
|
||||
600: "#5d5d5d",
|
||||
700: "#4f4f4f",
|
||||
800: "#454545",
|
||||
900: "#3d3d3d",
|
||||
950: "#3E3E41",
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "#3E3E41",
|
||||
50: "#f6f6f6",
|
||||
|
||||
@@ -37,6 +37,12 @@
|
||||
"src/components/footer"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../libs/components/upload-modal/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/pagescene/tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/slider-v2/tsconfig.lib.json"
|
||||
},
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../libs/components/upload-modal"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/pagescene"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/slider-v2"
|
||||
},
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
{
|
||||
"path": "../../libs/components/badge"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/vfx"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/slider-v2"
|
||||
},
|
||||
@@ -55,9 +58,6 @@
|
||||
{
|
||||
"path": "../../libs/components/promptbox"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/vfx"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/menu-icon-selector"
|
||||
},
|
||||
@@ -97,12 +97,6 @@
|
||||
{
|
||||
"path": "../../libs/components/gravatar"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/input"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/upload-modal"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/modal"
|
||||
},
|
||||
@@ -113,7 +107,7 @@
|
||||
"path": "../../libs/components/file-uploader"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/list-dropdown"
|
||||
"path": "../../libs/components/input"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/select"
|
||||
@@ -148,6 +142,9 @@
|
||||
{
|
||||
"path": "../../libs/components/button"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/components/upload-modal"
|
||||
},
|
||||
{
|
||||
"path": "../../libs/tauri-api"
|
||||
},
|
||||
|
||||
@@ -5,45 +5,42 @@
|
||||
{
|
||||
"path": "../slider-v2"
|
||||
},
|
||||
{
|
||||
"path": "../../api"
|
||||
},
|
||||
{
|
||||
"path": "../promptbox"
|
||||
},
|
||||
{
|
||||
"path": "../../api-enums"
|
||||
},
|
||||
{
|
||||
"path": "../../model-list"
|
||||
},
|
||||
{
|
||||
"path": "../action-reminder-modal"
|
||||
},
|
||||
{
|
||||
"path": "../tooltip"
|
||||
},
|
||||
{
|
||||
"path": "../modal"
|
||||
},
|
||||
{
|
||||
"path": "../model-selector"
|
||||
},
|
||||
{
|
||||
"path": "../pricing-modal"
|
||||
},
|
||||
{
|
||||
"path": "../help-menu"
|
||||
},
|
||||
{
|
||||
"path": "../model-selector"
|
||||
},
|
||||
{
|
||||
"path": "../../model-list"
|
||||
},
|
||||
{
|
||||
"path": "../../common"
|
||||
},
|
||||
{
|
||||
"path": "../../api"
|
||||
"path": "../action-reminder-modal"
|
||||
},
|
||||
{
|
||||
"path": "../gallery-modal"
|
||||
"path": "../tooltip"
|
||||
},
|
||||
{
|
||||
"path": "../button"
|
||||
},
|
||||
{
|
||||
"path": "../modal"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user