mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-06 02:00:46 +00:00
Port over more components as libs for PromptBox
This commit is contained in:
1 parent
6190416514
commit
df7b45f62d
59 files changed
+1785
-927
No files matched your search
@@ -2,3 +2,4 @@ export * from "./lib/EditorState";
|
||||
export * from "./lib/Queue";
|
||||
export * from "./lib/UploaderStates";
|
||||
export * from "./lib/Hotkeys";
|
||||
export * from "./lib/Toaster";
|
||||
@@ -0,0 +1,10 @@
|
||||
export enum AssetType {
|
||||
ANIMATION = "animation",
|
||||
AUDIO = "audio",
|
||||
CAMERA = "camera",
|
||||
CHARACTER = "character",
|
||||
EXPRESSION = "expression",
|
||||
OBJECT = "object",
|
||||
SKYBOX = "skybox",
|
||||
SHAPE = "shape",
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export enum ClipGroup {
|
||||
CHARACTER = "character",
|
||||
CAMERA = "camera",
|
||||
GLOBAL_AUDIO = "global_audio",
|
||||
OBJECT = "object",
|
||||
PROMPT_TRAVEL = "prompt",
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export enum ClipType {
|
||||
TRANSFORM = "transform",
|
||||
AUDIO = "audio",
|
||||
ANIMATION = "animation",
|
||||
EXPRESSION = "expression",
|
||||
FAKE = "fake",
|
||||
PROMPT_TRAVEL = "prompt",
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
export enum fromEngineActions {
|
||||
ADD_OBJECT = "add_object",
|
||||
CAMERA_ASPECT_RATIO_CHANGED = "camera_aspect_ratio_changed",
|
||||
// data = CameraAspectRatio
|
||||
DELETE_OBJECT = "delete_object",
|
||||
DESELECT_OBJECT = "deselect_object",
|
||||
RESET_TIMELINE = "reset_timeline",
|
||||
SELECT_OBJECT = "select_object",
|
||||
UPDATE_CHARACTER_ID = "update_character_id",
|
||||
UPDATE_TIME = "update_time",
|
||||
UPDATE_TIME_LINE = "update_timeline",
|
||||
POP_A_TOAST = "pop_a_toast",
|
||||
// data={currentTime: number}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
export enum toEngineActions {
|
||||
ADD_CLIP = "add_clip",
|
||||
// data=QueueClip
|
||||
ADD_KEYFRAME = "add_keyframe",
|
||||
|
||||
ADD_CHARACTER = "add_character",
|
||||
|
||||
ADD_OBJECT = "add_object",
|
||||
|
||||
ADD_SHAPE = "add_shape",
|
||||
|
||||
// data= QueueKeyframe
|
||||
DELETE_CLIP = "delete_clip",
|
||||
// data=QueueClip
|
||||
DELETE_KEYFRAME = "delete_keyframe",
|
||||
// data=QueueKeyframe
|
||||
ENTER_EDIT_STATE = "enter_edit",
|
||||
// data=null
|
||||
ENTER_PREVIEW_STATE = "enter_preview",
|
||||
// data=null
|
||||
GENERATE_VIDEO = "generate_video",
|
||||
// data=null
|
||||
MUTE = "mute",
|
||||
// data={version, type, group, object_uuid} if lipsync
|
||||
// data={version, type, group} if global_audio
|
||||
REFRESH_PREVIEW = "refresh_preview",
|
||||
// data=QueueClip
|
||||
TOGGLE_CAMERA_STATE = "toggle_camera",
|
||||
// data=null
|
||||
TOGGLE_REPEATING = "toggle_repeating",
|
||||
// data=null
|
||||
|
||||
CHANGE_CAMERA_ASPECT_RATIO = "change_camera_aspect_ratio",
|
||||
// data=CamperaAspectRatio
|
||||
|
||||
CAMERA_CHANGED = "camera_changed",
|
||||
|
||||
UNMUTE = "unmute",
|
||||
// data={version, type, group, object_uuid} if lipsync
|
||||
// data={version, type, group} if global_audio
|
||||
UPDATE_CLIP = "update_clip",
|
||||
// data=QueueClip
|
||||
UPDATE_KEYFRAME = "update_keyframe",
|
||||
// data=QueueKeyframe
|
||||
UPDATE_TIME = "update_time",
|
||||
// data={currentTime: number}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export enum toTimelineActions {
|
||||
ADD_KEYFRAME = "add_keyframe",
|
||||
GENERATE_PROGRESS = "generate_progress",
|
||||
}
|
||||
@@ -1 +1,7 @@
|
||||
export * from "./AssetType";
|
||||
export * from "./QueueNames";
|
||||
export * from "./FromEngineActions";
|
||||
export * from "./ToEngineActions";
|
||||
export * from "./ToTimelineActions";
|
||||
export * from "./ClipType";
|
||||
export * from "./ClipGroup";
|
||||
@@ -0,0 +1,5 @@
|
||||
export enum ToastTypes {
|
||||
SUCCESS,
|
||||
WARNING,
|
||||
ERROR,
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./ToastTypes";
|
||||
@@ -1,2 +1,8 @@
|
||||
export * from "./lib/Camera";
|
||||
export * from "./lib/UploadImage";
|
||||
export * from "./lib/IGenerationOptions";
|
||||
export * from "./lib/UpdateTime";
|
||||
export * from "./lib/Queue";
|
||||
export * from "./lib/MediaItem";
|
||||
export * from "./lib/UploadImage";
|
||||
export * from "./lib/UploadedState";
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface IGenerationOptions {
|
||||
upscale: boolean;
|
||||
faceDetail: boolean;
|
||||
styleStrength: number;
|
||||
lipSync: boolean;
|
||||
cinematic: boolean;
|
||||
globalIpAdapterImageMediaToken: string | null;
|
||||
enginePreProcessing: boolean;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { AssetType } from "@storyteller/enums";
|
||||
|
||||
export interface MediaItem {
|
||||
version: number;
|
||||
type: AssetType;
|
||||
maybe_animation_type?: string;
|
||||
media_type?: string;
|
||||
media_id: string;
|
||||
object_uuid?: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
publicBucketPath?: string;
|
||||
length?: number;
|
||||
thumbnail?: string;
|
||||
isMine?: boolean;
|
||||
isBookmarked?: boolean;
|
||||
imageIndex?: number;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { ClipGroup, ClipType } from "@storyteller/enums";
|
||||
import { XYZ } from "@storyteller/types";
|
||||
|
||||
export interface QueueClip {
|
||||
version: number;
|
||||
type: ClipType;
|
||||
group: ClipGroup;
|
||||
object_uuid?: string;
|
||||
clip_uuid?: string;
|
||||
media_id?: string;
|
||||
name?: string;
|
||||
offset?: number;
|
||||
length?: number;
|
||||
selected?: boolean;
|
||||
}
|
||||
|
||||
export interface QueueKeyframe {
|
||||
version: number;
|
||||
keyframe_uuid?: string;
|
||||
group: ClipGroup;
|
||||
object_uuid: string;
|
||||
object_name?: string;
|
||||
offset?: number;
|
||||
position: XYZ;
|
||||
rotation: XYZ;
|
||||
scale: XYZ;
|
||||
selected?: boolean;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface UpdateTime {
|
||||
currentTime: number;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@nx/react/babel",
|
||||
{
|
||||
"runtime": "automatic",
|
||||
"useBuiltIns": "usage"
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# @storyteller/types
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test @storyteller/types` to execute the unit tests via [Vitest](https://vitest.dev/).
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@storyteller/types",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"development": "./src/index.ts",
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './lib';
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './queue';
|
||||
export * from './toast';
|
||||
export * from './xyz';
|
||||
@@ -0,0 +1,114 @@
|
||||
import { QueueNames, toTimelineActions, CameraAspectRatio, fromEngineActions, toEngineActions } from "@storyteller/enums";
|
||||
|
||||
import { IGenerationOptions, UpdateTime, QueueClip, QueueKeyframe, MediaItem } from "@storyteller/interfaces";
|
||||
import { ToastDataType } from "@storyteller/types";
|
||||
|
||||
export type UnionedActionTypes =
|
||||
| fromEngineActions
|
||||
| toEngineActions
|
||||
| toTimelineActions;
|
||||
|
||||
export type UnionedDataTypes =
|
||||
| QueueClip
|
||||
| UpdateTime
|
||||
| QueueKeyframe
|
||||
| MediaItem
|
||||
| ToastDataType
|
||||
| IGenerationOptions
|
||||
| CameraAspectRatio
|
||||
| null;
|
||||
|
||||
export type QueueSubscribeType = {
|
||||
action: UnionedActionTypes;
|
||||
data: UnionedDataTypes;
|
||||
};
|
||||
|
||||
export type SubscribeHandler = (entry: {
|
||||
action: UnionedActionTypes;
|
||||
data: UnionedDataTypes;
|
||||
}) => void;
|
||||
|
||||
class Queue {
|
||||
private _queues: Record<
|
||||
QueueNames,
|
||||
Array<{
|
||||
action: UnionedActionTypes;
|
||||
data: UnionedDataTypes;
|
||||
}>
|
||||
> = {
|
||||
[QueueNames.FROM_ENGINE]: [],
|
||||
[QueueNames.TO_ENGINE]: [],
|
||||
[QueueNames.TO_TIMELINE]: []
|
||||
};
|
||||
|
||||
private _subscribers: Record<
|
||||
QueueNames,
|
||||
Map<
|
||||
string,
|
||||
SubscribeHandler
|
||||
>
|
||||
> = {
|
||||
[QueueNames.FROM_ENGINE]: new Map<string, SubscribeHandler>(),
|
||||
[QueueNames.TO_ENGINE]: new Map<string, SubscribeHandler>(),
|
||||
[QueueNames.TO_TIMELINE]: new Map<string, SubscribeHandler>(),
|
||||
};
|
||||
|
||||
// Enqueues actions to a specified queue
|
||||
public publish({
|
||||
queueName,
|
||||
action,
|
||||
data,
|
||||
}: {
|
||||
queueName: QueueNames;
|
||||
action: UnionedActionTypes;
|
||||
data: UnionedDataTypes;
|
||||
}) {
|
||||
// Queues for all QueueNames should be initialized above but this is a safeguard for future enum additions
|
||||
// Make sure the queue exists
|
||||
if (!this._queues[queueName]) {
|
||||
this._queues[queueName] = [];
|
||||
}
|
||||
|
||||
// Queue the task in the right queue
|
||||
this._queues[queueName].push({ action, data });
|
||||
|
||||
// TODO: Ideally the publisher shouldn't deal at all with the subscribers
|
||||
// It should only publish the events to the right queue
|
||||
// It also doesn't make sense to fire an event on publish because the operations are then dispersed
|
||||
// leading to potential race conditions
|
||||
// FIXME: Add some sort of queue loop using internal event and add queue locks using promises to serialize queue publishes
|
||||
if (this._subscribers[queueName]) {
|
||||
this._subscribers[queueName].forEach((subcribeHandler) =>
|
||||
subcribeHandler(this._queues[queueName][0]),
|
||||
);
|
||||
this._queues[queueName].shift();
|
||||
}
|
||||
}
|
||||
|
||||
public subscribe(
|
||||
queueName: QueueNames,
|
||||
id: string,
|
||||
onMessage: (entry: QueueSubscribeType) => void,
|
||||
) {
|
||||
|
||||
// Queues for all QueueNames should be initialized above but this is a safeguard for future enum additions
|
||||
// Make sure the queue exists
|
||||
if (!this._subscribers[queueName]) {
|
||||
this._subscribers[queueName] = new Map<string, SubscribeHandler>();
|
||||
}
|
||||
|
||||
// Set the handler mapped to the ID
|
||||
this._subscribers[queueName].set(id, onMessage);
|
||||
|
||||
while (this._queues[queueName]?.length) {
|
||||
this._subscribers[queueName].forEach((subscribeHandler) =>
|
||||
subscribeHandler(this._queues[queueName][0]),
|
||||
);
|
||||
this._queues[queueName].shift();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const queue = new Queue();
|
||||
|
||||
export default queue;
|
||||
@@ -0,0 +1,6 @@
|
||||
import { ToastTypes } from "@storyteller/enums";
|
||||
|
||||
export type ToastDataType = {
|
||||
type: ToastTypes;
|
||||
message: string;
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
export type XYZ = {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
};
|
||||
|
||||
export type Simple3DVector = {
|
||||
position: XYZ;
|
||||
rotation: XYZ;
|
||||
scale: XYZ;
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
],
|
||||
"extends": "../../../tsconfig.base.json"
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"types": [
|
||||
"node",
|
||||
"@nx/react/typings/cssmodule.d.ts",
|
||||
"@nx/react/typings/image.d.ts",
|
||||
"vite/client"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"jsx": "react-jsx",
|
||||
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo"
|
||||
},
|
||||
"exclude": [
|
||||
"out-tsc",
|
||||
"dist",
|
||||
"**/*.spec.ts",
|
||||
"**/*.test.ts",
|
||||
"**/*.spec.tsx",
|
||||
"**/*.test.tsx",
|
||||
"**/*.spec.js",
|
||||
"**/*.test.js",
|
||||
"**/*.spec.jsx",
|
||||
"**/*.test.jsx",
|
||||
"vite.config.ts",
|
||||
"vite.config.mts",
|
||||
"vitest.config.ts",
|
||||
"vitest.config.mts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.jsx",
|
||||
"src/**/*.spec.jsx"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.js",
|
||||
"src/**/*.jsx",
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/vitest",
|
||||
"types": [
|
||||
"vitest/globals",
|
||||
"vitest/importMeta",
|
||||
"vite/client",
|
||||
"node",
|
||||
"vitest"
|
||||
],
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": [
|
||||
"vite.config.ts",
|
||||
"vite.config.mts",
|
||||
"vitest.config.ts",
|
||||
"vitest.config.mts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.jsx",
|
||||
"src/**/*.spec.jsx",
|
||||
"src/**/*.d.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/// <reference types='vitest' />
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import dts from 'vite-plugin-dts';
|
||||
import * as path from 'path';
|
||||
|
||||
export default defineConfig(() => ({
|
||||
root: __dirname,
|
||||
cacheDir: '../../../node_modules/.vite/libs/common/types',
|
||||
plugins: [react(), dts({ entryRoot: 'src', tsconfigPath: path.join(__dirname, 'tsconfig.lib.json') })],
|
||||
// Uncomment this if you are using workers.
|
||||
// worker: {
|
||||
// plugins: [ nxViteTsPaths() ],
|
||||
// },
|
||||
// Configuration for building your library.
|
||||
// See: https://vitejs.dev/guide/build.html#library-mode
|
||||
build: {
|
||||
outDir: './dist',
|
||||
emptyOutDir: true,
|
||||
reportCompressedSize: true,
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true,
|
||||
},
|
||||
lib: {
|
||||
// Could also be a dictionary or array of multiple entry points.
|
||||
entry: 'src/index.ts',
|
||||
name: '@storyteller/types',
|
||||
fileName: 'index',
|
||||
// Change this to the formats you want to support.
|
||||
// Don't forget to update your package.json as well.
|
||||
formats: ['es' as const]
|
||||
},
|
||||
rollupOptions: {
|
||||
// External packages that should not be bundled into your library.
|
||||
external: ['react','react-dom','react/jsx-runtime']
|
||||
},
|
||||
},
|
||||
test: {
|
||||
watch: false,
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
reporters: ['default'],
|
||||
coverage: {
|
||||
reportsDirectory: './test-output/vitest/coverage',
|
||||
provider: 'v8' as const,
|
||||
}
|
||||
},
|
||||
}));
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@nx/react/babel",
|
||||
{
|
||||
"runtime": "automatic",
|
||||
"useBuiltIns": "usage"
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# @storyteller/ui-camera-settings-modal
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test @storyteller/ui-camera-settings-modal` to execute the unit tests via [Vitest](https://vitest.dev/).
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@storyteller/ui-camera-settings-modal",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"development": "./src/index.ts",
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
export * from './lib/camera-settings-modal';
|
||||
@@ -0,0 +1,236 @@
|
||||
import { TransitionDialogue } from "@storyteller/ui-transition-dialogue";
|
||||
import { faPlus, faTrashAlt } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { PopoverItem } from "@storyteller/ui-popover"
|
||||
import { Button } from "@storyteller/ui-button";
|
||||
import { Input } from "@storyteller/ui-input";
|
||||
import { Label } from "@storyteller/ui-label";
|
||||
import { Tooltip } from "@storyteller/ui-tooltip";
|
||||
import { SliderV2 } from "@storyteller/ui-sliderv2";
|
||||
import { useState, useEffect } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { Signal } from "@preact/signals-react";
|
||||
|
||||
interface ExtendedPopoverItem extends PopoverItem {
|
||||
id: string;
|
||||
focalLength: number;
|
||||
position: { x: number; y: number; z: number };
|
||||
rotation: { x: number; y: number; z: number };
|
||||
lookAt: { x: number; y: number; z: number };
|
||||
}
|
||||
|
||||
interface CameraSettingsModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
cameras: ExtendedPopoverItem[];
|
||||
onCameraNameChange: (id: string, newName: string) => void;
|
||||
onCameraFocalLengthChange: (id: string, value: number) => void;
|
||||
onAddCamera: () => void;
|
||||
selectedCameraId: string;
|
||||
handleCameraSelect: (selectedItem: PopoverItem) => void;
|
||||
onDeleteCamera: (id: string) => void;
|
||||
focalLengthDragging: Signal;
|
||||
disableHotkeyInput: (level: number) => void;
|
||||
enableHotkeyInput: (level: number) => void;
|
||||
}
|
||||
|
||||
export const CameraSettingsModal = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
cameras,
|
||||
onCameraNameChange,
|
||||
onCameraFocalLengthChange,
|
||||
onAddCamera,
|
||||
selectedCameraId,
|
||||
handleCameraSelect,
|
||||
onDeleteCamera,
|
||||
focalLengthDragging,
|
||||
disableHotkeyInput,
|
||||
enableHotkeyInput,
|
||||
}: CameraSettingsModalProps) => {
|
||||
const selectedCamera = cameras.find((cam) => cam.id === selectedCameraId);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [tempCameraName, setTempCameraName] = useState<string>("");
|
||||
const [editingCameraId, setEditingCameraId] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedCamera) {
|
||||
setTempCameraName(selectedCamera.label);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedCamera?.id]);
|
||||
|
||||
useEffect(() => {
|
||||
const handlePointerUp = () => {
|
||||
setIsDragging(false);
|
||||
focalLengthDragging.value = {
|
||||
isDragging: false,
|
||||
focalLength: selectedCamera?.focalLength || 35,
|
||||
};
|
||||
};
|
||||
document.addEventListener("pointerup", handlePointerUp);
|
||||
return () => document.removeEventListener("pointerup", handlePointerUp);
|
||||
}, [selectedCamera?.focalLength]);
|
||||
|
||||
const handlePointerDown = () => {
|
||||
setIsDragging(true);
|
||||
focalLengthDragging.value = {
|
||||
isDragging: true,
|
||||
focalLength: selectedCamera?.focalLength || 35,
|
||||
};
|
||||
};
|
||||
|
||||
const handleFocalLengthChange = (id: string, value: number) => {
|
||||
focalLengthDragging.value = { isDragging: true, focalLength: value };
|
||||
onCameraFocalLengthChange(id, value);
|
||||
};
|
||||
|
||||
const handleNameBlur = () => {
|
||||
if (selectedCamera && tempCameraName.trim() !== "") {
|
||||
onCameraNameChange(selectedCamera.id, tempCameraName);
|
||||
} else if (selectedCamera) {
|
||||
setTempCameraName(selectedCamera.label);
|
||||
}
|
||||
setEditingCameraId(null);
|
||||
};
|
||||
|
||||
const handleNameFocus = (id: string) => {
|
||||
setEditingCameraId(id);
|
||||
};
|
||||
|
||||
return (
|
||||
<TransitionDialogue
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
className={twMerge(
|
||||
"h-[500px] max-w-3xl duration-200",
|
||||
isDragging ? "opacity-10" : "opacity-100",
|
||||
)}
|
||||
backdropClassName={twMerge(
|
||||
"duration-200",
|
||||
isDragging ? "opacity-0" : "opacity-100",
|
||||
)}
|
||||
childPadding={false}
|
||||
disableHotkeyInput={disableHotkeyInput}
|
||||
enableHotkeyInput={enableHotkeyInput}
|
||||
>
|
||||
<div className="grid h-full grid-cols-12 gap-3">
|
||||
<div className="relative col-span-4 p-3 pt-2 after:absolute after:right-0 after:top-0 after:h-full after:w-px after:bg-gray-200 after:dark:bg-white/10">
|
||||
<div className="flex items-center justify-between gap-2.5 py-0.5">
|
||||
<h2 className="text-[18px] font-semibold opacity-80">Camera</h2>
|
||||
<Tooltip content="Add camera" position="top" delay={200}>
|
||||
<button
|
||||
className="h-6 w-6 rounded-full text-white/70 transition-colors hover:text-white/100"
|
||||
onClick={onAddCamera}
|
||||
>
|
||||
<FontAwesomeIcon icon={faPlus} className="text-xl" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<hr className="my-2 w-full border-white/10" />
|
||||
<div className="space-y-1">
|
||||
{cameras.map((camera) => (
|
||||
<button
|
||||
key={camera.id}
|
||||
className={`h-9 w-full rounded-lg p-2 text-left transition-colors duration-100 hover:bg-[#63636B]/40 ${camera.id === selectedCameraId ? "bg-[#63636B]/40" : ""
|
||||
}`}
|
||||
onClick={() => handleCameraSelect(camera)}
|
||||
>
|
||||
<div className="flex items-center gap-2.5 text-sm">
|
||||
{camera.icon}
|
||||
{editingCameraId === camera.id
|
||||
? tempCameraName
|
||||
: camera.label}
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-8 p-3 ps-0 pt-2">
|
||||
<div className="flex h-full flex-col">
|
||||
<div>
|
||||
<div className="flex items-center justify-between gap-2.5 py-0.5 opacity-100">
|
||||
<h2 className="text-[18px] font-semibold">
|
||||
{selectedCamera?.label || "Camera"}
|
||||
</h2>
|
||||
<Tooltip
|
||||
content={
|
||||
selectedCamera?.id === "main"
|
||||
? "Cannot delete the main camera"
|
||||
: "Delete camera"
|
||||
}
|
||||
position="top"
|
||||
delay={200}
|
||||
>
|
||||
<button
|
||||
className={`h-6 w-6 rounded-lg transition-colors ${selectedCamera?.id === "main"
|
||||
? "cursor-not-allowed text-white/30"
|
||||
: "text-white/60 hover:text-white/100"
|
||||
}`}
|
||||
onClick={() =>
|
||||
selectedCamera &&
|
||||
selectedCamera.id !== "main" &&
|
||||
onDeleteCamera(selectedCamera.id)
|
||||
}
|
||||
disabled={selectedCamera?.id === "main"}
|
||||
>
|
||||
<FontAwesomeIcon icon={faTrashAlt} className="text-lg" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<hr className="my-2 w-full border-white/10" />
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="camera-name" className="text-sm opacity-70">
|
||||
Name
|
||||
</Label>
|
||||
<Input
|
||||
id="camera-name"
|
||||
type="text"
|
||||
value={tempCameraName}
|
||||
onChange={(e) => setTempCameraName(e.target.value)}
|
||||
onBlur={handleNameBlur}
|
||||
onFocus={() =>
|
||||
selectedCamera && handleNameFocus(selectedCamera.id)
|
||||
}
|
||||
className="text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="focal-length" className="text-sm opacity-70">
|
||||
Focal Length
|
||||
</Label>
|
||||
<div
|
||||
className="mt-1 flex items-center gap-4"
|
||||
onPointerDown={handlePointerDown}
|
||||
>
|
||||
<SliderV2
|
||||
min={10}
|
||||
max={200}
|
||||
value={selectedCamera?.focalLength || 35}
|
||||
onChange={(value) =>
|
||||
selectedCamera &&
|
||||
handleFocalLengthChange(selectedCamera.id, value)
|
||||
}
|
||||
step={1}
|
||||
suffix="mm"
|
||||
showDecrement={true}
|
||||
showIncrement={true}
|
||||
className="w-full"
|
||||
/>
|
||||
<span className="min-w-[60px] text-sm">
|
||||
{selectedCamera?.focalLength || 35}mm
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-auto flex justify-end pt-4">
|
||||
<Button onClick={onClose}>Done</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</TransitionDialogue>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
],
|
||||
"extends": "../../../tsconfig.base.json"
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"types": [
|
||||
"node",
|
||||
"@nx/react/typings/cssmodule.d.ts",
|
||||
"@nx/react/typings/image.d.ts",
|
||||
"vite/client"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"jsx": "react-jsx",
|
||||
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo"
|
||||
},
|
||||
"exclude": [
|
||||
"out-tsc",
|
||||
"dist",
|
||||
"**/*.spec.ts",
|
||||
"**/*.test.ts",
|
||||
"**/*.spec.tsx",
|
||||
"**/*.test.tsx",
|
||||
"**/*.spec.js",
|
||||
"**/*.test.js",
|
||||
"**/*.spec.jsx",
|
||||
"**/*.test.jsx",
|
||||
"vite.config.ts",
|
||||
"vite.config.mts",
|
||||
"vitest.config.ts",
|
||||
"vitest.config.mts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.jsx",
|
||||
"src/**/*.spec.jsx"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.js",
|
||||
"src/**/*.jsx",
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/vitest",
|
||||
"types": [
|
||||
"vitest/globals",
|
||||
"vitest/importMeta",
|
||||
"vite/client",
|
||||
"node",
|
||||
"vitest"
|
||||
],
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": [
|
||||
"vite.config.ts",
|
||||
"vite.config.mts",
|
||||
"vitest.config.ts",
|
||||
"vitest.config.mts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.jsx",
|
||||
"src/**/*.spec.jsx",
|
||||
"src/**/*.d.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/// <reference types='vitest' />
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import dts from 'vite-plugin-dts';
|
||||
import * as path from 'path';
|
||||
|
||||
export default defineConfig(() => ({
|
||||
root: __dirname,
|
||||
cacheDir: '../../../node_modules/.vite/libs/components/camera-settings-modal',
|
||||
plugins: [react(), dts({ entryRoot: 'src', tsconfigPath: path.join(__dirname, 'tsconfig.lib.json') })],
|
||||
// Uncomment this if you are using workers.
|
||||
// worker: {
|
||||
// plugins: [ nxViteTsPaths() ],
|
||||
// },
|
||||
// Configuration for building your library.
|
||||
// See: https://vitejs.dev/guide/build.html#library-mode
|
||||
build: {
|
||||
outDir: './dist',
|
||||
emptyOutDir: true,
|
||||
reportCompressedSize: true,
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true,
|
||||
},
|
||||
lib: {
|
||||
// Could also be a dictionary or array of multiple entry points.
|
||||
entry: 'src/index.ts',
|
||||
name: '@storyteller/ui-camera-settings-modal',
|
||||
fileName: 'index',
|
||||
// Change this to the formats you want to support.
|
||||
// Don't forget to update your package.json as well.
|
||||
formats: ['es' as const]
|
||||
},
|
||||
rollupOptions: {
|
||||
// External packages that should not be bundled into your library.
|
||||
external: ['react','react-dom','react/jsx-runtime']
|
||||
},
|
||||
},
|
||||
test: {
|
||||
watch: false,
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
reporters: ['default'],
|
||||
coverage: {
|
||||
reportsDirectory: './test-output/vitest/coverage',
|
||||
provider: 'v8' as const,
|
||||
}
|
||||
},
|
||||
}));
|
||||
@@ -1 +1 @@
|
||||
export * from "./lib/PromptBox";
|
||||
export * from "./lib/PromptBox3D";
|
||||
@@ -1,11 +0,0 @@
|
||||
interface PromptBoxProps {
|
||||
is3D: boolean;
|
||||
}
|
||||
|
||||
export const PromptBox = ({
|
||||
is3D
|
||||
}: PromptBoxProps) => {
|
||||
return (
|
||||
{is3D ?? PromptBox3D : PromptBox2D}
|
||||
);
|
||||
};
|
||||
@@ -52,7 +52,7 @@ import {
|
||||
UploadImageArgs,
|
||||
} from "@storyteller/interfaces";
|
||||
import { EngineApi } from "@storyteller/api";
|
||||
import { CameraSettingsModal } from "../CameraSettingsModal";
|
||||
import { CameraSettingsModal } from "@storyteller/ui-camera-settings-modal";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { GalleryModal, GalleryItem } from "@storyteller/ui-gallery-modal";
|
||||
import { Modal } from "@storyteller/ui-modal";
|
||||
@@ -66,22 +66,20 @@ interface PromptBox3DProps {
|
||||
gridVisibility: Signal<boolean>;
|
||||
setGridVisibility: (isVisible: boolean) => void;
|
||||
selectedCameraId: Signal<string>;
|
||||
addCamera: (cam: Camera) => void;
|
||||
updateCamera: (id: string, updates: Partial<Camera>) => void;
|
||||
deleteCamera: (id: string) => void;
|
||||
focalLengthDragging: Signal<FocalLengthDragging>;
|
||||
isPromptBoxFocused: Signal<boolean>;
|
||||
uploadImage: (arg: UploadImageArgs) => Promise<void>;
|
||||
handleCameraSelect: (item: PopoverItem) => void;
|
||||
handleAddCamera: () => void;
|
||||
handleCameraNameChange: (name: string) => void;
|
||||
handleCameraNameChange: (id: string, newName: string) => void;
|
||||
handleCameraFocalLengthChange: (id: string, value: number) => void;
|
||||
handleAspectRatioSelect: (selectedItem: PopoverItem) => void;
|
||||
onAspectRatioSelect: (newRatio: CameraAspectRatio) => void;
|
||||
setEnginePrompt: (prompt: string) => void;
|
||||
snapshotCurrentFrame: (shouldDownload?: boolean) => {
|
||||
snapshotCurrentFrame: ((shouldDownload?: boolean) => {
|
||||
base64Snapshot: string;
|
||||
file: File;
|
||||
} | null;
|
||||
} | null) | undefined;
|
||||
}
|
||||
|
||||
export const PromptBox3D = ({
|
||||
@@ -92,8 +90,6 @@ export const PromptBox3D = ({
|
||||
gridVisibility,
|
||||
setGridVisibility,
|
||||
selectedCameraId,
|
||||
addCamera,
|
||||
updateCamera,
|
||||
deleteCamera,
|
||||
focalLengthDragging,
|
||||
isPromptBoxFocused,
|
||||
@@ -102,7 +98,7 @@ export const PromptBox3D = ({
|
||||
handleAddCamera,
|
||||
handleCameraNameChange,
|
||||
handleCameraFocalLengthChange,
|
||||
handleAspectRatioSelect,
|
||||
onAspectRatioSelect,
|
||||
setEnginePrompt,
|
||||
snapshotCurrentFrame,
|
||||
}: PromptBox3DProps) => {
|
||||
@@ -169,6 +165,37 @@ export const PromptBox3D = ({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [cameraAspectRatio.value]);
|
||||
|
||||
const handleAspectRatioSelect = (selectedItem: PopoverItem) => {
|
||||
setAspectRatioList((prev) =>
|
||||
prev.map((item) => ({
|
||||
...item,
|
||||
selected: item.label === selectedItem.label,
|
||||
})),
|
||||
);
|
||||
|
||||
// Map the selected label to the corresponding CameraAspectRatio enum value
|
||||
let newRatio: CameraAspectRatio;
|
||||
switch (selectedItem.label) {
|
||||
case "16:9":
|
||||
newRatio = CameraAspectRatio.HORIZONTAL_16_9;
|
||||
break;
|
||||
case "3:2":
|
||||
newRatio = CameraAspectRatio.HORIZONTAL_3_2;
|
||||
break;
|
||||
case "2:3":
|
||||
newRatio = CameraAspectRatio.VERTICAL_2_3;
|
||||
break;
|
||||
case "1:1":
|
||||
newRatio = CameraAspectRatio.SQUARE_1_1;
|
||||
break;
|
||||
default:
|
||||
newRatio = CameraAspectRatio.HORIZONTAL_16_9;
|
||||
}
|
||||
|
||||
onAspectRatioSelect(newRatio);
|
||||
};
|
||||
|
||||
|
||||
const handleFileUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const files = event.target.files;
|
||||
if (files) {
|
||||
@@ -314,44 +341,46 @@ export const PromptBox3D = ({
|
||||
//const engineApi = new EngineApi();
|
||||
const promptsApi = new PromptsApi();
|
||||
|
||||
const snapshot = snapshotCurrentFrame(false);
|
||||
if (snapshotCurrentFrame) {
|
||||
const snapshot = snapshotCurrentFrame(false);
|
||||
|
||||
if (snapshot) {
|
||||
const snapshotResult = await promptsApi.uploadSceneSnapshot({
|
||||
screenshot: snapshot.file,
|
||||
sceneMediaToken: "",
|
||||
});
|
||||
if (snapshot) {
|
||||
const snapshotResult = await promptsApi.uploadSceneSnapshot({
|
||||
screenshot: snapshot.file,
|
||||
sceneMediaToken: "",
|
||||
});
|
||||
|
||||
console.log("useSystemPrompt", useSystemPrompt);
|
||||
console.log("useSystemPrompt", useSystemPrompt);
|
||||
|
||||
const response = await promptsApi.enqueueImageGeneration({
|
||||
disableSystemPrompt: !useSystemPrompt,
|
||||
prompt: prompt,
|
||||
snapshotMediaToken: snapshotResult.data || "",
|
||||
additionalImages: referenceImages.map((image) => image.mediaToken),
|
||||
});
|
||||
const response = await promptsApi.enqueueImageGeneration({
|
||||
disableSystemPrompt: !useSystemPrompt,
|
||||
prompt: prompt,
|
||||
snapshotMediaToken: snapshotResult.data || "",
|
||||
additionalImages: referenceImages.map((image) => image.mediaToken),
|
||||
});
|
||||
|
||||
console.log("response", response);
|
||||
console.log("response", response);
|
||||
|
||||
if (response.errorMessage) {
|
||||
handleError(response.errorMessage);
|
||||
setisEnqueueing(false);
|
||||
return;
|
||||
if (response.errorMessage) {
|
||||
handleError(response.errorMessage);
|
||||
setisEnqueueing(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Here we would pass both the prompt and reference images to the generation
|
||||
console.log(
|
||||
"Enqueuing with prompt:",
|
||||
prompt,
|
||||
"and reference images:",
|
||||
referenceImages
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
} finally {
|
||||
setisEnqueueing(false);
|
||||
toast.success("Image added to queue");
|
||||
try {
|
||||
// Here we would pass both the prompt and reference images to the generation
|
||||
console.log(
|
||||
"Enqueuing with prompt:",
|
||||
prompt,
|
||||
"and reference images:",
|
||||
referenceImages
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
} finally {
|
||||
setisEnqueueing(false);
|
||||
toast.success("Image added to queue");
|
||||
}
|
||||
}
|
||||
setisEnqueueing(false);
|
||||
};
|
||||
@@ -365,47 +394,49 @@ export const PromptBox3D = ({
|
||||
|
||||
const promptsApi = new PromptsApi();
|
||||
|
||||
const snapshot = snapshotCurrentFrame(false);
|
||||
if (snapshotCurrentFrame) {
|
||||
const snapshot = snapshotCurrentFrame(false);
|
||||
|
||||
if (snapshot) {
|
||||
const snapshotResult = await promptsApi.uploadSceneSnapshot({
|
||||
screenshot: snapshot.file,
|
||||
//sceneMediaToken: "",
|
||||
});
|
||||
if (snapshot) {
|
||||
const snapshotResult = await promptsApi.uploadSceneSnapshot({
|
||||
screenshot: snapshot.file,
|
||||
//sceneMediaToken: "",
|
||||
});
|
||||
|
||||
const generateResponse = await invoke("sora_image_remix_command", {
|
||||
request: {
|
||||
snapshot_media_token: snapshotResult.data!,
|
||||
disable_system_prompt: !useSystemPrompt,
|
||||
prompt: prompt,
|
||||
maybe_additional_images: referenceImages.map(
|
||||
(image) => image.mediaToken
|
||||
),
|
||||
maybe_number_of_samples: 1,
|
||||
},
|
||||
});
|
||||
const generateResponse = await invoke("sora_image_remix_command", {
|
||||
request: {
|
||||
snapshot_media_token: snapshotResult.data!,
|
||||
disable_system_prompt: !useSystemPrompt,
|
||||
prompt: prompt,
|
||||
maybe_additional_images: referenceImages.map(
|
||||
(image) => image.mediaToken
|
||||
),
|
||||
maybe_number_of_samples: 1,
|
||||
},
|
||||
});
|
||||
|
||||
console.log("response", generateResponse);
|
||||
console.log("response", generateResponse);
|
||||
|
||||
//if (generateResponse.errorMessage) {
|
||||
// handleError(response.errorMessage);
|
||||
// setisEnqueueing(false);
|
||||
// return;
|
||||
//}
|
||||
}
|
||||
//if (generateResponse.errorMessage) {
|
||||
// handleError(response.errorMessage);
|
||||
// setisEnqueueing(false);
|
||||
// return;
|
||||
//}
|
||||
}
|
||||
|
||||
try {
|
||||
// Here we would pass both the prompt and reference images to the generation
|
||||
console.log(
|
||||
"Enqueuing with prompt:",
|
||||
prompt,
|
||||
"and reference images:",
|
||||
referenceImages
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
} finally {
|
||||
setisEnqueueing(false);
|
||||
toast.success("Image added to queue");
|
||||
try {
|
||||
// Here we would pass both the prompt and reference images to the generation
|
||||
console.log(
|
||||
"Enqueuing with prompt:",
|
||||
prompt,
|
||||
"and reference images:",
|
||||
referenceImages
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
} finally {
|
||||
setisEnqueueing(false);
|
||||
toast.success("Image added to queue");
|
||||
}
|
||||
}
|
||||
|
||||
setisEnqueueing(false);
|
||||
@@ -435,6 +466,10 @@ export const PromptBox3D = ({
|
||||
};
|
||||
|
||||
const handleSaveFrame = async () => {
|
||||
if (!snapshotCurrentFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
const snapshot = snapshotCurrentFrame(false);
|
||||
if (snapshot) {
|
||||
const engineApi = new EngineApi();
|
||||
@@ -446,6 +481,9 @@ export const PromptBox3D = ({
|
||||
};
|
||||
|
||||
const handleDownloadFrame = () => {
|
||||
if (!snapshotCurrentFrame) {
|
||||
return;
|
||||
}
|
||||
snapshotCurrentFrame(true);
|
||||
};
|
||||
|
||||
@@ -704,6 +742,7 @@ export const PromptBox3D = ({
|
||||
selected: cam.id === selectedCameraId.value,
|
||||
icon: <FontAwesomeIcon icon={faCamera} className="h-4 w-4" />,
|
||||
focalLength: cam.focalLength,
|
||||
focalLengthDragging: focalLengthDragging,
|
||||
position: cam.position,
|
||||
rotation: cam.rotation,
|
||||
lookAt: cam.lookAt,
|
||||
@@ -714,6 +753,9 @@ export const PromptBox3D = ({
|
||||
selectedCameraId={selectedCameraId.value}
|
||||
handleCameraSelect={handleCameraSelect}
|
||||
onDeleteCamera={deleteCamera}
|
||||
disableHotkeyInput={disableHotkeyInput}
|
||||
enableHotkeyInput={enableHotkeyInput}
|
||||
focalLengthDragging={focalLengthDragging}
|
||||
/>
|
||||
</div>
|
||||
<GalleryModal
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@nx/react/babel",
|
||||
{
|
||||
"runtime": "automatic",
|
||||
"useBuiltIns": "usage"
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# @storyteller/ui-sliderv2
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test @storyteller/ui-sliderv2` to execute the unit tests via [Vitest](https://vitest.dev/).
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@storyteller/ui-sliderv2",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"development": "./src/index.ts",
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
export * from './lib/slider-v2';
|
||||
@@ -0,0 +1,184 @@
|
||||
import { Transition } from "@headlessui/react";
|
||||
import React, { useState, useRef, useEffect, ReactNode } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { Button } from "@storyteller/ui-button";
|
||||
import { faMinus, faPlus } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
interface SliderProps {
|
||||
min: number;
|
||||
max: number;
|
||||
value: number;
|
||||
onChange: (value: number) => void;
|
||||
step: number;
|
||||
className?: string;
|
||||
showTooltip?: boolean;
|
||||
tooltipContent?: ReactNode;
|
||||
suffix?: string;
|
||||
innerLabel?: string;
|
||||
showDecrement?: boolean;
|
||||
showIncrement?: boolean;
|
||||
}
|
||||
|
||||
export const SliderV2 = ({
|
||||
min,
|
||||
max,
|
||||
value,
|
||||
onChange,
|
||||
step,
|
||||
className,
|
||||
showTooltip,
|
||||
tooltipContent,
|
||||
suffix,
|
||||
innerLabel,
|
||||
showDecrement,
|
||||
showIncrement,
|
||||
}: SliderProps) => {
|
||||
const [localValue, setLocalValue] = useState(value);
|
||||
const sliderRef = useRef<HTMLDivElement>(null);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [showHandleTooltip, setShowHandleTooltip] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setLocalValue(value);
|
||||
}, [value]);
|
||||
|
||||
const setClampedValue = (value: number) => {
|
||||
const roundedValue = Math.round(value / step) * step;
|
||||
const clampedValue = Math.min(Math.max(roundedValue, min), max);
|
||||
setLocalValue(clampedValue);
|
||||
onChange(clampedValue);
|
||||
};
|
||||
|
||||
const updatePosition = (x: number) => {
|
||||
if (!sliderRef.current) return;
|
||||
const rect = sliderRef.current.getBoundingClientRect();
|
||||
const fraction = (x - rect.left) / rect.width;
|
||||
const newValue = fraction * (max - min) + min;
|
||||
setClampedValue(newValue);
|
||||
};
|
||||
|
||||
const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
setIsDragging(true);
|
||||
setShowHandleTooltip(true);
|
||||
document.addEventListener("mousemove", handleMouseMove);
|
||||
document.addEventListener("mouseup", handleMouseUp);
|
||||
updatePosition(e.clientX);
|
||||
};
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
updatePosition(e.clientX);
|
||||
};
|
||||
|
||||
const handleMouseUp = (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
setIsDragging(false);
|
||||
setShowHandleTooltip(false);
|
||||
document.removeEventListener("mousemove", handleMouseMove);
|
||||
document.removeEventListener("mouseup", handleMouseUp);
|
||||
};
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
if (!isDragging) {
|
||||
setShowHandleTooltip(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
if (!isDragging) {
|
||||
setShowHandleTooltip(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDecrement = () => {
|
||||
setClampedValue(localValue - step);
|
||||
};
|
||||
|
||||
const handleIncrement = () => {
|
||||
setClampedValue(localValue + step);
|
||||
};
|
||||
|
||||
const percentage = ((localValue - min) / (max - min)) * 100;
|
||||
const displayValue =
|
||||
localValue.toFixed(step.toString().split(".")[1]?.length || 0) +
|
||||
(suffix || "");
|
||||
|
||||
return (
|
||||
<div className="flex w-full">
|
||||
{showDecrement && (
|
||||
<Button
|
||||
icon={faMinus}
|
||||
className="focus-visible:outline-primary my-auto mr-1 size-6 rounded-full bg-transparent text-white/80 hover:bg-white/10 active:bg-brand-primary/30"
|
||||
onClick={handleDecrement}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div
|
||||
ref={sliderRef}
|
||||
className={twMerge(
|
||||
"glass border-ui-border group relative h-7 w-full cursor-pointer overflow-hidden rounded-lg border",
|
||||
isDragging && "!bg-ui-controls/90",
|
||||
className,
|
||||
)}
|
||||
onMouseDown={handleMouseDown}
|
||||
>
|
||||
<div
|
||||
className={twMerge(
|
||||
"absolute h-full bg-brand-primary/30 transition-colors duration-300 group-hover:bg-brand-primary/50",
|
||||
isDragging && "!bg-brand-primary/50",
|
||||
)}
|
||||
style={{ width: `${percentage}%` }}
|
||||
>
|
||||
{innerLabel && (
|
||||
<span
|
||||
className={twMerge(
|
||||
"absolute top-1/2 ml-2.5 -translate-y-1/2 text-nowrap text-sm font-medium text-white/60 transition-colors duration-300 group-hover:text-white",
|
||||
isDragging && "!text-white",
|
||||
)}
|
||||
>
|
||||
{innerLabel}
|
||||
</span>
|
||||
)}
|
||||
<div
|
||||
className={twMerge(
|
||||
"absolute right-0 top-1/2 mr-1 h-4 w-0.5 -translate-y-1/2 rounded-full",
|
||||
isDragging ? "bg-white" : "bg-white/50",
|
||||
)}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showIncrement && (
|
||||
<Button
|
||||
icon={faPlus}
|
||||
className="focus-visible:outline-primary my-auto ml-1 size-6 rounded-full bg-transparent text-white/80 hover:bg-white/10 active:bg-brand-primary/30"
|
||||
onClick={handleIncrement}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showTooltip && (
|
||||
<Transition
|
||||
as={"div"}
|
||||
show={showHandleTooltip}
|
||||
enter="transition ease-out duration-200"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="transition ease-in duration-150"
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div
|
||||
className="absolute -top-8 z-10 rounded-md bg-ui-panel px-2 py-1 text-xs text-black shadow-lg"
|
||||
style={{ left: `${percentage}%`, transform: "translateX(-50%)" }}
|
||||
>
|
||||
{tooltipContent ? tooltipContent : displayValue}
|
||||
</div>
|
||||
</Transition>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
],
|
||||
"extends": "../../../tsconfig.base.json"
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"types": [
|
||||
"node",
|
||||
"@nx/react/typings/cssmodule.d.ts",
|
||||
"@nx/react/typings/image.d.ts",
|
||||
"vite/client"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"jsx": "react-jsx",
|
||||
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo"
|
||||
},
|
||||
"exclude": [
|
||||
"out-tsc",
|
||||
"dist",
|
||||
"**/*.spec.ts",
|
||||
"**/*.test.ts",
|
||||
"**/*.spec.tsx",
|
||||
"**/*.test.tsx",
|
||||
"**/*.spec.js",
|
||||
"**/*.test.js",
|
||||
"**/*.spec.jsx",
|
||||
"**/*.test.jsx",
|
||||
"vite.config.ts",
|
||||
"vite.config.mts",
|
||||
"vitest.config.ts",
|
||||
"vitest.config.mts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.jsx",
|
||||
"src/**/*.spec.jsx"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.js",
|
||||
"src/**/*.jsx",
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/vitest",
|
||||
"types": [
|
||||
"vitest/globals",
|
||||
"vitest/importMeta",
|
||||
"vite/client",
|
||||
"node",
|
||||
"vitest"
|
||||
],
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": [
|
||||
"vite.config.ts",
|
||||
"vite.config.mts",
|
||||
"vitest.config.ts",
|
||||
"vitest.config.mts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.jsx",
|
||||
"src/**/*.spec.jsx",
|
||||
"src/**/*.d.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/// <reference types='vitest' />
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import dts from 'vite-plugin-dts';
|
||||
import * as path from 'path';
|
||||
|
||||
export default defineConfig(() => ({
|
||||
root: __dirname,
|
||||
cacheDir: '../../../node_modules/.vite/libs/components/slider-v2',
|
||||
plugins: [react(), dts({ entryRoot: 'src', tsconfigPath: path.join(__dirname, 'tsconfig.lib.json') })],
|
||||
// Uncomment this if you are using workers.
|
||||
// worker: {
|
||||
// plugins: [ nxViteTsPaths() ],
|
||||
// },
|
||||
// Configuration for building your library.
|
||||
// See: https://vitejs.dev/guide/build.html#library-mode
|
||||
build: {
|
||||
outDir: './dist',
|
||||
emptyOutDir: true,
|
||||
reportCompressedSize: true,
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true,
|
||||
},
|
||||
lib: {
|
||||
// Could also be a dictionary or array of multiple entry points.
|
||||
entry: 'src/index.ts',
|
||||
name: '@storyteller/ui-sliderv2',
|
||||
fileName: 'index',
|
||||
// Change this to the formats you want to support.
|
||||
// Don't forget to update your package.json as well.
|
||||
formats: ['es' as const]
|
||||
},
|
||||
rollupOptions: {
|
||||
// External packages that should not be bundled into your library.
|
||||
external: ['react','react-dom','react/jsx-runtime']
|
||||
},
|
||||
},
|
||||
test: {
|
||||
watch: false,
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
reporters: ['default'],
|
||||
coverage: {
|
||||
reportsDirectory: './test-output/vitest/coverage',
|
||||
provider: 'v8' as const,
|
||||
}
|
||||
},
|
||||
}));
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@nx/react/babel",
|
||||
{
|
||||
"runtime": "automatic",
|
||||
"useBuiltIns": "usage"
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# @storyteller/ui-transition-dialogue
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test @storyteller/ui-transition-dialogue` to execute the unit tests via [Vitest](https://vitest.dev/).
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@storyteller/ui-transition-dialogue",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"development": "./src/index.ts",
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
export * from './lib/transition-dialogue';
|
||||
@@ -0,0 +1,165 @@
|
||||
import { useEffect, Fragment, ReactNode } from "react";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
IconDefinition,
|
||||
faDownLeftAndUpRightToCenter,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import { Tooltip } from "@storyteller/ui-tooltip";
|
||||
import { DomLevels } from "@storyteller/enums";
|
||||
|
||||
const DialogBackdrop = ({
|
||||
className,
|
||||
disableHotkeyInput,
|
||||
enableHotkeyInput,
|
||||
}: {
|
||||
className?: string;
|
||||
disableHotkeyInput: (level: number) => void;
|
||||
enableHotkeyInput: (level: number) => void;
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
disableHotkeyInput(DomLevels.DIALOGUE);
|
||||
return () => {
|
||||
enableHotkeyInput(DomLevels.DIALOGUE);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div
|
||||
className={twMerge("fixed inset-0 bg-black/60", className)}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
</Transition.Child>
|
||||
);
|
||||
};
|
||||
|
||||
export const TransitionDialogue = ({
|
||||
isOpen,
|
||||
title,
|
||||
titleIcon,
|
||||
onTitleIconClick,
|
||||
onClose,
|
||||
className,
|
||||
backdropClassName,
|
||||
width,
|
||||
children,
|
||||
childPadding = true,
|
||||
titleIconClassName,
|
||||
showClose = true,
|
||||
disableHotkeyInput = () => { },
|
||||
enableHotkeyInput = () => { },
|
||||
}: {
|
||||
isOpen: boolean;
|
||||
title?: ReactNode;
|
||||
titleIcon?: IconDefinition;
|
||||
onTitleIconClick?: () => void;
|
||||
titleIconClassName?: string;
|
||||
onClose: () => void;
|
||||
className?: string;
|
||||
backdropClassName?: string;
|
||||
width?: number;
|
||||
children: ReactNode;
|
||||
childPadding?: boolean;
|
||||
showClose?: boolean;
|
||||
disableHotkeyInput: (level: number) => void;
|
||||
enableHotkeyInput: (level: number) => void;
|
||||
}) => {
|
||||
return (
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
<Dialog as="div" className="relative z-[70]" onClose={onClose}>
|
||||
<DialogBackdrop className={backdropClassName} disableHotkeyInput={disableHotkeyInput} enableHotkeyInput={enableHotkeyInput} />
|
||||
<div className="fixed inset-0 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center p-4 text-center">
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-200"
|
||||
enterFrom="opacity-0 scale-95"
|
||||
enterTo="opacity-100 scale-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<Dialog.Panel
|
||||
className={twMerge(
|
||||
"w-full max-w-lg transform rounded-xl",
|
||||
"border border-ui-panel-border bg-[#2C2C2C]",
|
||||
"text-left align-middle shadow-xl transition-all",
|
||||
className,
|
||||
)}
|
||||
style={{ minWidth: width }}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{title && (
|
||||
<Dialog.Title
|
||||
as="div"
|
||||
className="mb-5 flex justify-between p-5 pb-0 text-xl font-bold text-white"
|
||||
>
|
||||
<>
|
||||
{onTitleIconClick ? (
|
||||
<button
|
||||
className="flex items-center gap-3"
|
||||
onClick={onTitleIconClick}
|
||||
>
|
||||
{titleIcon && (
|
||||
<FontAwesomeIcon
|
||||
icon={titleIcon}
|
||||
className={titleIconClassName}
|
||||
/>
|
||||
)}
|
||||
{title}
|
||||
</button>
|
||||
) : (
|
||||
<div className="flex items-center gap-3">
|
||||
{titleIcon && (
|
||||
<FontAwesomeIcon
|
||||
icon={titleIcon}
|
||||
className={titleIconClassName}
|
||||
/>
|
||||
)}
|
||||
{title}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
{showClose && (
|
||||
<Tooltip position="top" content="Close">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="opacity-50 transition-opacity duration-150 hover:opacity-80 focus:outline-none"
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faDownLeftAndUpRightToCenter}
|
||||
/>
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Dialog.Title>
|
||||
)}
|
||||
<div
|
||||
className={`h-full ${childPadding ? "p-5 pt-0" : ""}`.trim()}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Transition>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
],
|
||||
"extends": "../../../tsconfig.base.json"
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"types": [
|
||||
"node",
|
||||
"@nx/react/typings/cssmodule.d.ts",
|
||||
"@nx/react/typings/image.d.ts",
|
||||
"vite/client"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"jsx": "react-jsx",
|
||||
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo"
|
||||
},
|
||||
"exclude": [
|
||||
"out-tsc",
|
||||
"dist",
|
||||
"**/*.spec.ts",
|
||||
"**/*.test.ts",
|
||||
"**/*.spec.tsx",
|
||||
"**/*.test.tsx",
|
||||
"**/*.spec.js",
|
||||
"**/*.test.js",
|
||||
"**/*.spec.jsx",
|
||||
"**/*.test.jsx",
|
||||
"vite.config.ts",
|
||||
"vite.config.mts",
|
||||
"vitest.config.ts",
|
||||
"vitest.config.mts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.jsx",
|
||||
"src/**/*.spec.jsx"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.js",
|
||||
"src/**/*.jsx",
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/vitest",
|
||||
"types": [
|
||||
"vitest/globals",
|
||||
"vitest/importMeta",
|
||||
"vite/client",
|
||||
"node",
|
||||
"vitest"
|
||||
],
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": [
|
||||
"vite.config.ts",
|
||||
"vite.config.mts",
|
||||
"vitest.config.ts",
|
||||
"vitest.config.mts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.tsx",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.jsx",
|
||||
"src/**/*.spec.jsx",
|
||||
"src/**/*.d.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/// <reference types='vitest' />
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import dts from 'vite-plugin-dts';
|
||||
import * as path from 'path';
|
||||
|
||||
export default defineConfig(() => ({
|
||||
root: __dirname,
|
||||
cacheDir: '../../../node_modules/.vite/libs/components/transition-dialogue',
|
||||
plugins: [react(), dts({ entryRoot: 'src', tsconfigPath: path.join(__dirname, 'tsconfig.lib.json') })],
|
||||
// Uncomment this if you are using workers.
|
||||
// worker: {
|
||||
// plugins: [ nxViteTsPaths() ],
|
||||
// },
|
||||
// Configuration for building your library.
|
||||
// See: https://vitejs.dev/guide/build.html#library-mode
|
||||
build: {
|
||||
outDir: './dist',
|
||||
emptyOutDir: true,
|
||||
reportCompressedSize: true,
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true,
|
||||
},
|
||||
lib: {
|
||||
// Could also be a dictionary or array of multiple entry points.
|
||||
entry: 'src/index.ts',
|
||||
name: '@storyteller/ui-transition-dialogue',
|
||||
fileName: 'index',
|
||||
// Change this to the formats you want to support.
|
||||
// Don't forget to update your package.json as well.
|
||||
formats: ['es' as const]
|
||||
},
|
||||
rollupOptions: {
|
||||
// External packages that should not be bundled into your library.
|
||||
external: ['react','react-dom','react/jsx-runtime']
|
||||
},
|
||||
},
|
||||
test: {
|
||||
watch: false,
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
reporters: ['default'],
|
||||
coverage: {
|
||||
reportsDirectory: './test-output/vitest/coverage',
|
||||
provider: 'v8' as const,
|
||||
}
|
||||
},
|
||||
}));
|
||||
Generated
+52
-838
File diff suppressed because it is too large.
Load diff
@@ -74,6 +74,18 @@
|
||||
},
|
||||
{
|
||||
"path": "./libs/common/interfaces"
|
||||
},
|
||||
{
|
||||
"path": "./libs/components/camera-settings-modal"
|
||||
},
|
||||
{
|
||||
"path": "./libs/components/transition-dialogue"
|
||||
},
|
||||
{
|
||||
"path": "./libs/components/slider-v2"
|
||||
},
|
||||
{
|
||||
"path": "./libs/common/types"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user