mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 17:38:10 +00:00
Merge pull request #146 from storytold/styling/stylization-page
styling/stylization page
This commit is contained in:
9 files changed
+94
-89
No files matched your search
@@ -6,32 +6,23 @@ import { kebabCase } from "~/utilities";
|
||||
|
||||
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
||||
label?: string;
|
||||
icon?: IconDefinition
|
||||
icon?: IconDefinition;
|
||||
}
|
||||
|
||||
export function Input({
|
||||
label, icon, className, id, ...rest
|
||||
}: InputProps) {
|
||||
export function Input({ label, icon, className, id, ...rest }: InputProps) {
|
||||
return (
|
||||
<div className={twMerge("flex flex-col gap-2", className)}>
|
||||
{label &&
|
||||
<Label htmlFor={id ? id : kebabCase(label)}>
|
||||
{label}
|
||||
</Label>
|
||||
}
|
||||
{label && <Label htmlFor={id ? id : kebabCase(label)}>{label}</Label>}
|
||||
|
||||
<div className="relative w-full">
|
||||
{icon && (
|
||||
<FontAwesomeIcon
|
||||
icon={icon}
|
||||
className="absolute pt-2.5 pl-3 h-5"
|
||||
/>
|
||||
<FontAwesomeIcon icon={icon} className="absolute h-5 pl-3 pt-2.5" />
|
||||
)}
|
||||
<input
|
||||
id={id ? id : (label ? kebabCase(label) : undefined)}
|
||||
id={id ? id : label ? kebabCase(label) : undefined}
|
||||
className={twMerge(
|
||||
"w-full h-10 rounded-md bg-brand-secondary p-3 text-white transition-all duration-150 ease-in-out outline-none outline-offset-0 focus:outline-brand-primary",
|
||||
icon? "pl-12" : "",
|
||||
"h-10 w-full rounded-md bg-brand-secondary px-3 py-2.5 text-white outline-none outline-offset-0 transition-all duration-150 ease-in-out focus:outline-brand-primary",
|
||||
icon ? "pl-12" : "",
|
||||
)}
|
||||
{...rest}
|
||||
/>
|
||||
|
||||
@@ -30,7 +30,7 @@ export const ItemPicker = ({
|
||||
>
|
||||
<img className="aspect-square" {...imgProps} alt="style" />
|
||||
<div className="absolute left-0 top-0 h-full w-full bg-gradient-to-t from-gray-700" />
|
||||
<H4 className="absolute bottom-[1px] left-[6px] text-sm drop-shadow-md">
|
||||
<H4 className="absolute bottom-[1px] left-[6px] text-start text-sm drop-shadow-md">
|
||||
{label}
|
||||
</H4>
|
||||
</button>
|
||||
|
||||
@@ -30,7 +30,7 @@ export const Textarea = ({
|
||||
<textarea
|
||||
id={id ? id : label ? kebabCase(label) : undefined}
|
||||
className={twMerge(
|
||||
"rounded-lg border border-ui-panel-border bg-ui-controls p-3",
|
||||
"rounded-lg border border-ui-panel-border bg-ui-controls px-3 py-2",
|
||||
className,
|
||||
)}
|
||||
style={{
|
||||
|
||||
@@ -40,8 +40,9 @@ export const TopBar = ({ pageName }: Props) => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center">
|
||||
<span className="opacity-60">{pageName} /</span>
|
||||
<div className="flex items-center justify-center font-medium">
|
||||
<span className="opacity-60">{pageName} /</span>
|
||||
|
||||
{sceneTitle.value}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faAngleLeft } from "@fortawesome/pro-solid-svg-icons";
|
||||
import {
|
||||
faAngleLeft,
|
||||
faArrowsRotate,
|
||||
faFilm,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import { Button, Link } from "~/components";
|
||||
import { StyleSelection } from "~/pages/PageEnigma/comps/StyleSelection";
|
||||
import { LowerPanel } from "~/modules/LowerPanel";
|
||||
@@ -30,32 +34,38 @@ export const PageStyling = ({ setPage }: Props) => {
|
||||
const switchEdit = () => {
|
||||
editorEngine?.switchEdit();
|
||||
setPage("edit");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-screen">
|
||||
<TopBar pageName="Stylization" />
|
||||
<div className="flex w-full justify-center">
|
||||
<div className="bg-ui-controls p-2">
|
||||
<div className="rounded-b-lg bg-ui-controls p-2">
|
||||
<Button variant="action" onClick={() => switchEdit()}>
|
||||
<FontAwesomeIcon icon={faAngleLeft} />
|
||||
Back to Scene
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex flex-col items-center gap-4">
|
||||
<div className="mt-5 flex flex-col items-center gap-6">
|
||||
<PreviewImages />
|
||||
<StyleSelection />
|
||||
</div>
|
||||
<div className="fixed bottom-0 left-0 w-full">
|
||||
<div className="flex h-[62px] w-full items-center justify-center gap-5 bg-ui-panel">
|
||||
<div>
|
||||
<Button variant="action" onClick={generateFrame}>Update Preview</Button>
|
||||
</div>
|
||||
<div>
|
||||
<Button variant="primary" onClick={generateMovie}>Generate Movie</Button>
|
||||
<div className="flex flex-col items-center">
|
||||
<StyleSelection />
|
||||
<div className="flex w-full justify-center gap-4 rounded-b-lg bg-ui-panel pb-5">
|
||||
<Button
|
||||
icon={faArrowsRotate}
|
||||
variant="action"
|
||||
onClick={generateFrame}
|
||||
>
|
||||
Update Preview
|
||||
</Button>
|
||||
<Button icon={faFilm} variant="primary" onClick={generateMovie}>
|
||||
Generate Movie
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="fixed bottom-0 left-0 w-full">
|
||||
<div className="relative flex h-[80px] w-full gap-5 border-t border-t-action-600 bg-ui-panel">
|
||||
<LowerPanel onStyle>
|
||||
<TimerGrid />
|
||||
|
||||
@@ -59,9 +59,9 @@ export const Controls3D = ({ setPage }: Props) => {
|
||||
};
|
||||
|
||||
const changeStylize = () => {
|
||||
editorEngine?.switchPreview();
|
||||
editorEngine?.switchPreview();
|
||||
setPage("style");
|
||||
}
|
||||
};
|
||||
|
||||
const modes = [
|
||||
{ value: "move", icon: faArrowsUpDownLeftRight },
|
||||
@@ -73,13 +73,13 @@ export const Controls3D = ({ setPage }: Props) => {
|
||||
<div>
|
||||
<div className="flex justify-center">
|
||||
<div className="rounded-b-lg border-x border-b border-ui-panel-border bg-ui-controls p-2 text-white">
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<div className="flex items-center justify-center gap-3">
|
||||
<ButtonIconSelect
|
||||
options={modes}
|
||||
onOptionChange={handleModeChange}
|
||||
/>
|
||||
|
||||
<span className="h-4 w-0 border-l border-white/[0.15]" />
|
||||
<span className="h-6 w-0 border-l border-white/[0.2]" />
|
||||
|
||||
<Button variant="primary" onClick={() => changeStylize()}>
|
||||
Stylize <FontAwesomeIcon icon={faAngleRight} />
|
||||
|
||||
@@ -8,7 +8,7 @@ export const PreviewImages = () => {
|
||||
|
||||
const imageWidth1 = pageWidth.value > 1340 ? 630 : (pageWidth.value - 80) / 2;
|
||||
const imageHeight1 = imageWidth1 * 0.56;
|
||||
const imageHeight2 = pageHeight.value > 1138 ? 354 : pageHeight.value - 620;
|
||||
const imageHeight2 = pageHeight.value > 1138 ? 354 : pageHeight.value - 650;
|
||||
const imageWidth2 = imageHeight2 / 0.56;
|
||||
|
||||
const imageWidth = imageHeight1 < imageHeight2 ? imageWidth1 : imageWidth2;
|
||||
@@ -21,18 +21,14 @@ export const PreviewImages = () => {
|
||||
].join(" ");
|
||||
|
||||
return (
|
||||
<div className="flex justify-center gap-2">
|
||||
<div className="flex justify-center gap-1">
|
||||
<div className="flex flex-col" style={{ width: imageWidth }}>
|
||||
<div className={textClasses}>Raw Preview</div>
|
||||
<div
|
||||
className="block w-full rounded-b-lg"
|
||||
className="block w-full overflow-hidden rounded-b-lg"
|
||||
style={{ height: imageHeight }}
|
||||
>
|
||||
<canvas
|
||||
id="raw-preview"
|
||||
width={imageWidth}
|
||||
height={imageHeight}
|
||||
/>
|
||||
<canvas id="raw-preview" width={imageWidth} height={imageHeight} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-[40px] flex-col justify-center">
|
||||
@@ -41,7 +37,7 @@ export const PreviewImages = () => {
|
||||
<div className="flex flex-col" style={{ width: imageWidth }}>
|
||||
<div className={textClasses}>Styled Preview</div>
|
||||
<div
|
||||
className="block w-full rounded-b-lg"
|
||||
className="block w-full overflow-hidden rounded-b-lg"
|
||||
style={{ height: imageHeight }}
|
||||
>
|
||||
<img id="styled-preview" width={imageWidth} height={imageHeight} />
|
||||
|
||||
@@ -46,55 +46,62 @@ export const StyleSelection = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-[280px] w-[800px] flex-col gap-3 rounded-lg bg-ui-panel p-4">
|
||||
<div className="flex flex-col gap-4 rounded-t-lg bg-ui-panel p-5">
|
||||
<div className="flex w-full flex-col">
|
||||
<Label>Select Base Style</Label>
|
||||
<div
|
||||
className="relative overflow-x-hidden"
|
||||
style={{ width: 768, height: 80 }}
|
||||
>
|
||||
<div className="relative">
|
||||
<div
|
||||
className="absolute flex gap-2"
|
||||
style={{
|
||||
width: styleList.length * 84 + 26,
|
||||
left: scrollPosition * -86,
|
||||
top: 0,
|
||||
}}
|
||||
className="relative overflow-x-hidden"
|
||||
style={{ width: 768, height: 80 }}
|
||||
>
|
||||
{styleList.map((style) => (
|
||||
<ItemPicker
|
||||
key={style.type}
|
||||
label={style.label}
|
||||
type={style.type}
|
||||
selected={selection === style.type}
|
||||
onSelected={handlePickingStylizer}
|
||||
src={style.image}
|
||||
width={80}
|
||||
height={80}
|
||||
/>
|
||||
))}
|
||||
<div
|
||||
className="absolute flex gap-2 transition-all duration-300 ease-in-out"
|
||||
style={{
|
||||
width: styleList.length * 84 + 26,
|
||||
left: scrollPosition * -86,
|
||||
top: 0,
|
||||
}}
|
||||
>
|
||||
{styleList.map((style) => (
|
||||
<ItemPicker
|
||||
key={style.type}
|
||||
label={style.label}
|
||||
type={style.type}
|
||||
selected={selection === style.type}
|
||||
onSelected={handlePickingStylizer}
|
||||
src={style.image}
|
||||
width={80}
|
||||
height={80}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{scrollPosition > 0 && (
|
||||
<div className="absolute left-3 top-5">
|
||||
<ButtonIcon
|
||||
icon={faAngleLeft}
|
||||
onClick={() =>
|
||||
setScrollPosition(Math.max(scrollPosition - 6, 0))
|
||||
}
|
||||
/>
|
||||
<div className="pointer-events-none absolute left-[-10px] top-0 h-full w-12 bg-gradient-to-r from-ui-panel to-transparent">
|
||||
<div className="flex h-full w-full items-center justify-start">
|
||||
<ButtonIcon
|
||||
icon={faAngleLeft}
|
||||
onClick={() =>
|
||||
setScrollPosition(Math.max(scrollPosition - 6, 0))
|
||||
}
|
||||
className="pointer-events-auto h-6 w-6 rounded-full bg-white/80 text-gray-800/75 hover:bg-white/100 hover:text-gray-800"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{scrollPosition < styleList.length - 9 && (
|
||||
<div className="absolute right-3 top-5">
|
||||
<ButtonIcon
|
||||
icon={faAngleRight}
|
||||
onClick={() =>
|
||||
setScrollPosition(
|
||||
Math.min(scrollPosition + 6, styleList.length - 9),
|
||||
)
|
||||
}
|
||||
fill
|
||||
/>
|
||||
<div className="pointer-events-none absolute right-[-10px] top-0 h-full w-12 bg-gradient-to-l from-ui-panel to-transparent">
|
||||
<div className="flex h-full w-full items-center justify-end">
|
||||
<ButtonIcon
|
||||
icon={faAngleRight}
|
||||
onClick={() =>
|
||||
setScrollPosition(
|
||||
Math.min(scrollPosition + 6, styleList.length - 9),
|
||||
)
|
||||
}
|
||||
className="pointer-events-auto h-6 w-6 rounded-full bg-white/80 text-gray-800/75 hover:bg-white/100 hover:text-gray-800"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -40,10 +40,10 @@ export const TrackKeyFrame = ({ keyframe, updateKeyframe }: Props) => {
|
||||
: "bg-keyframe-unselected",
|
||||
].join(" ")}
|
||||
style={{
|
||||
width: 18,
|
||||
height: 18,
|
||||
width: 14,
|
||||
height: 14,
|
||||
left: displayOffset * 4 * scale.value - 6,
|
||||
top: 8,
|
||||
top: 11,
|
||||
}}
|
||||
onPointerDown={(event) => onPointerDown(event, "drag")}
|
||||
onClick={() => (selectedItem.value = keyframe)}
|
||||
|
||||
Reference in new issue
Block a user