mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 17:38:10 +00:00
Merge branch 'test' of github.com:storytold/GottaGoFast into test
This commit is contained in:
commit
e0df1c4af9
24 files changed
+354
-58
No files matched your search
+1
-1
@@ -1,5 +1,5 @@
|
||||
node_modules
|
||||
|
||||
/~/
|
||||
/.cache
|
||||
/public/build
|
||||
/build
|
||||
|
||||
@@ -3,20 +3,29 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
icon?: IconDefinition;
|
||||
variant?: "primary"|"secondary";
|
||||
}
|
||||
|
||||
export const Button = ({
|
||||
icon,
|
||||
children,
|
||||
className : propsClassName,
|
||||
variant = 'primary',
|
||||
...rest
|
||||
}:ButtonProps)=>{
|
||||
const className = `
|
||||
bg-brand-primary hover:bg-brand-primary-400
|
||||
text-white text-sm font-semibold
|
||||
rounded-md px-3.5 py-2.5 shadow-sm
|
||||
focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-primary-600
|
||||
` + (propsClassName ? ` ${propsClassName}` : null);
|
||||
function getVariantClassNames(variant: string){
|
||||
switch(variant){
|
||||
case "secondary":{
|
||||
return " bg-brand-secondary hover:bg-brand-secondary-900 text-white focus-visible:outline-brand-secondary";
|
||||
}
|
||||
case "primary":
|
||||
default:{
|
||||
return " bg-brand-primary hover:bg-brand-primary-400 text-white focus-visible:outline-brand-primary-600";
|
||||
}
|
||||
}
|
||||
};
|
||||
const className = "text-sm font-semibold rounded-md px-3.5 py-2.5 shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2" + getVariantClassNames(variant)
|
||||
+ (propsClassName ? ` ${propsClassName}` : "");
|
||||
|
||||
return(
|
||||
<button
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Link, LinkProps } from "@remix-run/react";
|
||||
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
interface LinkButtonProps extends LinkProps {
|
||||
icon?: IconDefinition;
|
||||
variant?: "primary"|"secondary";
|
||||
}
|
||||
|
||||
export const ButtonLink = ({
|
||||
icon,
|
||||
children,
|
||||
className: propsClassName,
|
||||
variant = "primary",
|
||||
...rest
|
||||
}:LinkButtonProps)=>{
|
||||
//TODO: Duplicated from Button.tsx
|
||||
function getVariantClassNames(variant: string){
|
||||
switch(variant){
|
||||
case "secondary":{
|
||||
return " bg-brand-secondary hover:bg-brand-secondary-900 text-white focus-visible:outline-brand-secondary";
|
||||
}
|
||||
case "primary":
|
||||
default:{
|
||||
return " bg-brand-primary hover:bg-brand-primary-400 text-white focus-visible:outline-brand-primary-600";
|
||||
}
|
||||
}
|
||||
};
|
||||
const className = "text-sm font-semibold rounded-md px-3.5 py-2.5 shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2" + getVariantClassNames(variant)
|
||||
+ (propsClassName ? ` ${propsClassName}` : "");
|
||||
// END TODO
|
||||
|
||||
return(
|
||||
<Link {...rest}>
|
||||
<button className={className}>
|
||||
{icon && <FontAwesomeIcon className="mr-2" icon={icon}/>}
|
||||
{children}
|
||||
</button>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { createContext } from "react";
|
||||
|
||||
export const TopBarInnerContext = createContext<{
|
||||
TopBarInner: JSX.Element | null;
|
||||
setTopBarInner: (el: JSX.Element | null)=>void;
|
||||
} | null>(null);
|
||||
@@ -1,3 +0,0 @@
|
||||
import { ReactNode, createContext } from "react";
|
||||
|
||||
export const TopBarMidSection = createContext<ReactNode | null>(null);
|
||||
@@ -1,13 +1,28 @@
|
||||
import {
|
||||
useRef,
|
||||
useEffect,
|
||||
useState,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import {
|
||||
faChevronLeft
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
import { Button } from '~/components/Button';
|
||||
import { ButtonLink } from '~/components/ButtonLink';
|
||||
import { TopBarInnerContext } from "~/contexts/TopBarInner";
|
||||
|
||||
import { SidePanel } from '~/templates/SidePanel';
|
||||
|
||||
import { SceneWithCube } from './SceneWithCube';
|
||||
|
||||
export const PageCube = () => {
|
||||
|
||||
const { setTopBarInner } = useContext(TopBarInnerContext) || {};
|
||||
|
||||
const mountRef = useRef<HTMLDivElement | null>(null);
|
||||
const sceneRef = useRef<SceneWithCube | null>(null);
|
||||
const [{
|
||||
@@ -27,7 +42,10 @@ export const PageCube = () => {
|
||||
const listeningXYRotation = useCallback((
|
||||
{x,y}:{x:number;y:number}
|
||||
)=>{
|
||||
setRotations({x:x, y:y})
|
||||
setRotations({
|
||||
x:Math.round(x*100)/100,
|
||||
y:Math.round(y*100)/100,
|
||||
})
|
||||
},[]);
|
||||
|
||||
useEffect(() => { //componentDidMount
|
||||
@@ -45,13 +63,35 @@ export const PageCube = () => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
useLayoutEffect(()=>{
|
||||
if(setTopBarInner){
|
||||
const BackButton = (
|
||||
<ButtonLink
|
||||
to={"/"}
|
||||
variant='secondary'
|
||||
icon={faChevronLeft}
|
||||
>
|
||||
Back to Dashboard
|
||||
</ButtonLink>
|
||||
);
|
||||
setTopBarInner(BackButton);
|
||||
}
|
||||
},[setTopBarInner]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="Cube" ref={mountRef} />
|
||||
<button onClick={toggleStopped}> STOP </button>
|
||||
<p>{rotationX ? rotationX : ""}</p>
|
||||
<p>{rotationY ? rotationY : ""}</p>
|
||||
</>
|
||||
<div className="grid grid-cols-12 gap-2 ">
|
||||
<div className="col-span-6 ">
|
||||
<div className="MountingPoint" ref={mountRef} />
|
||||
</div>
|
||||
<div className="col-span-6 ">
|
||||
<Button onClick={toggleStopped}> STOP </Button>
|
||||
<p className='text-white'>Ration X: {rotationX ? rotationX : ""}</p>
|
||||
<p className='text-white'>Ration Y: {rotationY ? rotationY : ""}</p>
|
||||
</div>
|
||||
<SidePanel>
|
||||
<p>Side Panel Text</p>
|
||||
</SidePanel>
|
||||
</div>
|
||||
);
|
||||
|
||||
};
|
||||
@@ -1,16 +1,27 @@
|
||||
import {
|
||||
useRef,
|
||||
useEffect,
|
||||
// useState,
|
||||
import {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useRef,
|
||||
// useState,
|
||||
} from 'react';
|
||||
|
||||
import {
|
||||
faChevronLeft,
|
||||
faWandSparkles,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
|
||||
import { Button } from '~/components/Button';
|
||||
import { ButtonLink } from '~/components/ButtonLink';
|
||||
import { TopBarInnerContext } from "~/contexts/TopBarInner";
|
||||
import { SidePanel } from '~/templates/SidePanel';
|
||||
|
||||
import Editor from './js/editor';
|
||||
|
||||
export const PageEnigma = () => {
|
||||
const { setTopBarInner } = useContext(TopBarInnerContext) || {};
|
||||
|
||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||
const editorRef = useRef<Editor | null>(null);
|
||||
@@ -37,6 +48,29 @@ export const PageEnigma = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
useLayoutEffect(()=>{
|
||||
if(setTopBarInner){
|
||||
const TopBarInnerButtons = (
|
||||
<div className="flex grow justify-between">
|
||||
<ButtonLink
|
||||
to={"/"}
|
||||
variant='secondary'
|
||||
icon={faChevronLeft}
|
||||
>
|
||||
Back to Dashboard
|
||||
</ButtonLink>
|
||||
<Button
|
||||
icon={faWandSparkles}
|
||||
>
|
||||
Generate Movie
|
||||
</Button>
|
||||
<span className="w-8"/>
|
||||
</div>
|
||||
);
|
||||
setTopBarInner(TopBarInnerButtons);
|
||||
}
|
||||
},[setTopBarInner]);
|
||||
|
||||
const handleButtonSave = ()=>{
|
||||
editorRef.current?.save();
|
||||
}
|
||||
@@ -53,14 +87,16 @@ export const PageEnigma = () => {
|
||||
return(
|
||||
<div>
|
||||
<canvas ref={canvasRef} id="video-scene" width="1280px" height="720px" />
|
||||
<div className="absolute top-0 right-0 bg-ui-panel h-screen w-1/5 pt-20">
|
||||
<SidePanel>
|
||||
<Button onClick={handleButtonSave}>Save</Button>
|
||||
<Button onClick={handleButtonLoad}>Load</Button>
|
||||
<Button onClick={handleButtonRender}>Render</Button>
|
||||
<Button onClick={handleButtonPlay}>Play</Button>
|
||||
</SidePanel>
|
||||
<div className="bg-ui-panel w-full h-screen">
|
||||
<p className='text-white'>Timeline Panel</p>
|
||||
<input style={{ display: 'none' }} type="file" id="load-upload" name="load-upload"></input>
|
||||
</div>
|
||||
<div className="bg-ui-panel w-full h-screen">Timeline Panel</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
class MediaUploadManager {
|
||||
constructor(sessionToken) {
|
||||
this.baseUrl = "https://api.fakeyou.com";
|
||||
@@ -7,15 +9,19 @@ class MediaUploadManager {
|
||||
async uploadMedia(blob, fileName) {
|
||||
const url = `${this.baseUrl}/v1/media_uploads/upload`;
|
||||
|
||||
let uuid = uuidv4();
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('uuid_idempotency_token', uuid);
|
||||
formData.append('file', blob, fileName);
|
||||
formData.append('source', 'file');
|
||||
formData.append('type', 'video');
|
||||
formData.append('source', 'file');
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Authorization': `Bearer ${this.sessionToken}`, // Assuming the session token is a Bearer token
|
||||
'Access-Control-Allow-Origin': 'http://localhost:3000',
|
||||
'Access-Control-Allow-Credentials': true
|
||||
"accept": "application/json",
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
@@ -38,4 +38,6 @@ class AudioManager {
|
||||
console.warn(`AudioManager: AudioClip with id "${id}" not found.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default AudioManager;
|
||||
@@ -6,6 +6,7 @@ import Stats from 'three/addons/libs/stats.module.js';
|
||||
import Scene from './scene.js';
|
||||
import SaveManager from './serialization.js';
|
||||
import MediaUploadManager from './api_manager.js';
|
||||
import AudioManager from './audio_manager.js';
|
||||
|
||||
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
|
||||
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
|
||||
@@ -63,12 +64,10 @@ class Editor {
|
||||
// API.
|
||||
this.api_manager = new MediaUploadManager();
|
||||
|
||||
|
||||
this.locked = false;
|
||||
|
||||
// Debug & Movement.
|
||||
this.stats = null;
|
||||
this.orbit = null;
|
||||
this.locked = false;
|
||||
|
||||
// Recording params.
|
||||
this.capturer = null;
|
||||
@@ -81,9 +80,13 @@ class Editor {
|
||||
this.playback = false;
|
||||
this.playback_location = 0;
|
||||
this.max_length = 10;
|
||||
this.timeline = null;
|
||||
|
||||
// Save & Load.
|
||||
this.save_manager = new SaveManager(this.version);
|
||||
|
||||
// Audio Engine.
|
||||
this.audio_manager = new AudioManager();
|
||||
}
|
||||
|
||||
// Initializes the main scene and ThreeJS essentials.
|
||||
@@ -302,10 +305,15 @@ class Editor {
|
||||
this.control.detach(this.selected);
|
||||
this.activeScene.scene.remove(this.control);
|
||||
this.activeScene.scene.remove(this.activeScene.gridHelper);
|
||||
this.save_manager.save(this.activeScene.scene);
|
||||
this.save_manager.save(this.activeScene.scene, this._save_to_cloud.bind(this), this.audio_manager, this.timeline);
|
||||
this.activeScene._createGrid();
|
||||
}
|
||||
|
||||
_save_to_cloud(blob) {
|
||||
console.log("Posting to cloud!");
|
||||
this.api_manager.uploadMedia(blob, "test.bin");
|
||||
}
|
||||
|
||||
load() {
|
||||
let uploadedFile = document.getElementById("load-upload").files[0];
|
||||
this.save_manager.load(uploadedFile, this.load_callback.bind(this));
|
||||
@@ -365,6 +373,8 @@ class Editor {
|
||||
const blob = new Blob([output.buffer], { type: 'video/mp4' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
await this.api_manager.uploadMedia(blob, "output.mp4");
|
||||
|
||||
// Create a link to download the file
|
||||
const downloadLink = document.createElement('a');
|
||||
downloadLink.href = url;
|
||||
|
||||
@@ -86,7 +86,6 @@ class Scene {
|
||||
}
|
||||
|
||||
play_anim_demo(character_name) {
|
||||
console.log(this.characters[character_name].anims[0]._clip);
|
||||
this.characters[character_name].animate(this.characters[character_name].anims[0]._clip);
|
||||
this.characters[character_name].sync_lips("/resources/sound/2pac.wav");
|
||||
this.activeCharacter = character_name;
|
||||
|
||||
@@ -8,16 +8,18 @@ class SaveManager {
|
||||
this.scene = null;
|
||||
}
|
||||
|
||||
save(scene, scene_data) {
|
||||
save(scene, scene_callback, audio_manager, timeline) {
|
||||
let gltfExporter = new GLTFExporter();
|
||||
gltfExporter.parse(
|
||||
scene,
|
||||
function (gltfJson) {
|
||||
const jsonString = JSON.stringify(gltfJson);
|
||||
function (gltf) {
|
||||
console.log(scene);
|
||||
let blob = new Blob([jsonString], {type: 'application/octet-stream'})
|
||||
let save_json = {"glb": gltf, "audio": audio_manager.clips, "timeline": timeline}
|
||||
let blob = new Blob([JSON.stringify(save_json)], {type: 'application/json'})
|
||||
let blobUrl = URL.createObjectURL(blob);
|
||||
|
||||
scene_callback(blob);
|
||||
|
||||
let a = document.createElement('a');
|
||||
|
||||
const now = new Date();
|
||||
@@ -28,7 +30,7 @@ class SaveManager {
|
||||
const minutes = String(now.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(now.getSeconds()).padStart(2, '0');
|
||||
const randomNumber = Math.floor(Math.random() * 1000);
|
||||
let save_name = `save_${randomNumber}_${year}${month}${day}_${hours}${minutes}${seconds}.glb`;
|
||||
let save_name = `save_${randomNumber}_${year}${month}${day}_${hours}${minutes}${seconds}.sav`;
|
||||
|
||||
a.href = blobUrl;
|
||||
a.download = save_name;
|
||||
@@ -51,18 +53,13 @@ class SaveManager {
|
||||
reader.onload = function(e) {
|
||||
const contents = e.target.result;
|
||||
|
||||
const loader = new THREE.GLTFLoader();
|
||||
const loader = new GLTFLoader();
|
||||
loader.parse(contents, '', function(gltf) {
|
||||
scene.add(gltf.scene);
|
||||
console.log(gltf);
|
||||
load_callback(gltf.scene);
|
||||
});
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
|
||||
//const loader = new GLTFLoader();
|
||||
//loader.load(uploadedFile, function ( gltf ) {
|
||||
// console.log(gltf);
|
||||
// load_callback(gltf.scene);
|
||||
//});
|
||||
reader.readAsArrayBuffer(uploadedFile);
|
||||
}
|
||||
|
||||
download(data, filename, type) {
|
||||
|
||||
+15
-4
@@ -1,3 +1,4 @@
|
||||
import { useState } from 'react';
|
||||
import { LinksFunction } from "@remix-run/deno";
|
||||
import {
|
||||
Links,
|
||||
@@ -10,8 +11,9 @@ import {
|
||||
import tailwindCss from "./styles/tailwind.css?url";
|
||||
import normalizeCss from "./styles/normalize.css?url";
|
||||
|
||||
import { TopBar } from "./template/TopBar";
|
||||
import { TopBarMidSection } from "./contexts/TopbarMidSection";
|
||||
import { TopBar } from "./templates/TopBar";
|
||||
import { TopBarInnerContext } from '~/contexts/TopBarInner';
|
||||
|
||||
|
||||
export const links : LinksFunction = () => [{
|
||||
rel: "stylesheet",
|
||||
@@ -22,6 +24,8 @@ export const links : LinksFunction = () => [{
|
||||
}];
|
||||
|
||||
export default function App() {
|
||||
const [topBarInnerComponent, setTopBarInnerComponent] = useState<JSX.Element | null>(null);
|
||||
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
@@ -31,8 +35,15 @@ export default function App() {
|
||||
<Links />
|
||||
</head>
|
||||
<body className="bg-ui-background">
|
||||
<Outlet />
|
||||
<TopBar />
|
||||
<TopBarInnerContext.Provider value={{
|
||||
TopBarInner: topBarInnerComponent,
|
||||
setTopBarInner: setTopBarInnerComponent
|
||||
}}>
|
||||
|
||||
<div className="h-10 m-4 w-screen border-b"/>
|
||||
<Outlet />
|
||||
<TopBar />
|
||||
</TopBarInnerContext.Provider>
|
||||
<ScrollRestoration />
|
||||
<Scripts />
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
export default function ColourGuide () {
|
||||
return(
|
||||
<>
|
||||
<h1 className="text-brand-primary">Primary / Sunglo</h1>
|
||||
<h1 className="text-brand-secondary">Secondary / Gunpowder</h1>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Button } from "~/components/Button";
|
||||
import { ButtonLink } from "~/components/ButtonLink";
|
||||
|
||||
export default function ComponentLibrary () {
|
||||
return(
|
||||
<>
|
||||
<Button>Button</Button>
|
||||
<ButtonLink to="/">Button with Link</ButtonLink>
|
||||
</>
|
||||
);
|
||||
};
|
||||
+2
-1
@@ -2,6 +2,7 @@ import { useState } from 'react';
|
||||
import { PageCube } from "../pages/PageCube";
|
||||
import { Button } from '~/components/Button';
|
||||
export default function Cube(){
|
||||
const pausedRiddle = true;
|
||||
const [riddle, setRiddle] = useState<string>("");
|
||||
const [submitted, setSubmitted] = useState<boolean>(false);
|
||||
|
||||
@@ -17,7 +18,7 @@ export default function Cube(){
|
||||
alert("What is the price for your blind eye?")
|
||||
}
|
||||
|
||||
if(submitted){
|
||||
if(submitted || pausedRiddle){
|
||||
return <PageCube />
|
||||
}else{
|
||||
return(
|
||||
|
||||
+12
-1
@@ -1,4 +1,10 @@
|
||||
import {
|
||||
useContext,
|
||||
useLayoutEffect,
|
||||
} from "react";
|
||||
import type { MetaFunction } from "@remix-run/deno";
|
||||
import { TopBarInnerContext } from "~/contexts/TopBarInner";
|
||||
|
||||
import sonic from "./_assets/sonic-the-hedgehog-classic-sonic.gif";
|
||||
|
||||
export const meta: MetaFunction = () => {
|
||||
@@ -8,8 +14,13 @@ export const meta: MetaFunction = () => {
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
export default function Index() {
|
||||
const { setTopBarInner } = useContext(TopBarInnerContext) || {};
|
||||
useLayoutEffect(()=>{
|
||||
if(setTopBarInner){
|
||||
setTopBarInner(null);
|
||||
}
|
||||
},[setTopBarInner]);
|
||||
return (
|
||||
<div className="size-full">
|
||||
<img
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { Fragment, useState } from 'react'
|
||||
import { Dialog, Transition } from '@headlessui/react'
|
||||
import {
|
||||
faXmark,
|
||||
faGears,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
import { Button } from '~/components/Button';
|
||||
interface SidePanelPropsI{
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export const SidePanel =(props:SidePanelPropsI)=>{
|
||||
const [open, setOpen] = useState(false)
|
||||
const handleOpen = ()=>{
|
||||
setOpen(true);
|
||||
}
|
||||
|
||||
return (<>
|
||||
<Button
|
||||
className='fixed right-0 top-20 mt-2 mr-4'
|
||||
onClick={handleOpen}
|
||||
>
|
||||
<FontAwesomeIcon icon={faGears} />
|
||||
</Button>
|
||||
<Transition.Root show={open} as={Fragment}>
|
||||
<Dialog as="div" className="relative z-10" onClose={setOpen}>
|
||||
<div className="fixed inset-0" />
|
||||
|
||||
<div className="fixed inset-0 overflow-hidden">
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<div className="pointer-events-none fixed inset-y-0 right-0 flex max-w-full pl-10 sm:pl-16">
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="transform transition ease-in-out duration-500 sm:duration-700"
|
||||
enterFrom="translate-x-full"
|
||||
enterTo="translate-x-0"
|
||||
leave="transform transition ease-in-out duration-500 sm:duration-700"
|
||||
leaveFrom="translate-x-0"
|
||||
leaveTo="translate-x-full"
|
||||
>
|
||||
<Dialog.Panel className="pointer-events-auto w-screen max-w-2xl">
|
||||
<div className="flex h-full flex-col overflow-y-scroll bg-ui-panel py-6 shadow-xl">
|
||||
<div className="px-4 sm:px-6">
|
||||
<div className="flex items-start justify-between">
|
||||
<Dialog.Title className="text-base font-semibold leading-6 text-white">
|
||||
Library
|
||||
</Dialog.Title>
|
||||
<div className="ml-3 flex h-7 items-center">
|
||||
<button
|
||||
type="button"
|
||||
className="relative rounded-md bg-brand-primary text-white hover:bg-brand-primary-400 focus:outline-none focus:ring-brand-primary-500"
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
<span className="absolute -inset-2.5" />
|
||||
<span className="sr-only">Close panel</span>
|
||||
<FontAwesomeIcon
|
||||
className="h-6 w-6"
|
||||
aria-hidden="true"
|
||||
icon={faXmark}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative mt-6 flex-1 px-4 sm:px-6">
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Transition.Root>
|
||||
</>);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { SidePanel } from './SidePanel';
|
||||
@@ -1,18 +1,32 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { Button } from '~/components/Button'
|
||||
import { faRightToBracket } from '@fortawesome/free-solid-svg-icons'
|
||||
export const TopBar = () => {
|
||||
import { TopBarInnerContext } from '~/contexts/TopBarInner';
|
||||
|
||||
export const TopBar = () => {
|
||||
return (
|
||||
<header className="bg-ui-panel fixed top-0 left-0 w-full">
|
||||
<header className="
|
||||
fixed top-0 left-0 w-full
|
||||
bg-ui-panel border-b border-ui-panel-border
|
||||
">
|
||||
<nav className="mx-auto flex max-w-full items-center justify-between p-4 lg:px-8" aria-label="Global">
|
||||
<div className="flex lg:flex-1">
|
||||
<a href="#" className="-m-1.5 p-1.5">
|
||||
<span className="sr-only">FakeYou</span>
|
||||
<img className="h-10 w-auto" src="/resources/images/Storyteller-Logo-1.png" alt="Logo FakeYou StoryTeller.ai" />
|
||||
</a>
|
||||
<span className="w-4 lg:w-8"/>
|
||||
<TopBarInner />
|
||||
</div>
|
||||
<Button icon={faRightToBracket}>Login</Button>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
const TopBarInner = ()=>{
|
||||
const { TopBarInner } = useContext(TopBarInnerContext) || {}
|
||||
return(TopBarInner);
|
||||
}
|
||||
File renamed without changes.
Generated
+13
@@ -26,6 +26,7 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"three": "^0.162.0",
|
||||
"uuid": "^9.0.1",
|
||||
"webm-writer": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -12475,6 +12476,18 @@
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/uvu": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz",
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"three": "^0.162.0",
|
||||
"uuid": "^9.0.1",
|
||||
"webm-writer": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -73,6 +73,7 @@ export default {
|
||||
|
||||
'ui-background': '#1a1a27',
|
||||
'ui-panel': '#242433',
|
||||
'ui-panel-border': '#5e6097',
|
||||
|
||||
gray: colors.gray,
|
||||
white: colors.white
|
||||
|
||||
Reference in new issue
Block a user