Skip to content

Commit e2ae270

Browse files
authored
Merge pull request #241 from Dumb-Code/photoshop-groups
Added Photoshop support to texture groups
2 parents bad8664 + 4e79de1 commit e2ae270

File tree

13 files changed

+501
-101
lines changed

13 files changed

+501
-101
lines changed

src/components/ClickableInput.tsx

Lines changed: 8 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,25 @@
11
import { PropsWithChildren } from "react"
2-
import { useTooltipRef } from "../contexts/TooltipContext"
3-
import { createReadableFile, createReadableFileExtended, FileSystemsAccessApi, ReadableFile } from "../studio/files/FileTypes"
2+
import { FileInputClickOptions, getFilesFromClick } from "../studio/files/FileInputClick"
43

5-
type Props = PropsWithChildren<{
6-
description: string
7-
accept: string[]
4+
type Props = PropsWithChildren<FileInputClickOptions & {
85
disabled?: boolean
9-
multiple?: boolean
10-
onFile: (file: ReadableFile) => void
116
className?: string
127
tooltip?: string
138
}>
149

15-
const ClickableInput = (props: Props) => {
16-
const ref = useTooltipRef<HTMLInputElement>(props.tooltip !== undefined ? () => props.tooltip : null)
10+
const ClickableInput = ({ disabled, className, tooltip, children, accept, description, onFile, multiple }: Props) => {
1711

1812
const onClick = () => {
19-
if (!FileSystemsAccessApi) {
20-
ref.current?.click()
13+
if (disabled) {
2114
return
2215
}
23-
window.showOpenFilePicker({
24-
multiple: props.multiple ?? false,
25-
types: [{
26-
description: props.description,
27-
accept: {
28-
"custom/dumbcode": props.accept
29-
}
30-
}]
31-
}).then(res => {
32-
res.forEach(handle => props.onFile(createReadableFileExtended(handle)))
33-
}).catch(() => { })
16+
getFilesFromClick({ accept, description, multiple, onFile })
3417
}
3518

3619
return (
37-
<>
38-
<input
39-
disabled={props.disabled}
40-
ref={ref}
41-
onChange={e => {
42-
const files = e.currentTarget.files
43-
if (files !== null) {
44-
for (let i = 0; i < files.length; i++) {
45-
const file = files.item(i)
46-
if (file !== null) {
47-
props.onFile(createReadableFile(file))
48-
}
49-
}
50-
}
51-
}}
52-
className="hidden"
53-
accept={props.accept.join(",")}
54-
type="file"
55-
multiple={props.multiple ?? false}
56-
/>
57-
<button disabled={props.disabled} className={props.className} onClick={onClick}>
58-
{props.children}
59-
</button>
60-
</>
20+
<button disabled={disabled} className={className} onClick={onClick}>
21+
{children}
22+
</button>
6123
)
6224
}
6325
export default ClickableInput

src/components/Icons.tsx

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ export const SVGChevronDown = (props: SVGProps<SVGSVGElement>) => {
6464
)
6565
}
6666

67+
export const SVGCaretDown = (props: SVGProps<SVGSVGElement>) => {
68+
return (
69+
<svg xmlns="http://www.w3.org/2000/svg" clipRule="evenodd" fillRule="evenodd" strokeLinejoin="round" strokeMiterlimit="2" viewBox="0 0 24 24" stroke="currentColor" fill="currentColor" {...props}>
70+
<path xmlns="http://www.w3.org/2000/svg" d="m16.843 10.211c.108-.141.157-.3.157-.456 0-.389-.306-.755-.749-.755h-8.501c-.445 0-.75.367-.75.755 0 .157.05.316.159.457 1.203 1.554 3.252 4.199 4.258 5.498.142.184.36.29.592.29.23 0 .449-.107.591-.291 1.002-1.299 3.044-3.945 4.243-5.498z" />
71+
</svg>
72+
)
73+
}
74+
6775
export const SVGCube = (props: SVGProps<SVGSVGElement>) => {
6876
return (
6977
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" {...props}>
@@ -404,7 +412,7 @@ export const SvgArrowRight = (props: SVGProps<SVGSVGElement>) => (
404412
export const SvgPhotoshop = (props: SVGProps<SVGSVGElement>) => (
405413
<svg
406414
xmlns="http://www.w3.org/2000/svg"
407-
viewBox="150 100 400 400"
415+
viewBox="200 100 300 400"
408416
{...props}
409417
>
410418
<path
@@ -418,6 +426,20 @@ export const SvgPhotoshop = (props: SVGProps<SVGSVGElement>) => (
418426
</svg>
419427
);
420428

429+
export const SVGChain = (props: SVGProps<SVGSVGElement>) => (
430+
<svg
431+
xmlns="http://www.w3.org/2000/svg"
432+
width="24" height="24"
433+
viewBox="0 0 24 24"
434+
{...props}
435+
>
436+
<path
437+
fill="currentColor"
438+
d="M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z"
439+
/>
440+
</svg>
441+
);
442+
421443
export const SvgPoweredByVercel = (props: SVGProps<SVGSVGElement>) => (
422444
<svg
423445
width={212}
@@ -456,4 +478,4 @@ export const SvgGithub = (props: SVGProps<SVGSVGElement>) => (
456478
d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"
457479
/>
458480
</svg>
459-
);
481+
);

src/contexts/ToastContext.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createContext, ReactNode, useCallback, useContext, useLayoutEffect, useMemo, useState } from "react"
22
import { v4 } from "uuid"
33
import { LO, useListenableObject } from "../studio/listenableobject/ListenableObject"
4+
import UnsafeOperations from "../studio/util/UnsafeOperations"
45
import { useCreatePortal } from "./CreatePortalContext"
56

67
//Info IS used btw
@@ -72,6 +73,8 @@ const ToastContext = ({ children }: { children: ReactNode }) => {
7273
}, duration)
7374
}, [])
7475

76+
UnsafeOperations._unsafe_AddToast = addToast
77+
7578
// // Uncomment this to test the toasts
7679
// useEffect(() => {
7780
// const test = setInterval(() => {

src/studio/files/FileInputClick.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { createReadableFile, createReadableFileExtended, FileSystemsAccessApi, ReadableFile } from "./FileTypes"
2+
3+
export type FileInputClickOptions = {
4+
description: string
5+
accept: string[]
6+
multiple?: boolean
7+
onFile: (file: ReadableFile) => void
8+
}
9+
10+
export const getFilesFromClick = ({ description, accept, multiple, onFile }: FileInputClickOptions) => {
11+
if (FileSystemsAccessApi) {
12+
getFileSystemApiFilesFromClick({ description, accept, multiple, onFile })
13+
} else {
14+
getOldFilesFromClick({ description, accept, multiple, onFile })
15+
}
16+
}
17+
18+
const getFileSystemApiFilesFromClick = async ({ description, accept, multiple, onFile }: FileInputClickOptions) => {
19+
const files = await window.showOpenFilePicker({
20+
multiple: multiple ?? false,
21+
types: [{
22+
description: description,
23+
accept: {
24+
"custom/dumbcode": accept
25+
}
26+
}]
27+
})
28+
for (const file of files) {
29+
onFile(createReadableFileExtended(file))
30+
}
31+
}
32+
33+
const getOldFilesFromClick = ({ description, accept, multiple, onFile }: FileInputClickOptions) => {
34+
const element = document.createElement("input")
35+
element.type = "file"
36+
element.accept = accept.join(",")
37+
element.multiple = multiple ?? false
38+
element.addEventListener("change", e => {
39+
const files = element.files
40+
if (files !== null) {
41+
for (let i = 0; i < files.length; i++) {
42+
const file = files.item(i)
43+
if (file !== null) {
44+
onFile(createReadableFile(file))
45+
}
46+
}
47+
}
48+
})
49+
}

src/studio/files/FileTypes.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type ReadableFile = {
3131

3232
export type WritableFile = {
3333
write: (name: string, blob: Blob | PromiseLike<Blob>, types?: FilePickerAcceptType[]) => Promise<string>
34+
asReadable: () => ReadableFile | null
3435
} & ListenableFile
3536

3637
export type OpenableFolder = {
@@ -50,13 +51,14 @@ export const downloadBlob: WritableFile['write'] = async (name, blob) => {
5051

5152
export const defaultWritable: WritableFile = {
5253
write: async (name, blob) => downloadBlob(name, await blob),
53-
startListening: () => null
54+
startListening: () => null,
55+
asReadable: () => null,
5456
}
5557

5658
//Gets the writeable file for where nothing has been defined.
5759
export const getUndefinedWritable = (description: string, ...accept: string[]): WritableFile & {
5860
unlink?: () => void,
59-
getName?: () => string | undefined
61+
getName?: () => string | undefined,
6062
} => {
6163
if (!FileSystemsAccessApi) {
6264
return defaultWritable
@@ -92,8 +94,8 @@ export const getUndefinedWritable = (description: string, ...accept: string[]):
9294
file = null
9395
readable = null
9496
},
95-
getName: () => saveName ?? undefined
96-
97+
getName: () => saveName ?? undefined,
98+
asReadable: () => readable,
9799
}
98100
}
99101

@@ -135,7 +137,7 @@ export const createReadableFile = (file: File): ReadableFile => {
135137
export const createReadableFileExtended = (handle: FileSystemFileHandle): ReadableFile => {
136138
const startListening: ListenableFile['startListening'] = listener => listener.addFile(() => handle.getFile())
137139

138-
return {
140+
const readableFile: ReadableFile = {
139141
asFile: () => handle.getFile(),
140142
asWritable: () => {
141143
return {
@@ -145,12 +147,15 @@ export const createReadableFileExtended = (handle: FileSystemFileHandle): Readab
145147
await writable.close()
146148
return handle.name
147149
},
148-
startListening
150+
startListening,
151+
asReadable: () => readableFile,
149152
}
150153
},
151154
name: handle.name,
152155
startListening
153156
}
157+
158+
return readableFile
154159
}
155160

156161

src/studio/formats/project/DcProjectLoader.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { imgSourceToElement, writeImgToBlob } from "../../util/Utils";
66
import { loadUnknownAnimation, writeDCAAnimation } from "../animations/DCALoader";
77
import { loadModelUnknown, writeModel } from "../model/DCMLoader";
88
import { DCMCube } from "../model/DcmModel";
9-
import { loadFromPsdFile, saveToPhotoshopFile } from "../textures/PhotoshopManager";
109
import { TextureGroup } from "../textures/TextureManager";
10+
import { loadFromPsdFile, saveToPhotoshopFile } from "../textures/TexturePhotoshopManager";
1111
import { wrapFolder } from './../../files/FileTypes';
1212
import { NumArray } from './../../util/NumArray';
1313
import { KeyframeLayerData } from './../animations/DcaAnimation';

0 commit comments

Comments
 (0)