krunakuamar
commited on
Commit
•
ed01507
1
Parent(s):
d45f692
Upload 216 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- Dockerfile +22 -0
- README.md +66 -0
- app.py +322 -0
- docker/CPUDockerfile +17 -0
- docker/GPUDockerfile +17 -0
- lama_cleaner/__init__.py +11 -0
- lama_cleaner/__pycache__/__init__.cpython-38.pyc +0 -0
- lama_cleaner/__pycache__/const.cpython-38.pyc +0 -0
- lama_cleaner/__pycache__/helper.cpython-38.pyc +0 -0
- lama_cleaner/__pycache__/interactive_seg.cpython-38.pyc +0 -0
- lama_cleaner/__pycache__/model_manager.cpython-38.pyc +0 -0
- lama_cleaner/__pycache__/parse_args.cpython-38.pyc +0 -0
- lama_cleaner/__pycache__/runtime.cpython-38.pyc +0 -0
- lama_cleaner/__pycache__/schema.cpython-38.pyc +0 -0
- lama_cleaner/__pycache__/server2.cpython-38.pyc +0 -0
- lama_cleaner/app/.env +1 -0
- lama_cleaner/app/.eslintrc.json +52 -0
- lama_cleaner/app/.gitignore +27 -0
- lama_cleaner/app/.prettierrc +6 -0
- lama_cleaner/app/LICENSE +201 -0
- lama_cleaner/app/build/asset-manifest.json +15 -0
- lama_cleaner/app/build/index.html +1 -0
- lama_cleaner/app/build/static/css/main.c28d98ca.css +1 -0
- lama_cleaner/app/build/static/js/main.1bd455bc.js +0 -0
- lama_cleaner/app/build/static/js/main.1bd455bc.js.LICENSE.txt +60 -0
- lama_cleaner/app/build/static/media/WorkSans-Black.67c2c5a144333953880b.ttf +0 -0
- lama_cleaner/app/build/static/media/WorkSans-Bold.2bea7a7f7d052c74da25.ttf +0 -0
- lama_cleaner/app/build/static/media/WorkSans-Regular.bb287b894b27372d8ea7.ttf +0 -0
- lama_cleaner/app/build/static/media/WorkSans-SemiBold.1e98db4eb705b586728e.ttf +0 -0
- lama_cleaner/app/config/env.js +104 -0
- lama_cleaner/app/config/getHttpsConfig.js +66 -0
- lama_cleaner/app/config/jest/babelTransform.js +29 -0
- lama_cleaner/app/config/jest/cssTransform.js +14 -0
- lama_cleaner/app/config/jest/fileTransform.js +40 -0
- lama_cleaner/app/config/modules.js +134 -0
- lama_cleaner/app/config/paths.js +77 -0
- lama_cleaner/app/config/webpack.config.js +761 -0
- lama_cleaner/app/config/webpack/persistentCache/createEnvironmentHash.js +9 -0
- lama_cleaner/app/config/webpackDevServer.config.js +127 -0
- lama_cleaner/app/package.json +180 -0
- lama_cleaner/app/public/index.html +33 -0
- lama_cleaner/app/scripts/build.js +217 -0
- lama_cleaner/app/scripts/start.js +154 -0
- lama_cleaner/app/scripts/test.js +52 -0
- lama_cleaner/app/src/App.tsx +204 -0
- lama_cleaner/app/src/adapters/inpainting.ts +225 -0
- lama_cleaner/app/src/components/CoffeeIcon/CoffeeIcon.tsx +66 -0
- lama_cleaner/app/src/components/Croper/Croper.scss +167 -0
- lama_cleaner/app/src/components/Croper/Croper.tsx +408 -0
- lama_cleaner/app/src/components/Editor/Editor.scss +111 -0
Dockerfile
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.8
|
2 |
+
# ENV MPLCONFIGDIR=/tmp/matplotlib-399fa59w
|
3 |
+
RUN mkdir -m 777 -p /app/
|
4 |
+
|
5 |
+
RUN mkdir -m 777 -p /.cache/matplotlib
|
6 |
+
RUN mkdir -m 777 -p /.cache/huggingface/hub/
|
7 |
+
RUN mkdir -m 777 -p /.cache/torch/
|
8 |
+
RUN mkdir -m 777 -p /.cache/
|
9 |
+
RUN mkdir -m 777 -p /.config/matplotlib/
|
10 |
+
|
11 |
+
|
12 |
+
RUN apt-get update && apt-get install ffmpeg libsm6 libxext6 -y
|
13 |
+
COPY ./app.py ./app.py
|
14 |
+
COPY ./lama_cleaner ./lama_cleaner
|
15 |
+
COPY ./yolov8x-seg.pt ./yolov8x-seg.pt
|
16 |
+
COPY ./requirements.txt ./requirements.txt
|
17 |
+
RUN pip install -r ./requirements.txt
|
18 |
+
ENV HOST="0.0.0.0"
|
19 |
+
ENV PORT=7860
|
20 |
+
|
21 |
+
#ENTRYPOINT python3 app.py --host ${HOST} --port ${PORT}
|
22 |
+
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
README.md
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<h1 align="center" >Remove Objects Server</h1>
|
2 |
+
|
3 |
+
|
4 |
+
<!-- TABLE OF CONTENTS -->
|
5 |
+
<details>
|
6 |
+
<summary>Table of Contents</summary>
|
7 |
+
<ol>
|
8 |
+
<li><a href="#about-the-project">About</a></li>
|
9 |
+
<li><a href="#built-with">Installation</a></li>
|
10 |
+
<li><a href="#usage">Usage</a></li>
|
11 |
+
<li><a href="#license">License</a></li>
|
12 |
+
|
13 |
+
</ol>
|
14 |
+
</details>
|
15 |
+
|
16 |
+
## About
|
17 |
+
|
18 |
+
|
19 |
+
This is a Python project for removing unwanted objects from images using the inpainting technique. It includes a server implemented with FastAPI and an endpoint for processing images by applying inpainting techniques. This project uses a deep learning library, PyTorch, for training and testing the inpainting model.
|
20 |
+
|
21 |
+
<p align="center">
|
22 |
+
<img src="lama_cleaner_video.gif" />
|
23 |
+
</p>
|
24 |
+
|
25 |
+
## Installation
|
26 |
+
|
27 |
+
To install this project, you should first create a virtual environment using the following commands:
|
28 |
+
|
29 |
+
```bash
|
30 |
+
python3 -m venv venv
|
31 |
+
source venv/bin/activate
|
32 |
+
```
|
33 |
+
After creating the virtual environment, you can install the required libraries using pip:
|
34 |
+
|
35 |
+
```bash
|
36 |
+
pip install -r requirements.txt
|
37 |
+
```
|
38 |
+
|
39 |
+
## Usage
|
40 |
+
|
41 |
+
To use this project, first start the server by running main.py:
|
42 |
+
|
43 |
+
```bash
|
44 |
+
python main.py
|
45 |
+
```
|
46 |
+
|
47 |
+
After the server has started, you can test following endpoints:
|
48 |
+
|
49 |
+
- `http://{localhost}:{port}/lama/paint`
|
50 |
+
- This endpoint accepts an image file in the `file` parameter and applies inpainting techniques to remove unwanted objects.
|
51 |
+
|
52 |
+
- `http://{localhost}:{port}/mask`
|
53 |
+
- Mask endpoint is used to apply a mask to an image. The route accepts `img` and `mask` as input parameters. Then, it applies a mask on an image.
|
54 |
+
- You can use `testX.png` image and `testX_mask.png` mask in image folder for testing.
|
55 |
+
|
56 |
+
## License
|
57 |
+
|
58 |
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
59 |
+
|
60 |
+
|
61 |
+
Other command
|
62 |
+
|
63 |
+
```bash
|
64 |
+
docker build -t zest .
|
65 |
+
```
|
66 |
+
|
app.py
ADDED
@@ -0,0 +1,322 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import base64
|
2 |
+
import imghdr
|
3 |
+
import os
|
4 |
+
|
5 |
+
import cv2
|
6 |
+
import numpy as np
|
7 |
+
import psutil
|
8 |
+
import pyinstrument
|
9 |
+
import torch
|
10 |
+
from ultralytics import YOLO
|
11 |
+
from ultralytics.yolo.utils.ops import scale_image
|
12 |
+
import asyncio
|
13 |
+
from fastapi import FastAPI, File, UploadFile
|
14 |
+
from fastapi.middleware.cors import CORSMiddleware
|
15 |
+
import uvicorn
|
16 |
+
# from mangum import Mangum
|
17 |
+
|
18 |
+
from argparse import ArgumentParser
|
19 |
+
|
20 |
+
import lama_cleaner.server2 as server
|
21 |
+
from lama_cleaner.helper import (
|
22 |
+
load_img,
|
23 |
+
)
|
24 |
+
|
25 |
+
# os.environ["TRANSFORMERS_CACHE"] = "/path/to/writable/directory"
|
26 |
+
|
27 |
+
app = FastAPI()
|
28 |
+
# handler = Mangum(app)
|
29 |
+
|
30 |
+
origins = ["*"]
|
31 |
+
|
32 |
+
app.add_middleware(
|
33 |
+
CORSMiddleware,
|
34 |
+
allow_origins=origins,
|
35 |
+
allow_credentials=True,
|
36 |
+
allow_methods=["*"],
|
37 |
+
allow_headers=["*"],
|
38 |
+
)
|
39 |
+
|
40 |
+
def numpy_to_bytes(image_numpy: np.ndarray, ext: str) -> bytes:
|
41 |
+
"""
|
42 |
+
Args:
|
43 |
+
image_numpy: numpy image
|
44 |
+
ext: image extension
|
45 |
+
Returns:
|
46 |
+
image bytes
|
47 |
+
"""
|
48 |
+
data = cv2.imencode(
|
49 |
+
f".{ext}",
|
50 |
+
image_numpy,
|
51 |
+
[int(cv2.IMWRITE_JPEG_QUALITY), 100, int(cv2.IMWRITE_PNG_COMPRESSION), 0],
|
52 |
+
)[1].tobytes()
|
53 |
+
return data
|
54 |
+
|
55 |
+
|
56 |
+
def get_image_ext(img_bytes):
|
57 |
+
"""
|
58 |
+
Args:
|
59 |
+
img_bytes: image bytes
|
60 |
+
Returns:
|
61 |
+
image extension
|
62 |
+
"""
|
63 |
+
if not img_bytes:
|
64 |
+
raise ValueError("Empty input")
|
65 |
+
header = img_bytes[:32]
|
66 |
+
w = imghdr.what("", header)
|
67 |
+
if w is None:
|
68 |
+
w = "jpeg"
|
69 |
+
return w
|
70 |
+
|
71 |
+
|
72 |
+
def predict_on_image(model, img, conf, retina_masks):
|
73 |
+
"""
|
74 |
+
Args:
|
75 |
+
model: YOLOv8 model
|
76 |
+
img: image (C, H, W)
|
77 |
+
conf: confidence threshold
|
78 |
+
retina_masks: use retina masks or not
|
79 |
+
Returns:
|
80 |
+
boxes: box with xyxy format, (N, 4)
|
81 |
+
masks: masks, (N, H, W)
|
82 |
+
cls: class of masks, (N, )
|
83 |
+
probs: confidence score, (N, 1)
|
84 |
+
"""
|
85 |
+
with torch.no_grad():
|
86 |
+
result = model(img, conf=conf, retina_masks=retina_masks, scale=1)[0]
|
87 |
+
|
88 |
+
|
89 |
+
boxes, masks, cls, probs = None, None, None, None
|
90 |
+
|
91 |
+
if result.boxes.cls.size(0) > 0:
|
92 |
+
# detection
|
93 |
+
cls = result.boxes.cls.cpu().numpy().astype(np.int32)
|
94 |
+
probs = result.boxes.conf.cpu().numpy() # confidence score, (N, 1)
|
95 |
+
boxes = result.boxes.xyxy.cpu().numpy() # box with xyxy format, (N, 4)
|
96 |
+
|
97 |
+
# segmentation
|
98 |
+
masks = result.masks.masks.cpu().numpy() # masks, (N, H, W)
|
99 |
+
masks = np.transpose(masks, (1, 2, 0)) # masks, (H, W, N)
|
100 |
+
# rescale masks to original image
|
101 |
+
masks = scale_image(masks.shape[:2], masks, result.masks.orig_shape)
|
102 |
+
masks = np.transpose(masks, (2, 0, 1)) # masks, (N, H, W)
|
103 |
+
|
104 |
+
return boxes, masks, cls, probs
|
105 |
+
|
106 |
+
|
107 |
+
def overlay(image, mask, color, alpha, id, resize=None):
|
108 |
+
"""Overlays a binary mask on an image.
|
109 |
+
|
110 |
+
Args:
|
111 |
+
image: Image to be overlayed on.
|
112 |
+
mask: Binary mask to overlay.
|
113 |
+
color: Color to use for the mask.
|
114 |
+
alpha: Opacity of the mask.
|
115 |
+
id: id of the mask
|
116 |
+
resize: Resize the image to this size. If None, no resizing is performed.
|
117 |
+
|
118 |
+
Returns:
|
119 |
+
The overlayed image.
|
120 |
+
"""
|
121 |
+
color = color[::-1]
|
122 |
+
colored_mask = np.expand_dims(mask, 0).repeat(3, axis=0)
|
123 |
+
colored_mask = np.moveaxis(colored_mask, 0, -1)
|
124 |
+
masked = np.ma.MaskedArray(image, mask=colored_mask, fill_value=color)
|
125 |
+
image_overlay = masked.filled()
|
126 |
+
|
127 |
+
imgray = cv2.cvtColor(image_overlay, cv2.COLOR_BGR2GRAY)
|
128 |
+
|
129 |
+
contour_thickness = 8
|
130 |
+
_, thresh = cv2.threshold(imgray, 255, 255, 255)
|
131 |
+
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
|
132 |
+
imgray = cv2.cvtColor(imgray, cv2.COLOR_GRAY2BGR)
|
133 |
+
imgray = cv2.drawContours(imgray, contours, -1, (255, 255, 255), contour_thickness)
|
134 |
+
|
135 |
+
imgray = np.where(imgray.any(-1, keepdims=True), (46, 36, 225), 0)
|
136 |
+
|
137 |
+
if resize is not None:
|
138 |
+
image = cv2.resize(image.transpose(1, 2, 0), resize)
|
139 |
+
image_overlay = cv2.resize(image_overlay.transpose(1, 2, 0), resize)
|
140 |
+
|
141 |
+
return imgray
|
142 |
+
|
143 |
+
|
144 |
+
async def process_mask(idx, mask_i, boxes, probs, yolo_model, blank_image, cls):
|
145 |
+
"""Process the mask of the image.
|
146 |
+
|
147 |
+
Args:
|
148 |
+
idx: index of the mask
|
149 |
+
mask_i: mask of the image
|
150 |
+
boxes: box with xyxy format, (N, 4)
|
151 |
+
probs: confidence score, (N, 1)
|
152 |
+
yolo_model: YOLOv8 model
|
153 |
+
blank_image: blank image
|
154 |
+
cls: class of masks, (N, )
|
155 |
+
|
156 |
+
Returns:
|
157 |
+
dictionary_seg: dictionary of the mask of the image
|
158 |
+
"""
|
159 |
+
dictionary_seg = {}
|
160 |
+
maskwith_back = overlay(blank_image, mask_i, color=(255, 155, 155), alpha=0.5, id=idx)
|
161 |
+
|
162 |
+
alpha = np.sum(maskwith_back, axis=-1) > 0
|
163 |
+
alpha = np.uint8(alpha * 255)
|
164 |
+
maskwith_back = np.dstack((maskwith_back, alpha))
|
165 |
+
|
166 |
+
imgencode = await asyncio.get_running_loop().run_in_executor(None, cv2.imencode, '.png', maskwith_back)
|
167 |
+
mask = base64.b64encode(imgencode[1]).decode('utf-8')
|
168 |
+
|
169 |
+
dictionary_seg["confi"] = f'{probs[idx] * 100:.2f}'
|
170 |
+
dictionary_seg["boxe"] = [int(item) for item in list(boxes[idx])]
|
171 |
+
dictionary_seg["mask"] = mask
|
172 |
+
dictionary_seg["cls"] = str(yolo_model.names[cls[idx]])
|
173 |
+
|
174 |
+
return dictionary_seg
|
175 |
+
|
176 |
+
|
177 |
+
@app.post("/api/mask")
|
178 |
+
async def detect_mask(file: UploadFile = File()):
|
179 |
+
"""
|
180 |
+
Detects masks in an image uploaded via a POST request and returns a JSON response containing the details of the detected masks.
|
181 |
+
|
182 |
+
Args:
|
183 |
+
None
|
184 |
+
|
185 |
+
Parameters:
|
186 |
+
- file: a file object containing the input image
|
187 |
+
|
188 |
+
Returns:
|
189 |
+
A JSON response containing the details of the detected masks:
|
190 |
+
- code: 200 if objects were detected, 500 if no objects were detected
|
191 |
+
- msg: a message indicating whether objects were detected or not
|
192 |
+
- data: a list of dictionaries, where each dictionary contains the following keys:
|
193 |
+
- confi: the confidence level of the detected object
|
194 |
+
- boxe: a list containing the coordinates of the bounding box of the detected object
|
195 |
+
- mask: the mask of the detected object encoded in base64
|
196 |
+
- cls: the class of the detected object
|
197 |
+
|
198 |
+
Raises:
|
199 |
+
500: No objects detected
|
200 |
+
"""
|
201 |
+
file = await file.read()
|
202 |
+
|
203 |
+
img, _ = load_img(file)
|
204 |
+
|
205 |
+
# predict by YOLOv8
|
206 |
+
boxes, masks, cls, probs = predict_on_image(yolo_model, img, conf=0.55, retina_masks=True)
|
207 |
+
|
208 |
+
if boxes.size == 0:
|
209 |
+
return {'code': 500, 'msg': 'No objects detected'}
|
210 |
+
|
211 |
+
# overlay masks on original image
|
212 |
+
blank_image = np.zeros(img.shape, dtype=np.uint8)
|
213 |
+
|
214 |
+
data = []
|
215 |
+
|
216 |
+
coroutines = [process_mask(idx, mask_i, boxes, probs, yolo_model, blank_image, cls) for idx, mask_i in enumerate(masks)]
|
217 |
+
results = await asyncio.gather(*coroutines)
|
218 |
+
|
219 |
+
for result in results:
|
220 |
+
data.append(result)
|
221 |
+
|
222 |
+
return {'code': 200, 'msg': "object detected", 'data': data}
|
223 |
+
|
224 |
+
|
225 |
+
@app.post("/api/lama/paint")
|
226 |
+
async def paint(img: UploadFile = File(), mask: UploadFile = File()):
|
227 |
+
"""
|
228 |
+
Endpoint to process an image with a given mask using the server's process function.
|
229 |
+
|
230 |
+
Route: '/api/lama/paint'
|
231 |
+
Method: POST
|
232 |
+
|
233 |
+
Parameters:
|
234 |
+
img: The input image file (JPEG or PNG format).
|
235 |
+
mask: The mask file (JPEG or PNG format).
|
236 |
+
Returns:
|
237 |
+
A JSON object containing the processed image in base64 format under the "image" key.
|
238 |
+
"""
|
239 |
+
|
240 |
+
img = await img.read()
|
241 |
+
mask = await mask.read()
|
242 |
+
|
243 |
+
profiler = pyinstrument.Profiler()
|
244 |
+
profiler.start()
|
245 |
+
|
246 |
+
x = {"image": server.process(img, mask)}
|
247 |
+
|
248 |
+
profiler.stop()
|
249 |
+
print("--------START------")
|
250 |
+
os.system("nvidia-smi")
|
251 |
+
print(profiler.output_text(unicode=True, color=True))
|
252 |
+
|
253 |
+
process = psutil.Process()
|
254 |
+
memory_info = process.memory_info()
|
255 |
+
cpu_percent = psutil.cpu_percent()
|
256 |
+
|
257 |
+
print("Memory usage: {} MB".format(memory_info.rss / 1048576))
|
258 |
+
print("CPU usage: {}%".format(cpu_percent))
|
259 |
+
print("--------END------")
|
260 |
+
|
261 |
+
return x
|
262 |
+
|
263 |
+
|
264 |
+
@app.post("/api/lama/model")
|
265 |
+
def switch_model(new_name: str):
|
266 |
+
return server.switch_model(new_name)
|
267 |
+
|
268 |
+
|
269 |
+
@app.get("/api/lama/model")
|
270 |
+
def current_model():
|
271 |
+
return server.current_model()
|
272 |
+
|
273 |
+
|
274 |
+
@app.get("/api/lama/switchmode")
|
275 |
+
def get_is_disable_model_switch():
|
276 |
+
return server.get_is_disable_model_switch()
|
277 |
+
|
278 |
+
@app.on_event("startup")
|
279 |
+
def init_data():
|
280 |
+
model_device = "cuda"
|
281 |
+
if not torch.cuda.is_available():
|
282 |
+
print("CUDA is not available, switching to CPU")
|
283 |
+
model_device = "cpu"
|
284 |
+
global yolo_model
|
285 |
+
yolo_model = YOLO('yolov8x-seg.pt')
|
286 |
+
yolo_model.to(model_device)
|
287 |
+
print(f"YOLO model yolov8x-seg.pt loaded.")
|
288 |
+
server.initModel()
|
289 |
+
|
290 |
+
def create_app(args):
|
291 |
+
"""
|
292 |
+
Creates the FastAPI app and adds the endpoints.
|
293 |
+
|
294 |
+
Args:
|
295 |
+
args: The arguments.
|
296 |
+
"""
|
297 |
+
uvicorn.run("app:app", host=args.host, port=args.port, reload=args.reload)
|
298 |
+
|
299 |
+
|
300 |
+
if __name__ == "__main__":
|
301 |
+
parser = ArgumentParser()
|
302 |
+
parser.add_argument('--model_name', type=str, default='lama', help='Model name')
|
303 |
+
parser.add_argument('--host', type=str, default='0.0.0.0')
|
304 |
+
parser.add_argument('--port', type=int, default=5000)
|
305 |
+
parser.add_argument('--reload', type=bool, default=True)
|
306 |
+
parser.add_argument('--model_device', type=str, default='cuda', help='Model device')
|
307 |
+
parser.add_argument('--disable_model_switch', type=bool, default=False, help='Disable model switch')
|
308 |
+
parser.add_argument('--gui', type=bool, default=False, help='Enable GUI')
|
309 |
+
parser.add_argument('--cpu_offload', type=bool, default=False, help='Enable CPU offload')
|
310 |
+
parser.add_argument('--disable_nsfw', type=bool, default=False, help='Disable NSFW')
|
311 |
+
parser.add_argument('--enable_xformers', type=bool, default=False, help='Enable xformers')
|
312 |
+
parser.add_argument('--hf_access_token', type=str, default='', help='Hugging Face access token')
|
313 |
+
parser.add_argument('--local_files_only', type=bool, default=False, help='Enable local files only')
|
314 |
+
parser.add_argument('--no_half', type=bool, default=False, help='Disable half')
|
315 |
+
parser.add_argument('--sd_cpu_textencoder', type=bool, default=False, help='Enable CPU text encoder')
|
316 |
+
parser.add_argument('--sd_disable_nsfw', type=bool, default=False, help='Disable NSFW')
|
317 |
+
parser.add_argument('--sd_enable_xformers', type=bool, default=False, help='Enable xformers')
|
318 |
+
parser.add_argument('--sd_run_local', type=bool, default=False, help='Enable local files only')
|
319 |
+
|
320 |
+
args = parser.parse_args()
|
321 |
+
create_app(args)
|
322 |
+
|
docker/CPUDockerfile
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.7.4-slim-buster
|
2 |
+
|
3 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
4 |
+
software-properties-common \
|
5 |
+
libsm6 libxext6 ffmpeg libfontconfig1 libxrender1 libgl1-mesa-glx \
|
6 |
+
curl
|
7 |
+
|
8 |
+
RUN pip install --upgrade pip && \
|
9 |
+
pip install torch==1.13.1 --extra-index-url https://download.pytorch.org/whl/cpu
|
10 |
+
|
11 |
+
ARG version
|
12 |
+
|
13 |
+
RUN pip install lama-cleaner==$version
|
14 |
+
|
15 |
+
EXPOSE 8080
|
16 |
+
|
17 |
+
CMD ["bash"]
|
docker/GPUDockerfile
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM nvidia/cuda:11.7.1-runtime-ubuntu20.04
|
2 |
+
|
3 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
4 |
+
software-properties-common \
|
5 |
+
libsm6 libxext6 ffmpeg libfontconfig1 libxrender1 libgl1-mesa-glx \
|
6 |
+
curl python3-pip
|
7 |
+
|
8 |
+
RUN pip3 install --upgrade pip && \
|
9 |
+
pip3 install torch==1.13.1 xformers==0.0.16rc425
|
10 |
+
|
11 |
+
ARG version
|
12 |
+
|
13 |
+
RUN pip3 install lama-cleaner==$version
|
14 |
+
|
15 |
+
EXPOSE 8080
|
16 |
+
|
17 |
+
CMD ["bash"]
|
lama_cleaner/__init__.py
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import warnings
|
2 |
+
warnings.simplefilter("ignore", UserWarning)
|
3 |
+
|
4 |
+
from lama_cleaner.parse_args import parse_args
|
5 |
+
|
6 |
+
def entry_point():
|
7 |
+
args = parse_args()
|
8 |
+
# To make os.environ["XDG_CACHE_HOME"] = args.model_cache_dir works for diffusers
|
9 |
+
# https://github.com/huggingface/diffusers/blob/be99201a567c1ccd841dc16fb24e88f7f239c187/src/diffusers/utils/constants.py#L18
|
10 |
+
from lama_cleaner.server import main
|
11 |
+
main(args)
|
lama_cleaner/__pycache__/__init__.cpython-38.pyc
ADDED
Binary file (462 Bytes). View file
|
|
lama_cleaner/__pycache__/const.cpython-38.pyc
ADDED
Binary file (1.77 kB). View file
|
|
lama_cleaner/__pycache__/helper.cpython-38.pyc
ADDED
Binary file (5.44 kB). View file
|
|
lama_cleaner/__pycache__/interactive_seg.cpython-38.pyc
ADDED
Binary file (6.75 kB). View file
|
|
lama_cleaner/__pycache__/model_manager.cpython-38.pyc
ADDED
Binary file (2.26 kB). View file
|
|
lama_cleaner/__pycache__/parse_args.cpython-38.pyc
ADDED
Binary file (4.27 kB). View file
|
|
lama_cleaner/__pycache__/runtime.cpython-38.pyc
ADDED
Binary file (1.33 kB). View file
|
|
lama_cleaner/__pycache__/schema.cpython-38.pyc
ADDED
Binary file (2.4 kB). View file
|
|
lama_cleaner/__pycache__/server2.cpython-38.pyc
ADDED
Binary file (5.77 kB). View file
|
|
lama_cleaner/app/.env
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
REACT_APP_INPAINTING_URL=""
|
lama_cleaner/app/.eslintrc.json
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"extends": [
|
3 |
+
"airbnb",
|
4 |
+
"airbnb/hooks",
|
5 |
+
"plugin:@typescript-eslint/recommended",
|
6 |
+
"prettier",
|
7 |
+
"plugin:prettier/recommended"
|
8 |
+
],
|
9 |
+
"plugins": ["@typescript-eslint", "react", "react-hooks", "prettier"],
|
10 |
+
"parser": "@typescript-eslint/parser",
|
11 |
+
"parserOptions": {
|
12 |
+
"ecmaFeatures": {
|
13 |
+
"jsx": true
|
14 |
+
},
|
15 |
+
"ecmaVersion": 2018,
|
16 |
+
"sourceType": "module",
|
17 |
+
"project": "./tsconfig.json"
|
18 |
+
},
|
19 |
+
"rules": {
|
20 |
+
"jsx-a11y/click-events-have-key-events": 0,
|
21 |
+
"react/jsx-props-no-spreading": 0,
|
22 |
+
"import/no-unresolved": 0,
|
23 |
+
"react/jsx-no-bind": "off",
|
24 |
+
"react/jsx-filename-extension": [
|
25 |
+
1,
|
26 |
+
{
|
27 |
+
"extensions": [".ts", ".tsx"]
|
28 |
+
}
|
29 |
+
],
|
30 |
+
"prettier/prettier": [
|
31 |
+
"error",
|
32 |
+
{
|
33 |
+
"singleQuote": true,
|
34 |
+
"arrowParens": "avoid",
|
35 |
+
"endOfLine": "auto"
|
36 |
+
}
|
37 |
+
],
|
38 |
+
"consistent-return": "off",
|
39 |
+
"no-use-before-define": "off",
|
40 |
+
"import/extensions": "off",
|
41 |
+
"react/prop-types": 0,
|
42 |
+
"react/require-default-props": "off",
|
43 |
+
"no-shadow": "off",
|
44 |
+
"@typescript-eslint/ban-ts-comment": "off",
|
45 |
+
"@typescript-eslint/no-shadow": ["error"],
|
46 |
+
"@typescript-eslint/no-explicit-any": "off",
|
47 |
+
"@typescript-eslint/explicit-function-return-type": "off",
|
48 |
+
"@typescript-eslint/explicit-module-boundary-types": "off",
|
49 |
+
"react-hooks/rules-of-hooks": "error",
|
50 |
+
"react-hooks/exhaustive-deps": "warn"
|
51 |
+
}
|
52 |
+
}
|
lama_cleaner/app/.gitignore
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
2 |
+
|
3 |
+
# dependencies
|
4 |
+
/node_modules
|
5 |
+
/.pnp
|
6 |
+
.pnp.js
|
7 |
+
|
8 |
+
# testing
|
9 |
+
/coverage
|
10 |
+
|
11 |
+
# production
|
12 |
+
|
13 |
+
# misc
|
14 |
+
.DS_Store
|
15 |
+
.env.local
|
16 |
+
.env.development.local
|
17 |
+
.env.test.local
|
18 |
+
.env.production.local
|
19 |
+
|
20 |
+
npm-debug.log*
|
21 |
+
yarn-debug.log*
|
22 |
+
yarn-error.log*
|
23 |
+
|
24 |
+
# Tailwind processed CSS
|
25 |
+
index.css
|
26 |
+
|
27 |
+
.firebase
|
lama_cleaner/app/.prettierrc
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"singleQuote": true,
|
3 |
+
"semi": false,
|
4 |
+
"trailingComma": "es5",
|
5 |
+
"arrowParens": "avoid"
|
6 |
+
}
|
lama_cleaner/app/LICENSE
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Apache License
|
2 |
+
Version 2.0, January 2004
|
3 |
+
http://www.apache.org/licenses/
|
4 |
+
|
5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
6 |
+
|
7 |
+
1. Definitions.
|
8 |
+
|
9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
11 |
+
|
12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
13 |
+
the copyright owner that is granting the License.
|
14 |
+
|
15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
16 |
+
other entities that control, are controlled by, or are under common
|
17 |
+
control with that entity. For the purposes of this definition,
|
18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
19 |
+
direction or management of such entity, whether by contract or
|
20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
22 |
+
|
23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
24 |
+
exercising permissions granted by this License.
|
25 |
+
|
26 |
+
"Source" form shall mean the preferred form for making modifications,
|
27 |
+
including but not limited to software source code, documentation
|
28 |
+
source, and configuration files.
|
29 |
+
|
30 |
+
"Object" form shall mean any form resulting from mechanical
|
31 |
+
transformation or translation of a Source form, including but
|
32 |
+
not limited to compiled object code, generated documentation,
|
33 |
+
and conversions to other media types.
|
34 |
+
|
35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
36 |
+
Object form, made available under the License, as indicated by a
|
37 |
+
copyright notice that is included in or attached to the work
|
38 |
+
(an example is provided in the Appendix below).
|
39 |
+
|
40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
41 |
+
form, that is based on (or derived from) the Work and for which the
|
42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
44 |
+
of this License, Derivative Works shall not include works that remain
|
45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
46 |
+
the Work and Derivative Works thereof.
|
47 |
+
|
48 |
+
"Contribution" shall mean any work of authorship, including
|
49 |
+
the original version of the Work and any modifications or additions
|
50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
54 |
+
means any form of electronic, verbal, or written communication sent
|
55 |
+
to the Licensor or its representatives, including but not limited to
|
56 |
+
communication on electronic mailing lists, source code control systems,
|
57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
59 |
+
excluding communication that is conspicuously marked or otherwise
|
60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
61 |
+
|
62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
64 |
+
subsequently incorporated within the Work.
|
65 |
+
|
66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
71 |
+
Work and such Derivative Works in Source or Object form.
|
72 |
+
|
73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
76 |
+
(except as stated in this section) patent license to make, have made,
|
77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
78 |
+
where such license applies only to those patent claims licensable
|
79 |
+
by such Contributor that are necessarily infringed by their
|
80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
82 |
+
institute patent litigation against any entity (including a
|
83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
84 |
+
or a Contribution incorporated within the Work constitutes direct
|
85 |
+
or contributory patent infringement, then any patent licenses
|
86 |
+
granted to You under this License for that Work shall terminate
|
87 |
+
as of the date such litigation is filed.
|
88 |
+
|
89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
90 |
+
Work or Derivative Works thereof in any medium, with or without
|
91 |
+
modifications, and in Source or Object form, provided that You
|
92 |
+
meet the following conditions:
|
93 |
+
|
94 |
+
(a) You must give any other recipients of the Work or
|
95 |
+
Derivative Works a copy of this License; and
|
96 |
+
|
97 |
+
(b) You must cause any modified files to carry prominent notices
|
98 |
+
stating that You changed the files; and
|
99 |
+
|
100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
101 |
+
that You distribute, all copyright, patent, trademark, and
|
102 |
+
attribution notices from the Source form of the Work,
|
103 |
+
excluding those notices that do not pertain to any part of
|
104 |
+
the Derivative Works; and
|
105 |
+
|
106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
107 |
+
distribution, then any Derivative Works that You distribute must
|
108 |
+
include a readable copy of the attribution notices contained
|
109 |
+
within such NOTICE file, excluding those notices that do not
|
110 |
+
pertain to any part of the Derivative Works, in at least one
|
111 |
+
of the following places: within a NOTICE text file distributed
|
112 |
+
as part of the Derivative Works; within the Source form or
|
113 |
+
documentation, if provided along with the Derivative Works; or,
|
114 |
+
within a display generated by the Derivative Works, if and
|
115 |
+
wherever such third-party notices normally appear. The contents
|
116 |
+
of the NOTICE file are for informational purposes only and
|
117 |
+
do not modify the License. You may add Your own attribution
|
118 |
+
notices within Derivative Works that You distribute, alongside
|
119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
120 |
+
that such additional attribution notices cannot be construed
|
121 |
+
as modifying the License.
|
122 |
+
|
123 |
+
You may add Your own copyright statement to Your modifications and
|
124 |
+
may provide additional or different license terms and conditions
|
125 |
+
for use, reproduction, or distribution of Your modifications, or
|
126 |
+
for any such Derivative Works as a whole, provided Your use,
|
127 |
+
reproduction, and distribution of the Work otherwise complies with
|
128 |
+
the conditions stated in this License.
|
129 |
+
|
130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
132 |
+
by You to the Licensor shall be under the terms and conditions of
|
133 |
+
this License, without any additional terms or conditions.
|
134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
135 |
+
the terms of any separate license agreement you may have executed
|
136 |
+
with Licensor regarding such Contributions.
|
137 |
+
|
138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
140 |
+
except as required for reasonable and customary use in describing the
|
141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
142 |
+
|
143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
144 |
+
agreed to in writing, Licensor provides the Work (and each
|
145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
147 |
+
implied, including, without limitation, any warranties or conditions
|
148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
150 |
+
appropriateness of using or redistributing the Work and assume any
|
151 |
+
risks associated with Your exercise of permissions under this License.
|
152 |
+
|
153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
154 |
+
whether in tort (including negligence), contract, or otherwise,
|
155 |
+
unless required by applicable law (such as deliberate and grossly
|
156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
157 |
+
liable to You for damages, including any direct, indirect, special,
|
158 |
+
incidental, or consequential damages of any character arising as a
|
159 |
+
result of this License or out of the use or inability to use the
|
160 |
+
Work (including but not limited to damages for loss of goodwill,
|
161 |
+
work stoppage, computer failure or malfunction, or any and all
|
162 |
+
other commercial damages or losses), even if such Contributor
|
163 |
+
has been advised of the possibility of such damages.
|
164 |
+
|
165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
168 |
+
or other liability obligations and/or rights consistent with this
|
169 |
+
License. However, in accepting such obligations, You may act only
|
170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
171 |
+
of any other Contributor, and only if You agree to indemnify,
|
172 |
+
defend, and hold each Contributor harmless for any liability
|
173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
174 |
+
of your accepting any such warranty or additional liability.
|
175 |
+
|
176 |
+
END OF TERMS AND CONDITIONS
|
177 |
+
|
178 |
+
APPENDIX: How to apply the Apache License to your work.
|
179 |
+
|
180 |
+
To apply the Apache License to your work, attach the following
|
181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
182 |
+
replaced with your own identifying information. (Don't include
|
183 |
+
the brackets!) The text should be enclosed in the appropriate
|
184 |
+
comment syntax for the file format. We also recommend that a
|
185 |
+
file or class name and description of purpose be included on the
|
186 |
+
same "printed page" as the copyright notice for easier
|
187 |
+
identification within third-party archives.
|
188 |
+
|
189 |
+
Copyright [yyyy] [name of copyright owner]
|
190 |
+
|
191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
192 |
+
you may not use this file except in compliance with the License.
|
193 |
+
You may obtain a copy of the License at
|
194 |
+
|
195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
196 |
+
|
197 |
+
Unless required by applicable law or agreed to in writing, software
|
198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
200 |
+
See the License for the specific language governing permissions and
|
201 |
+
limitations under the License.
|
lama_cleaner/app/build/asset-manifest.json
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"files": {
|
3 |
+
"main.css": "/static/css/main.c28d98ca.css",
|
4 |
+
"main.js": "/static/js/main.1bd455bc.js",
|
5 |
+
"static/media/WorkSans-SemiBold.ttf": "/static/media/WorkSans-SemiBold.1e98db4eb705b586728e.ttf",
|
6 |
+
"static/media/WorkSans-Bold.ttf": "/static/media/WorkSans-Bold.2bea7a7f7d052c74da25.ttf",
|
7 |
+
"static/media/WorkSans-Regular.ttf": "/static/media/WorkSans-Regular.bb287b894b27372d8ea7.ttf",
|
8 |
+
"static/media/WorkSans-Black.ttf": "/static/media/WorkSans-Black.67c2c5a144333953880b.ttf",
|
9 |
+
"index.html": "/index.html"
|
10 |
+
},
|
11 |
+
"entrypoints": [
|
12 |
+
"static/css/main.c28d98ca.css",
|
13 |
+
"static/js/main.1bd455bc.js"
|
14 |
+
]
|
15 |
+
}
|
lama_cleaner/app/build/index.html
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
<!doctype html><html lang="en"><head><meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/><meta http-equiv="Pragma" content="no-cache"/><meta http-equiv="Expires" content="0"/><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#ffffff"/><title>lama-cleaner - Image inpainting powered by SOTA AI model</title><script defer="defer" src="/static/js/main.1bd455bc.js"></script><link href="/static/css/main.c28d98ca.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
lama_cleaner/app/build/static/css/main.c28d98ca.css
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
:root{--blackA1:rgba(0,0,0,.012);--blackA2:rgba(0,0,0,.027);--blackA3:rgba(0,0,0,.047);--blackA4:rgba(0,0,0,.071);--blackA5:rgba(0,0,0,.09);--blackA6:rgba(0,0,0,.114);--blackA7:rgba(0,0,0,.141);--blackA8:rgba(0,0,0,.22);--blackA9:rgba(0,0,0,.439);--blackA10:rgba(0,0,0,.478);--blackA11:rgba(0,0,0,.565);--blackA12:rgba(0,0,0,.91);--mauve1:#fdfcfd;--mauve2:#f9f8f9;--mauve3:#f4f2f4;--mauve4:#eeedef;--mauve5:#e9e8ea;--mauve6:#e4e2e4;--mauve7:#dcdbdd;--mauve8:#c8c7cb;--mauve9:#908e96;--mauve10:#86848d;--mauve11:#6f6e77;--mauve12:#1a1523;--violet1:#fdfcfe;--violet2:#fbfaff;--violet3:#f5f2ff;--violet4:#ede9fe;--violet5:#e4defc;--violet6:#d7cff9;--violet7:#c4b8f3;--violet8:#aa99ec;--violet9:#6e56cf;--violet10:#644fc1;--violet11:#5746af;--violet12:#20134b;--page-bg:#fff;--page-bg-light:hsla(0,0%,100%,.5);--page-text-color:#040404;--yellow-accent:#fc0;--yellow-accent-light:#ffcc0055;--link-color:#000;--border-color:#eff1f4;--border-color-light:hsla(240,9%,43%,.5);--tooltip-bg:#e6e6ea;--tooltip-text-color:#000;--error-color:#ef4444;--success-color:#10b981;--editor-toolkit-bg:hsla(0,0%,100%,.5);--editor-options-bg:#e6e6ea;--options-text-color:var(--page-text-color);--editor-size-border-color:var(--border-color);--editor-toolkit-panel-border:0;--modal-bg:var(--page-bg);--modal-text-color:#000;--modal-hotkey-border-color:#000;--model-mask-bg:rgba(209,213,219,.4);--text-color:#040404;--text-color-gray:#6b6f76;--btn-text-color:var(--text-color);--btn-text-hover-color:#040404;--btn-border-color:#646478;--btn-primary-hover-bg:var(--yellow-accent);--animation-pulsing-bg:hsla(0,0%,100%,.5);--switch-root-background-color:#dfe1e4;--switch-thumb-color:var(--page-bg);--switch-thumb-checked-color:var(--page-bg);--slider-background-color:var(--switch-root-background-color);--tooltip-bg:var(--page-bg);--badge-background-color:#f1f3f5;--badge-color:#687076;--box-shadow:inset 0 0.5px hsla(0,0%,100%,.1),inset 0 1px 5px #f8f9fa,0px 0px 0px 0.5px #c1c8cd,0px 2px 1px -1px #c1c8cd,0 1px #c1c8cd;--croper-bg:rgba(0,0,0,.5);--tabs-active-color:#f0f3f9}@font-face{font-family:WorkSans;src:url(/static/media/WorkSans-Regular.bb287b894b27372d8ea7.ttf)}@font-face{font-family:WorkSans-Semibold;src:url(/static/media/WorkSans-SemiBold.1e98db4eb705b586728e.ttf)}@font-face{font-family:WorkSans-Bold;src:url(/static/media/WorkSans-Bold.2bea7a7f7d052c74da25.ttf)}@font-face{font-family:WorkSans-Black;src:url(/static/media/WorkSans-Black.67c2c5a144333953880b.ttf)}[data-theme=dark]{--page-bg:#040404;--page-bg-light:#04040488;--page-text-color:#f9f9f9;--yellow-accent:#fc0;--yellow-accent-light:#ffcc0055;--link-color:var(--yellow-accent);--border-color:#1e1e1e;--border-color-light:#666;--tooltip-bg:#212121;--tooltip-text-color:#d2d2d2;--editor-toolkit-bg:rgba(0,0,0,.5);--editor-options-bg:#212121;--options-text-color:var(--page-text-color);--editor-size-border-color:var(--yellow-accent);--editor-toolkit-panel-border:1px solid hsla(240,9%,43%,.4);--modal-bg:var(--page-bg);--modal-text-color:var(--page-text-color);--modal-hotkey-border-color:var(--page-text-color);--model-mask-bg:rgba(76,76,87,.4);--text-color:#fff;--text-color-gray:#c3c4c6;--btn-text-color:var(--text-color);--btn-text-hover-color:var(--page-bg);--btn-border-color:var(--yellow-accent);--btn-primary-hover-bg:var(--yellow-accent);--animation-pulsing-bg:#f0f0ff;--switch-root-background-color:#3c3f44;--switch-thumb-color:#1f2023;--switch-thumb-checked-color:#fff;--slider-background-color:var(--switch-root-background-color);--badge-background-color:#202425;--badge-color:#9ba1a6;--box-shadow:inset 0 0.5px hsla(0,0%,100%,.1),inset 0 1px 5px #1a1d1e,0px 0px 0px 0.5px #4c5155,0px 2px 1px -1px #4c5155,0 1px #4c5155;--croper-bg:rgba(0,0,0,.5);--tabs-active-color:#272831}@supports (color:hsl(0 0% 0%/0)){[data-theme=dark]{--tooltip-bg:#202425}}@-webkit-keyframes pulsing{0%{opacity:1}50%{background-color:hsla(0,0%,100%,.5);background-color:var(--animation-pulsing-bg);opacity:.75}to{opacity:1}}@keyframes pulsing{0%{opacity:1}50%{background-color:hsla(0,0%,100%,.5);background-color:var(--animation-pulsing-bg);opacity:.75}to{opacity:1}}@-webkit-keyframes opacityReveal{0%{opacity:0}to{opacity:1}}@keyframes opacityReveal{0%{opacity:0}to{opacity:1}}@-webkit-keyframes slideDown{0%{-webkit-transform:translateY(-100%);transform:translateY(-100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes slideDown{0%{-webkit-transform:translateY(-100%);transform:translateY(-100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes slideUp{0%{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes slideUp{0%{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes slideIn{0%{-webkit-transform:translateX(calc(100% + 25px));transform:translateX(calc(100% + 25px))}to{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideIn{0%{-webkit-transform:translateX(calc(100% + 25px));transform:translateX(calc(100% + 25px))}to{-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes slideUpAndFade{0%{opacity:0;-webkit-transform:translateY(2px);transform:translateY(2px)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes slideUpAndFade{0%{opacity:0;-webkit-transform:translateY(2px);transform:translateY(2px)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes slideDownAndFade{0%{opacity:0;-webkit-transform:translateY(-2px);transform:translateY(-2px)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes slideDownAndFade{0%{opacity:0;-webkit-transform:translateY(-2px);transform:translateY(-2px)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}.lama-cleaner{background-color:#fff;background-color:var(--page-bg);color:#040404;color:var(--page-text-color);display:grid;grid-template-areas:"main-content";height:100vh;transition-duration:.2s;transition-property:background-color,color;transition-timing-function:repeat(2,ease-out);width:100vw}a{color:inherit;text-decoration:inherit}input:disabled{color:#6b6f76;color:var(--text-color-gray)}.editor-container{align-items:center;display:flex;height:100vh;justify-content:center;width:100vw}.react-transform-wrapper{display:grid!important;height:100%!important;width:100%!important}.editor-canvas-container{grid-row-gap:1rem;display:grid;grid-template-areas:"editor-content";row-gap:1rem}.editor-canvas{grid-area:editor-content;z-index:2}.original-image-container{display:grid;grid-area:editor-content;grid-template-areas:"original-image-content";pointer-events:none}.original-image-container img{grid-area:original-image-content}.original-image-container .editor-slider{background-color:#fc0;background-color:var(--yellow-accent);grid-area:original-image-content;height:100%;justify-self:end;transition:all .3s cubic-bezier(.4,0,.2,1);width:6px;z-index:2}.editor-canvas-loading{-webkit-animation:pulsing .75s infinite;animation:pulsing .75s infinite;pointer-events:none}.editor-toolkit-panel{grid-column-gap:2rem;align-items:center;-webkit-animation:slideUp .2s ease-out;animation:slideUp .2s ease-out;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);background-color:hsla(0,0%,100%,.5);background-color:var(--page-bg-light);border:0;border:var(--editor-toolkit-panel-border);border-radius:3rem;bottom:.5rem;box-shadow:0 0 0 1px rgba(0,0,0,.102),0 3px 16px rgba(0,0,0,.078),0 2px 6px 1px rgba(0,0,0,.09);-webkit-column-gap:2rem;column-gap:2rem;display:grid;grid-template-areas:"toolkit-size-selector toolkit-brush-slider toolkit-btns";justify-content:center;padding:.6rem 3rem;position:fixed}@media screen and (max-width:767px){.editor-toolkit-panel{grid-template-areas:"toolkit-size-selector toolkit-size-selector" "toolkit-brush-slider toolkit-brush-slider" "toolkit-btns toolkit-btns";justify-items:center;padding:1rem 2rem;row-gap:2rem}}.editor-toolkit-panel .eyeicon-active{background-color:#fc0;background-color:var(--yellow-accent);color:#040404;color:var(--btn-text-hover-color)}.editor-brush-slider{grid-column-gap:1rem;align-items:center;-webkit-column-gap:1rem;column-gap:1rem;display:grid;grid-area:toolkit-brush-slider;grid-template-columns:repeat(2,-webkit-max-content);grid-template-columns:repeat(2,max-content);height:-webkit-max-content;height:max-content;-webkit-user-select:none;user-select:none}.editor-brush-slider input[type=range]{-webkit-appearance:none;appearance:none;background:transparent;border-color:transparent;color:transparent;cursor:pointer;width:100%}.editor-brush-slider input[type=range]:focus{outline:none}.editor-brush-slider input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;background:#fc0;background:var(--yellow-accent);border:1px solid #000;border-radius:50%;height:1.2rem;margin-top:-.5rem;width:1.2rem;z-index:2}.editor-brush-slider input[type=range]::-webkit-slider-runnable-track{background:#dfe1e4;background:var(--slider-background-color);border-radius:2rem;height:.2rem}.editor-brush-slider input[type=range]::-moz-range-track{background:#dfe1e4;background:var(--slider-background-color);border-radius:2rem}.editor-brush-slider input[type=range]::-moz-range-progress{background:#fc0;background:var(--yellow-accent)}.editor-toolkit-btns{grid-column-gap:1rem;-webkit-column-gap:1rem;column-gap:1rem;display:grid;grid-area:toolkit-btns;grid-auto-flow:column}.brush-shape{background-color:rgba(255,204,0,.733);border:1px solid #fc0;border:1px solid var(--yellow-accent);border-radius:50%;pointer-events:none;position:absolute}.file-manager-modal{color:#040404;color:var(--text-color);height:90%;width:80%}.react-photo-album.react-photo-album--columns{height:80vh}.react-photo-album--photo{border:1px solid transparent;border-radius:8px;transition:visibility .25s ease-in,-webkit-transform .25s;transition:transform .25s,visibility .25s ease-in;transition:transform .25s,visibility .25s ease-in,-webkit-transform .25s;-webkit-user-select:none;user-select:none}.react-photo-album--photo:hover{border:1px solid #eff1f4;border:1px solid var(--border-color);-webkit-transform:scale(1.03);transform:scale(1.03)}.ScrollAreaRoot{--scrollbar-size:10px;border-radius:4px;overflow:hidden}.ScrollAreaViewport{border-radius:inherit;height:100%;width:100%}.ScrollAreaScrollbar{display:flex;padding:2px;touch-action:none;transition:background .16s ease-out;-webkit-user-select:none;user-select:none}.ScrollAreaScrollbar:hover{background:var(--blackA8)}.ScrollAreaScrollbar[data-orientation=vertical]{width:var(--scrollbar-size)}.ScrollAreaScrollbar[data-orientation=horizontal]{flex-direction:column;height:var(--scrollbar-size)}.ScrollAreaThumb{background:var(--mauve10);border-radius:var(--scrollbar-size);flex:1 1;position:relative}.ScrollAreaThumb:before{content:"";height:100%;left:50%;min-height:44px;min-width:44px;position:absolute;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);width:100%}.ScrollAreaCorner{background:var(--blackA8)}.file-search-input{border:1px solid #eff1f4;border:1px solid var(--border-color);border-radius:12px;height:32px;padding-left:30px;width:250px}.sort-btn-inactive svg{opacity:.5}button,fieldset,input{all:unset}.TabsRoot{align-self:flex-start;background-color:#fff;background-color:var(--page-bg);display:flex;flex-direction:column;gap:8px}.TabsList{border:1px solid #eff1f4;border:1px solid var(--border-color);border-radius:12px;flex-direction:row;gap:6px;padding:4px}.TabsList,.TabsTrigger{background-color:#fff;background-color:var(--page-bg);display:flex;justify-content:flex-start}.TabsTrigger{align-items:center;border-radius:8px;color:#000;color:var(--modal-text-color);font-family:inherit;font-size:15px;line-height:1;padding:8px;-webkit-user-select:none;user-select:none}.TabsTrigger:hover,.TabsTrigger[data-state=active]{background-color:#f0f3f9;background-color:var(--tabs-active-color)}.TabsTrigger:focus{position:relative}.TabsContent{background-color:#fff;background-color:var(--page-bg);outline:none;width:100%}.TabsContent[data-state=active]{display:flex;flex-direction:column;gap:14px}.landing-page{grid-row-gap:2rem;display:grid;grid-auto-rows:-webkit-max-content;grid-auto-rows:max-content;justify-items:center;place-self:center;row-gap:2rem}@media screen and (max-width:767px){.landing-page{padding:1rem}}.landing-page h1{font-size:1.4rem;text-align:center}@media screen and (max-width:767px){.landing-page h1{font-size:1.2rem}}.landing-page a{color:#000;color:var(--link-color)}.landing-file-selector{display:grid}header{align-items:center;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);background-color:hsla(0,0%,100%,.5);background-color:var(--page-bg-light);border-bottom:1px solid hsla(240,9%,43%,.2);display:flex;height:60px;justify-content:space-between;padding:1rem 1.5rem;position:absolute;top:0;width:100%;z-index:20}.shortcuts{z-index:1}.header-icons-wrapper{gap:12px}.header-icons,.header-icons-wrapper{align-items:center;display:flex;justify-content:center;justify-self:end}.header-icons{gap:6px}.mask-preview{border:1px solid #eff1f4;border:1px solid var(--border-color);border-radius:8px;margin-left:20px;margin-top:30px;max-height:400px;max-width:400px}.prompt-wrapper{display:flex;gap:12px}.prompt-wrapper input{all:unset;border-radius:.5rem;border-width:0;min-width:600px;outline:1px solid #eff1f4;outline:1px solid var(--border-color);padding:0 .8rem}.prompt-wrapper input:focus-visible{border-width:0;outline:1px solid #fc0;outline:1px solid var(--yellow-accent)}.theme-toggle-ui{transition:all .2s ease-in;-webkit-user-select:none;user-select:none;z-index:10}.theme-toggle-ui .theme-btn{align-items:center;cursor:pointer;display:flex;justify-content:center;outline:none}.theme-toggle-ui .theme-btn svg{height:22px;width:22px}.modal-shortcuts{background-color:#fff;background-color:var(--modal-bg);box-shadow:0 0 20px rgba(0,0,40,.2);color:#000;color:var(--modal-text-color);grid-area:main-content}@media screen and (max-width:767px){.modal-shortcuts{-webkit-animation:slideDown .2s ease-out;animation:slideDown .2s ease-out;display:grid;height:auto;width:100%}}.shortcut-options{grid-row-gap:1rem;display:grid;row-gap:1rem}.shortcut-options .shortcut-option{grid-column-gap:6rem;align-items:center;-webkit-column-gap:6rem;column-gap:6rem;display:grid;grid-template-columns:repeat(2,auto)}@media screen and (max-width:767px){.shortcut-options .shortcut-option{-webkit-column-gap:0;column-gap:0;row-gap:.6rem}}.shortcut-options .shortcut-key{background-color:#fff;background-color:var(--page-bg);border-radius:6px;box-shadow:inset 0 .5px hsla(0,0%,100%,.1),inset 0 1px 5px #f8f9fa,0 0 0 .5px #c1c8cd,0 2px 1px -1px #c1c8cd,0 1px #c1c8cd;box-shadow:var(--box-shadow);box-sizing:border-box;color:#000;color:var(--modal-text-color);font-family:inherit;font-weight:400;justify-self:end;line-height:1.5;padding-left:.5rem;padding-right:.5rem;text-shadow:0 0 1px hsla(0,0%,100%,.5);-webkit-user-select:none;user-select:none;white-space:nowrap;width:-webkit-max-content;width:max-content}@media screen and (max-width:767px){.shortcut-options .shortcut-key{padding:.2rem .4rem}}.shortcut-options .shortcut-description{font-size:.95rem;justify-self:start;text-align:left}@media screen and (max-width:767px){.shortcut-options .shortcut-description{justify-self:start;text-align:left;width:auto}}.setting-block,.setting-block .option-desc{display:flex;flex-direction:column}.setting-block .option-desc{border:1px solid #eff1f4;border:1px solid var(--border-color);border-radius:.3rem;color:#6b6f76;color:var(--text-color-gray);gap:8px;margin-top:12px;padding:1rem}.setting-block .option-desc .sub-setting-block{color:#040404;color:var(--text-color)}.setting-block .option-desc svg{color:#6b6f76;color:var(--text-color-gray)}.setting-block-content{align-items:center;display:flex;gap:12rem;justify-content:space-between}.setting-block-content-v{align-items:flex-start;display:flex;flex-direction:column;gap:1rem;justify-content:flex-start}.setting-block-content-title{align-items:center;display:flex;flex-direction:row;gap:8px;justify-content:center}.setting-block-desc{color:#6b6f76;color:var(--text-color-gray);font-size:1rem;margin-top:8px}.hd-setting-block .inline-tip{color:#040404;color:var(--text-color);cursor:pointer;display:inline}.model-desc-link{border-radius:999px;color:#687076;color:var(--badge-color);display:flex;justify-items:center;padding-left:5px;padding-right:5px;text-decoration:none}.modal-setting{background-color:#fff;background-color:var(--modal-bg);box-shadow:0 0 20px rgba(0,0,40,.2);color:#000;color:var(--modal-text-color);min-height:420px;width:680px}@media screen and (max-width:767px){.modal-setting{-webkit-animation:slideDown .2s ease-out;animation:slideDown .2s ease-out;display:grid;height:auto;margin-top:-11rem;width:100%}}.folder-path-block{display:flex;flex-direction:column;gap:12px}.folder-path{border-radius:6px;border-width:0;outline:1px solid #eff1f4;outline:1px solid var(--border-color);padding:.3rem .5rem;width:95%}.folder-path:focus-visible{border-width:0;outline:1px solid #fc0;outline:1px solid var(--yellow-accent)}.side-panel{border-color:#eff1f4;border-color:var(--border-color);border-radius:.8rem;border-style:solid;border-width:1px;padding:.3rem;position:absolute;right:1.5rem;top:68px;z-index:4}.side-panel-trigger{border:0;font-family:WorkSans,sans-serif;font-size:16px}.side-panel-content{background-color:#fff;background-color:var(--page-bg);border-color:#eff1f4;border-color:var(--border-color);border-radius:.8rem;border-style:solid;border-width:1px;color:#040404;color:var(--text-color);display:flex;flex-direction:column;font-family:WorkSans,sans-serif;font-size:14px;gap:12px;padding:1rem;position:relative;right:1.5rem;top:1rem;z-index:9}.side-panel-content .setting-block-content{gap:1rem}.negative-prompt{all:unset;border-radius:.5rem;border-width:0;max-width:200px;min-height:150px;outline:1px solid #eff1f4;outline:1px solid var(--border-color);padding:12px .8rem;width:100%}.negative-prompt:focus-visible{border-width:0;outline:1px solid #fc0;outline:1px solid var(--yellow-accent)}.negative-prompt:-webkit-input-placeholder{padding-top:10px}.negative-prompt:-moz-input-placeholder{padding-top:10px}.negative-prompt:-ms-input-placeholder{padding-top:10px}.resize-title-tile{color:#6b6f76;color:var(--text-color-gray);font-size:.5rem;width:86px}.crop-border{outline-color:#fc0;outline-color:var(--yellow-accent);outline-style:dashed}.info-bar{align-items:center;background-color:#fff;background-color:var(--page-bg);border:0;border:var(--editor-toolkit-panel-border);border-radius:9999px;box-shadow:0 0 0 1px rgba(0,0,0,.102),0 3px 16px rgba(0,0,0,.078),0 2px 6px 1px rgba(0,0,0,.09);color:#040404;color:var(--text-color);display:flex;font-size:1rem;gap:12px;justify-content:center;padding:.2rem .8rem;pointer-events:auto;position:absolute}.info-bar:hover{cursor:move}.croper-wrapper{height:100%;overflow:hidden;position:absolute;width:100%}.croper,.croper-wrapper{pointer-events:none;z-index:2}.croper{bottom:0;box-shadow:0 0 0 9999px rgba(0,0,0,.5);left:0;position:relative;right:0;top:0}.drag-bar{pointer-events:auto;position:absolute}.drag-bar.ord-top{cursor:ns-resize;height:12px;left:0;margin-top:-6px;top:0;width:100%}.drag-bar.ord-right{cursor:ew-resize;height:100%;margin-right:-6px;right:0;top:0;width:12px}.drag-bar.ord-bottom{bottom:0;cursor:ns-resize;height:12px;left:0;margin-bottom:-6px;width:100%}.drag-bar.ord-left{cursor:ew-resize;height:100%;left:0;margin-left:-6px;top:0;width:12px}.drag-handle{background-color:#ffcc0055;background-color:var(--yellow-accent-light);border:2px solid #fc0;border:2px solid var(--yellow-accent);content:"";display:block;height:12px;pointer-events:auto;position:absolute;width:12px;z-index:4}.drag-handle:hover{background-color:#fc0;background-color:var(--yellow-accent)}.drag-handle.ord-topleft{cursor:nw-resize;left:-7px;top:-7px}.drag-handle.ord-topright{cursor:ne-resize;right:-7px;top:-7px}.drag-handle.ord-bottomright{bottom:-7px;cursor:se-resize;right:-7px}.drag-handle.ord-bottomleft{bottom:-7px;cursor:sw-resize;left:-7px}.drag-handle.ord-bottom,.drag-handle.ord-top{cursor:ns-resize;left:calc(50% - 6px)}.drag-handle.ord-top{top:-7px}.drag-handle.ord-bottom{bottom:-7px}.drag-handle.ord-left,.drag-handle.ord-right{cursor:ew-resize;top:calc(50% - 6px)}.drag-handle.ord-left{left:-7px}.drag-handle.ord-right{right:-7px}.interactive-seg-wrapper{height:100%;overflow:hidden;pointer-events:none;position:absolute;width:100%;z-index:2}.interactive-seg-wrapper .click-item{border-radius:50%;height:8px;position:absolute;width:8px}.interactive-seg-wrapper .click-item-positive{background-color:rgba(21,215,121,.936);outline:6px solid rgba(98,255,179,.31)}.interactive-seg-wrapper .click-item-negative{background-color:rgba(237,49,55,.942);outline:6px solid rgba(255,89,95,.31)}.interactive-seg-confirm-actions{background-color:#fff;background-color:var(--page-bg);border-color:#eff1f4;border-color:var(--border-color);border-radius:16px;border-style:solid;border-width:1px;padding:8px;position:absolute;top:68px;z-index:5}.interactive-seg-confirm-actions .action-buttons{align-items:center;display:flex;gap:8px;justify-content:center}@-webkit-keyframes pulse{to{box-shadow:0 0 0 14px rgba(21,215,121,0)}}@keyframes pulse{to{box-shadow:0 0 0 14px rgba(21,215,121,0)}}.interactive-seg-cursor{-webkit-animation:pulse 1.5s cubic-bezier(.66,0,0,1) infinite;animation:pulse 1.5s cubic-bezier(.66,0,0,1) infinite;background-color:rgba(21,215,121,.936);border-radius:50%;box-shadow:0 0 0 0 rgba(21,215,121,.936);color:rgba(234,255,240,.98);height:20px;pointer-events:none;position:absolute;width:20px}.file-select-label{border:2px dashed #eff1f4;border:2px dashed var(--border-color);border-radius:.5rem;cursor:pointer;display:grid;min-width:600px}@media screen and (max-width:767px){.file-select-label{min-width:300px}}.file-select-label .file-select-label-hover,.file-select-label:hover{background-color:#fc0;background-color:var(--yellow-accent);color:#000}.file-select-container{display:grid;height:100%;padding:4rem;width:100%}.file-select-container input{display:none}.file-select-message{font-family:WorkSans;text-align:center}.btn-primary{grid-column-gap:1rem;background-color:#fff;background-color:var(--page-bg);border-radius:.5rem;color:#040404;color:var(--btn-text-color);-webkit-column-gap:1rem;column-gap:1rem;cursor:pointer;display:grid;font-family:WorkSans,sans-serif;grid-auto-flow:column;padding:.5rem;place-items:center;width:-webkit-max-content;width:max-content;z-index:1}.btn-primary:hover{background-color:#fc0;background-color:var(--btn-primary-hover-bg);color:#040404;color:var(--btn-text-hover-color)}.btn-primary svg{height:auto;width:20px}.btn-primary-disabled{background-color:#fff;background-color:var(--page-bg);opacity:.5;pointer-events:none}.btn-border{border-color:#646478;border-color:var(--btn-border-color);border-style:solid;border-width:1px}.modal-mask{-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);background-color:rgba(209,213,219,.4);background-color:var(--model-mask-bg);inset:0;position:fixed;z-index:9998}@media(prefers-reduced-motion:no-preference){.modal-mask{-webkit-animation:opacityReveal .15s cubic-bezier(.16,1,.3,1) forwards;animation:opacityReveal .15s cubic-bezier(.16,1,.3,1) forwards}}@-webkit-keyframes contentShow{0%{opacity:0;-webkit-transform:translate(-50%,-48%) scale(.96);transform:translate(-50%,-48%) scale(.96)}to{opacity:1;-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}}@keyframes contentShow{0%{opacity:0;-webkit-transform:translate(-50%,-48%) scale(.96);transform:translate(-50%,-48%) scale(.96)}to{opacity:1;-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}}.modal{background-color:#fff;background-color:var(--page-bg);border-radius:.95rem;display:flex;flex-direction:column;gap:16px;left:50%;padding:25px;place-self:center;position:fixed;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);z-index:9999}.modal:focus{outline:none}.modal .modal-header{align-items:center;display:grid;grid-template-columns:repeat(2,auto)}.modal .modal-header .btn-primary{justify-self:end}@media(prefers-reduced-motion:no-preference){.modal{-webkit-animation:contentShow .15s cubic-bezier(.16,1,.3,1) forwards;animation:contentShow .15s cubic-bezier(.16,1,.3,1) forwards}}.select-trigger{all:unset;align-items:center;background-color:#fff;background-color:var(--page-bg);border:1px solid #eff1f4;border:1px solid var(--border-color);border-radius:.5rem;color:#040404;color:var(--options-text-color);display:inline-flex;gap:8px;height:32px;justify-content:space-between;padding:0 .8rem}.select-trigger svg{height:1rem;margin-top:.25rem;width:1rem}.select-trigger:hover{border-color:#fc0;border-color:var(--yellow-accent)}.select-trigger:disabled{border-color:#eff1f4;border-color:var(--border-color);color:#eff1f4;color:var(--border-color)}.select-content{background-color:#fff;background-color:var(--page-bg);border-radius:.5rem;overflow:hidden}.select-viewport{border:1px solid #eff1f4;border:1px solid var(--border-color);border-radius:.5rem;padding:5px}.select-item{all:unset;align-items:center;background-color:#fff;background-color:var(--page-bg);border-radius:.5rem;color:#040404;color:var(--options-text-color);display:flex;padding:6px 6px 6px 25px;position:relative;-webkit-user-select:none;user-select:none}.select-item:focus{background-color:#fc0;background-color:var(--yellow-accent);color:#040404;color:var(--btn-text-hover-color)}.select-item-indicator{align-items:center;display:inline-flex;justify-content:center;left:0;padding-right:4px;position:absolute;width:25px}.switch-root{-webkit-tap-highlight-color:rgba(0,0,0,0);all:"unset";background-color:#dfe1e4;background-color:var(--switch-root-background-color);border:none;border-radius:9999px;height:25px;position:relative;transition:background-color .1s;width:42px}.switch-root:focus-visible{outline:none}.switch-root[data-state=checked]{background-color:#fc0;background-color:var(--yellow-accent)}.switch-thumb{background-color:#fff;background-color:var(--switch-thumb-color);border-radius:9999px;display:block;height:17px;-webkit-transform:translateX(4px);transform:translateX(4px);transition:-webkit-transform .1s;transition:transform .1s;transition:transform .1s,-webkit-transform .1s;width:17px;will-change:transform}.switch-thumb[data-state=checked]{background-color:#fff;background-color:var(--switch-thumb-checked-color);outline:1px solid hsla(240,9%,43%,.5);-webkit-transform:translateX(21px);transform:translateX(21px)}.number-input{all:unset;border-radius:.5rem;flex:1 0 auto;height:32px;outline:1px solid #eff1f4;outline:1px solid var(--border-color);padding:0 .8rem;text-align:right}.number-input:focus-visible{outline:1px solid #fc0;outline:1px solid var(--yellow-accent)}.number-input:disabled{color:#eff1f4;color:var(--border-color)}.toast-viewpoint{bottom:48px;display:flex;flex-direction:row;gap:10px;margin:0;max-width:100vw;padding:25px;position:fixed;right:1.5rem;z-index:999999}.toast-viewpoint:focus-visible{outline:none}.toast-root{align-items:center;background-color:#fff;background-color:var(--page-bg);border:1px solid hsla(240,9%,43%,.5);border:1px solid var(--border-color-light);border-radius:.6rem;display:flex;gap:12px;padding:15px}.toast-root[data-state=open]{-webkit-animation:slideIn .15s cubic-bezier(.16,1,.3,1);animation:slideIn .15s cubic-bezier(.16,1,.3,1)}.toast-root[data-state=close]{-webkit-animation:opacityReveal .1s ease-in forwards;animation:opacityReveal .1s ease-in forwards}.toast-root[data-state=cancel]{-webkit-animation:transform .1s ease-out;animation:transform .1s ease-out;-webkit-transform:translateX(0);transform:translateX(0)}.toast-root.error{border:1px solid #ef4444;border:1px solid var(--error-color)}.toast-root.success{border:1px solid #10b981;border:1px solid var(--success-color)}.error-icon{color:#ef4444;color:var(--error-color);height:24px;width:24px}.success-icon{color:#10b981;color:var(--success-color);height:24px;width:24px}.loading-icon{-webkit-animation-duration:1.5s;animation-duration:1.5s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:spin;animation-name:spin;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-transform-origin:center center;transform-origin:center center}.loading-icon,.toast-desc,.toast-icon{align-items:center;display:flex}.toast-desc{color:#040404;color:var(--text-color);margin:0;min-width:240px}.tooltip-trigger{align-items:center;display:flex;justify-content:center}.tooltip-content{background-color:#fff;background-color:var(--tooltip-bg);border-radius:4px;box-shadow:0 10px 38px -10px rgba(14,18,22,.35),0 10px 20px -15px rgba(14,18,22,.2);color:#000;color:var(--tooltip-text-color);padding:10px 15px}@media(prefers-reduced-motion:no-preference){.tooltip-content{-webkit-animation-duration:.4s;animation-duration:.4s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:cubic-bezier(.16,1,.3,1);animation-timing-function:cubic-bezier(.16,1,.3,1);will-change:transform,opacity}.tooltip-content[data-state=delayed-open][data-side=top]{-webkit-animation-name:slideDownAndFade;animation-name:slideDownAndFade}.tooltip-content[data-state=delayed-open][data-side=bottom]{-webkit-animation-name:slideUpAndFade;animation-name:slideUpAndFade}}.tooltip-arrow{fill:#fff;fill:var(--tooltip-bg)}*,:after,:before{box-sizing:border-box;margin:0;padding:0}body,html{font-family:WorkSans,sans-serif}
|
lama_cleaner/app/build/static/js/main.1bd455bc.js
ADDED
The diff for this file is too large to render.
See raw diff
|
|
lama_cleaner/app/build/static/js/main.1bd455bc.js.LICENSE.txt
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
object-assign
|
3 |
+
(c) Sindre Sorhus
|
4 |
+
@license MIT
|
5 |
+
*/
|
6 |
+
|
7 |
+
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @license
|
11 |
+
* Lodash <https://lodash.com/>
|
12 |
+
* Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
|
13 |
+
* Released under MIT license <https://lodash.com/license>
|
14 |
+
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
15 |
+
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
16 |
+
*/
|
17 |
+
|
18 |
+
/** @license React v0.20.2
|
19 |
+
* scheduler.production.min.js
|
20 |
+
*
|
21 |
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
22 |
+
*
|
23 |
+
* This source code is licensed under the MIT license found in the
|
24 |
+
* LICENSE file in the root directory of this source tree.
|
25 |
+
*/
|
26 |
+
|
27 |
+
/** @license React v17.0.2
|
28 |
+
* react-dom.production.min.js
|
29 |
+
*
|
30 |
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
31 |
+
*
|
32 |
+
* This source code is licensed under the MIT license found in the
|
33 |
+
* LICENSE file in the root directory of this source tree.
|
34 |
+
*/
|
35 |
+
|
36 |
+
/** @license React v17.0.2
|
37 |
+
* react-jsx-runtime.production.min.js
|
38 |
+
*
|
39 |
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
40 |
+
*
|
41 |
+
* This source code is licensed under the MIT license found in the
|
42 |
+
* LICENSE file in the root directory of this source tree.
|
43 |
+
*/
|
44 |
+
|
45 |
+
/** @license React v17.0.2
|
46 |
+
* react.production.min.js
|
47 |
+
*
|
48 |
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
49 |
+
*
|
50 |
+
* This source code is licensed under the MIT license found in the
|
51 |
+
* LICENSE file in the root directory of this source tree.
|
52 |
+
*/
|
53 |
+
|
54 |
+
/**!
|
55 |
+
* FlexSearch.js v0.7.21 (Bundle)
|
56 |
+
* Copyright 2018-2021 Nextapps GmbH
|
57 |
+
* Author: Thomas Wilkerling
|
58 |
+
* Licence: Apache-2.0
|
59 |
+
* https://github.com/nextapps-de/flexsearch
|
60 |
+
*/
|
lama_cleaner/app/build/static/media/WorkSans-Black.67c2c5a144333953880b.ttf
ADDED
Binary file (192 kB). View file
|
|
lama_cleaner/app/build/static/media/WorkSans-Bold.2bea7a7f7d052c74da25.ttf
ADDED
Binary file (193 kB). View file
|
|
lama_cleaner/app/build/static/media/WorkSans-Regular.bb287b894b27372d8ea7.ttf
ADDED
Binary file (192 kB). View file
|
|
lama_cleaner/app/build/static/media/WorkSans-SemiBold.1e98db4eb705b586728e.ttf
ADDED
Binary file (193 kB). View file
|
|
lama_cleaner/app/config/env.js
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict';
|
2 |
+
|
3 |
+
const fs = require('fs');
|
4 |
+
const path = require('path');
|
5 |
+
const paths = require('./paths');
|
6 |
+
|
7 |
+
// Make sure that including paths.js after env.js will read .env variables.
|
8 |
+
delete require.cache[require.resolve('./paths')];
|
9 |
+
|
10 |
+
const NODE_ENV = process.env.NODE_ENV;
|
11 |
+
if (!NODE_ENV) {
|
12 |
+
throw new Error(
|
13 |
+
'The NODE_ENV environment variable is required but was not specified.'
|
14 |
+
);
|
15 |
+
}
|
16 |
+
|
17 |
+
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
|
18 |
+
const dotenvFiles = [
|
19 |
+
`${paths.dotenv}.${NODE_ENV}.local`,
|
20 |
+
// Don't include `.env.local` for `test` environment
|
21 |
+
// since normally you expect tests to produce the same
|
22 |
+
// results for everyone
|
23 |
+
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
|
24 |
+
`${paths.dotenv}.${NODE_ENV}`,
|
25 |
+
paths.dotenv,
|
26 |
+
].filter(Boolean);
|
27 |
+
|
28 |
+
// Load environment variables from .env* files. Suppress warnings using silent
|
29 |
+
// if this file is missing. dotenv will never modify any environment variables
|
30 |
+
// that have already been set. Variable expansion is supported in .env files.
|
31 |
+
// https://github.com/motdotla/dotenv
|
32 |
+
// https://github.com/motdotla/dotenv-expand
|
33 |
+
dotenvFiles.forEach(dotenvFile => {
|
34 |
+
if (fs.existsSync(dotenvFile)) {
|
35 |
+
require('dotenv-expand')(
|
36 |
+
require('dotenv').config({
|
37 |
+
path: dotenvFile,
|
38 |
+
})
|
39 |
+
);
|
40 |
+
}
|
41 |
+
});
|
42 |
+
|
43 |
+
// We support resolving modules according to `NODE_PATH`.
|
44 |
+
// This lets you use absolute paths in imports inside large monorepos:
|
45 |
+
// https://github.com/facebook/create-react-app/issues/253.
|
46 |
+
// It works similar to `NODE_PATH` in Node itself:
|
47 |
+
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
|
48 |
+
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
|
49 |
+
// Otherwise, we risk importing Node.js core modules into an app instead of webpack shims.
|
50 |
+
// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
|
51 |
+
// We also resolve them to make sure all tools using them work consistently.
|
52 |
+
const appDirectory = fs.realpathSync(process.cwd());
|
53 |
+
process.env.NODE_PATH = (process.env.NODE_PATH || '')
|
54 |
+
.split(path.delimiter)
|
55 |
+
.filter(folder => folder && !path.isAbsolute(folder))
|
56 |
+
.map(folder => path.resolve(appDirectory, folder))
|
57 |
+
.join(path.delimiter);
|
58 |
+
|
59 |
+
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
|
60 |
+
// injected into the application via DefinePlugin in webpack configuration.
|
61 |
+
const REACT_APP = /^REACT_APP_/i;
|
62 |
+
|
63 |
+
function getClientEnvironment(publicUrl) {
|
64 |
+
const raw = Object.keys(process.env)
|
65 |
+
.filter(key => REACT_APP.test(key))
|
66 |
+
.reduce(
|
67 |
+
(env, key) => {
|
68 |
+
env[key] = process.env[key];
|
69 |
+
return env;
|
70 |
+
},
|
71 |
+
{
|
72 |
+
// Useful for determining whether we’re running in production mode.
|
73 |
+
// Most importantly, it switches React into the correct mode.
|
74 |
+
NODE_ENV: process.env.NODE_ENV || 'development',
|
75 |
+
// Useful for resolving the correct path to static assets in `public`.
|
76 |
+
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
|
77 |
+
// This should only be used as an escape hatch. Normally you would put
|
78 |
+
// images into the `src` and `import` them in code to get their paths.
|
79 |
+
PUBLIC_URL: publicUrl,
|
80 |
+
// We support configuring the sockjs pathname during development.
|
81 |
+
// These settings let a developer run multiple simultaneous projects.
|
82 |
+
// They are used as the connection `hostname`, `pathname` and `port`
|
83 |
+
// in webpackHotDevClient. They are used as the `sockHost`, `sockPath`
|
84 |
+
// and `sockPort` options in webpack-dev-server.
|
85 |
+
WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
|
86 |
+
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
|
87 |
+
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
|
88 |
+
// Whether or not react-refresh is enabled.
|
89 |
+
// It is defined here so it is available in the webpackHotDevClient.
|
90 |
+
FAST_REFRESH: process.env.FAST_REFRESH !== 'false',
|
91 |
+
}
|
92 |
+
);
|
93 |
+
// Stringify all values so we can feed into webpack DefinePlugin
|
94 |
+
const stringified = {
|
95 |
+
'process.env': Object.keys(raw).reduce((env, key) => {
|
96 |
+
env[key] = JSON.stringify(raw[key]);
|
97 |
+
return env;
|
98 |
+
}, {}),
|
99 |
+
};
|
100 |
+
|
101 |
+
return { raw, stringified };
|
102 |
+
}
|
103 |
+
|
104 |
+
module.exports = getClientEnvironment;
|
lama_cleaner/app/config/getHttpsConfig.js
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict';
|
2 |
+
|
3 |
+
const fs = require('fs');
|
4 |
+
const path = require('path');
|
5 |
+
const crypto = require('crypto');
|
6 |
+
const chalk = require('react-dev-utils/chalk');
|
7 |
+
const paths = require('./paths');
|
8 |
+
|
9 |
+
// Ensure the certificate and key provided are valid and if not
|
10 |
+
// throw an easy to debug error
|
11 |
+
function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
|
12 |
+
let encrypted;
|
13 |
+
try {
|
14 |
+
// publicEncrypt will throw an error with an invalid cert
|
15 |
+
encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
|
16 |
+
} catch (err) {
|
17 |
+
throw new Error(
|
18 |
+
`The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
|
19 |
+
);
|
20 |
+
}
|
21 |
+
|
22 |
+
try {
|
23 |
+
// privateDecrypt will throw an error with an invalid key
|
24 |
+
crypto.privateDecrypt(key, encrypted);
|
25 |
+
} catch (err) {
|
26 |
+
throw new Error(
|
27 |
+
`The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
|
28 |
+
err.message
|
29 |
+
}`
|
30 |
+
);
|
31 |
+
}
|
32 |
+
}
|
33 |
+
|
34 |
+
// Read file and throw an error if it doesn't exist
|
35 |
+
function readEnvFile(file, type) {
|
36 |
+
if (!fs.existsSync(file)) {
|
37 |
+
throw new Error(
|
38 |
+
`You specified ${chalk.cyan(
|
39 |
+
type
|
40 |
+
)} in your env, but the file "${chalk.yellow(file)}" can't be found.`
|
41 |
+
);
|
42 |
+
}
|
43 |
+
return fs.readFileSync(file);
|
44 |
+
}
|
45 |
+
|
46 |
+
// Get the https config
|
47 |
+
// Return cert files if provided in env, otherwise just true or false
|
48 |
+
function getHttpsConfig() {
|
49 |
+
const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
|
50 |
+
const isHttps = HTTPS === 'true';
|
51 |
+
|
52 |
+
if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
|
53 |
+
const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
|
54 |
+
const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
|
55 |
+
const config = {
|
56 |
+
cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
|
57 |
+
key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
|
58 |
+
};
|
59 |
+
|
60 |
+
validateKeyAndCerts({ ...config, keyFile, crtFile });
|
61 |
+
return config;
|
62 |
+
}
|
63 |
+
return isHttps;
|
64 |
+
}
|
65 |
+
|
66 |
+
module.exports = getHttpsConfig;
|
lama_cleaner/app/config/jest/babelTransform.js
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict';
|
2 |
+
|
3 |
+
const babelJest = require('babel-jest').default;
|
4 |
+
|
5 |
+
const hasJsxRuntime = (() => {
|
6 |
+
if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {
|
7 |
+
return false;
|
8 |
+
}
|
9 |
+
|
10 |
+
try {
|
11 |
+
require.resolve('react/jsx-runtime');
|
12 |
+
return true;
|
13 |
+
} catch (e) {
|
14 |
+
return false;
|
15 |
+
}
|
16 |
+
})();
|
17 |
+
|
18 |
+
module.exports = babelJest.createTransformer({
|
19 |
+
presets: [
|
20 |
+
[
|
21 |
+
require.resolve('babel-preset-react-app'),
|
22 |
+
{
|
23 |
+
runtime: hasJsxRuntime ? 'automatic' : 'classic',
|
24 |
+
},
|
25 |
+
],
|
26 |
+
],
|
27 |
+
babelrc: false,
|
28 |
+
configFile: false,
|
29 |
+
});
|
lama_cleaner/app/config/jest/cssTransform.js
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict';
|
2 |
+
|
3 |
+
// This is a custom Jest transformer turning style imports into empty objects.
|
4 |
+
// http://facebook.github.io/jest/docs/en/webpack.html
|
5 |
+
|
6 |
+
module.exports = {
|
7 |
+
process() {
|
8 |
+
return 'module.exports = {};';
|
9 |
+
},
|
10 |
+
getCacheKey() {
|
11 |
+
// The output is always the same.
|
12 |
+
return 'cssTransform';
|
13 |
+
},
|
14 |
+
};
|
lama_cleaner/app/config/jest/fileTransform.js
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict';
|
2 |
+
|
3 |
+
const path = require('path');
|
4 |
+
const camelcase = require('camelcase');
|
5 |
+
|
6 |
+
// This is a custom Jest transformer turning file imports into filenames.
|
7 |
+
// http://facebook.github.io/jest/docs/en/webpack.html
|
8 |
+
|
9 |
+
module.exports = {
|
10 |
+
process(src, filename) {
|
11 |
+
const assetFilename = JSON.stringify(path.basename(filename));
|
12 |
+
|
13 |
+
if (filename.match(/\.svg$/)) {
|
14 |
+
// Based on how SVGR generates a component name:
|
15 |
+
// https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
|
16 |
+
const pascalCaseFilename = camelcase(path.parse(filename).name, {
|
17 |
+
pascalCase: true,
|
18 |
+
});
|
19 |
+
const componentName = `Svg${pascalCaseFilename}`;
|
20 |
+
return `const React = require('react');
|
21 |
+
module.exports = {
|
22 |
+
__esModule: true,
|
23 |
+
default: ${assetFilename},
|
24 |
+
ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
|
25 |
+
return {
|
26 |
+
$$typeof: Symbol.for('react.element'),
|
27 |
+
type: 'svg',
|
28 |
+
ref: ref,
|
29 |
+
key: null,
|
30 |
+
props: Object.assign({}, props, {
|
31 |
+
children: ${assetFilename}
|
32 |
+
})
|
33 |
+
};
|
34 |
+
}),
|
35 |
+
};`;
|
36 |
+
}
|
37 |
+
|
38 |
+
return `module.exports = ${assetFilename};`;
|
39 |
+
},
|
40 |
+
};
|
lama_cleaner/app/config/modules.js
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict';
|
2 |
+
|
3 |
+
const fs = require('fs');
|
4 |
+
const path = require('path');
|
5 |
+
const paths = require('./paths');
|
6 |
+
const chalk = require('react-dev-utils/chalk');
|
7 |
+
const resolve = require('resolve');
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Get additional module paths based on the baseUrl of a compilerOptions object.
|
11 |
+
*
|
12 |
+
* @param {Object} options
|
13 |
+
*/
|
14 |
+
function getAdditionalModulePaths(options = {}) {
|
15 |
+
const baseUrl = options.baseUrl;
|
16 |
+
|
17 |
+
if (!baseUrl) {
|
18 |
+
return '';
|
19 |
+
}
|
20 |
+
|
21 |
+
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
22 |
+
|
23 |
+
// We don't need to do anything if `baseUrl` is set to `node_modules`. This is
|
24 |
+
// the default behavior.
|
25 |
+
if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
|
26 |
+
return null;
|
27 |
+
}
|
28 |
+
|
29 |
+
// Allow the user set the `baseUrl` to `appSrc`.
|
30 |
+
if (path.relative(paths.appSrc, baseUrlResolved) === '') {
|
31 |
+
return [paths.appSrc];
|
32 |
+
}
|
33 |
+
|
34 |
+
// If the path is equal to the root directory we ignore it here.
|
35 |
+
// We don't want to allow importing from the root directly as source files are
|
36 |
+
// not transpiled outside of `src`. We do allow importing them with the
|
37 |
+
// absolute path (e.g. `src/Components/Button.js`) but we set that up with
|
38 |
+
// an alias.
|
39 |
+
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
40 |
+
return null;
|
41 |
+
}
|
42 |
+
|
43 |
+
// Otherwise, throw an error.
|
44 |
+
throw new Error(
|
45 |
+
chalk.red.bold(
|
46 |
+
"Your project's `baseUrl` can only be set to `src` or `node_modules`." +
|
47 |
+
' Create React App does not support other values at this time.'
|
48 |
+
)
|
49 |
+
);
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Get webpack aliases based on the baseUrl of a compilerOptions object.
|
54 |
+
*
|
55 |
+
* @param {*} options
|
56 |
+
*/
|
57 |
+
function getWebpackAliases(options = {}) {
|
58 |
+
const baseUrl = options.baseUrl;
|
59 |
+
|
60 |
+
if (!baseUrl) {
|
61 |
+
return {};
|
62 |
+
}
|
63 |
+
|
64 |
+
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
65 |
+
|
66 |
+
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
67 |
+
return {
|
68 |
+
src: paths.appSrc,
|
69 |
+
};
|
70 |
+
}
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Get jest aliases based on the baseUrl of a compilerOptions object.
|
75 |
+
*
|
76 |
+
* @param {*} options
|
77 |
+
*/
|
78 |
+
function getJestAliases(options = {}) {
|
79 |
+
const baseUrl = options.baseUrl;
|
80 |
+
|
81 |
+
if (!baseUrl) {
|
82 |
+
return {};
|
83 |
+
}
|
84 |
+
|
85 |
+
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
86 |
+
|
87 |
+
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
88 |
+
return {
|
89 |
+
'^src/(.*)$': '<rootDir>/src/$1',
|
90 |
+
};
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
94 |
+
function getModules() {
|
95 |
+
// Check if TypeScript is setup
|
96 |
+
const hasTsConfig = fs.existsSync(paths.appTsConfig);
|
97 |
+
const hasJsConfig = fs.existsSync(paths.appJsConfig);
|
98 |
+
|
99 |
+
if (hasTsConfig && hasJsConfig) {
|
100 |
+
throw new Error(
|
101 |
+
'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
|
102 |
+
);
|
103 |
+
}
|
104 |
+
|
105 |
+
let config;
|
106 |
+
|
107 |
+
// If there's a tsconfig.json we assume it's a
|
108 |
+
// TypeScript project and set up the config
|
109 |
+
// based on tsconfig.json
|
110 |
+
if (hasTsConfig) {
|
111 |
+
const ts = require(resolve.sync('typescript', {
|
112 |
+
basedir: paths.appNodeModules,
|
113 |
+
}));
|
114 |
+
config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
|
115 |
+
// Otherwise we'll check if there is jsconfig.json
|
116 |
+
// for non TS projects.
|
117 |
+
} else if (hasJsConfig) {
|
118 |
+
config = require(paths.appJsConfig);
|
119 |
+
}
|
120 |
+
|
121 |
+
config = config || {};
|
122 |
+
const options = config.compilerOptions || {};
|
123 |
+
|
124 |
+
const additionalModulePaths = getAdditionalModulePaths(options);
|
125 |
+
|
126 |
+
return {
|
127 |
+
additionalModulePaths: additionalModulePaths,
|
128 |
+
webpackAliases: getWebpackAliases(options),
|
129 |
+
jestAliases: getJestAliases(options),
|
130 |
+
hasTsConfig,
|
131 |
+
};
|
132 |
+
}
|
133 |
+
|
134 |
+
module.exports = getModules();
|
lama_cleaner/app/config/paths.js
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict';
|
2 |
+
|
3 |
+
const path = require('path');
|
4 |
+
const fs = require('fs');
|
5 |
+
const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
|
6 |
+
|
7 |
+
// Make sure any symlinks in the project folder are resolved:
|
8 |
+
// https://github.com/facebook/create-react-app/issues/637
|
9 |
+
const appDirectory = fs.realpathSync(process.cwd());
|
10 |
+
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
|
11 |
+
|
12 |
+
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
|
13 |
+
// "public path" at which the app is served.
|
14 |
+
// webpack needs to know it to put the right <script> hrefs into HTML even in
|
15 |
+
// single-page apps that may serve index.html for nested URLs like /todos/42.
|
16 |
+
// We can't use a relative path in HTML because we don't want to load something
|
17 |
+
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
|
18 |
+
const publicUrlOrPath = getPublicUrlOrPath(
|
19 |
+
process.env.NODE_ENV === 'development',
|
20 |
+
require(resolveApp('package.json')).homepage,
|
21 |
+
process.env.PUBLIC_URL
|
22 |
+
);
|
23 |
+
|
24 |
+
const buildPath = process.env.BUILD_PATH || 'build';
|
25 |
+
|
26 |
+
const moduleFileExtensions = [
|
27 |
+
'web.mjs',
|
28 |
+
'mjs',
|
29 |
+
'web.js',
|
30 |
+
'js',
|
31 |
+
'web.ts',
|
32 |
+
'ts',
|
33 |
+
'web.tsx',
|
34 |
+
'tsx',
|
35 |
+
'json',
|
36 |
+
'web.jsx',
|
37 |
+
'jsx',
|
38 |
+
];
|
39 |
+
|
40 |
+
// Resolve file paths in the same order as webpack
|
41 |
+
const resolveModule = (resolveFn, filePath) => {
|
42 |
+
const extension = moduleFileExtensions.find(extension =>
|
43 |
+
fs.existsSync(resolveFn(`${filePath}.${extension}`))
|
44 |
+
);
|
45 |
+
|
46 |
+
if (extension) {
|
47 |
+
return resolveFn(`${filePath}.${extension}`);
|
48 |
+
}
|
49 |
+
|
50 |
+
return resolveFn(`${filePath}.js`);
|
51 |
+
};
|
52 |
+
|
53 |
+
// config after eject: we're in ./config/
|
54 |
+
module.exports = {
|
55 |
+
dotenv: resolveApp('.env'),
|
56 |
+
appPath: resolveApp('.'),
|
57 |
+
appBuild: resolveApp(buildPath),
|
58 |
+
appPublic: resolveApp('public'),
|
59 |
+
appHtml: resolveApp('public/index.html'),
|
60 |
+
appIndexJs: resolveModule(resolveApp, 'src/index'),
|
61 |
+
appPackageJson: resolveApp('package.json'),
|
62 |
+
appSrc: resolveApp('src'),
|
63 |
+
appTsConfig: resolveApp('tsconfig.json'),
|
64 |
+
appJsConfig: resolveApp('jsconfig.json'),
|
65 |
+
yarnLockFile: resolveApp('yarn.lock'),
|
66 |
+
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
|
67 |
+
proxySetup: resolveApp('src/setupProxy.js'),
|
68 |
+
appNodeModules: resolveApp('node_modules'),
|
69 |
+
appWebpackCache: resolveApp('node_modules/.cache'),
|
70 |
+
appTsBuildInfoFile: resolveApp('node_modules/.cache/tsconfig.tsbuildinfo'),
|
71 |
+
swSrc: resolveModule(resolveApp, 'src/service-worker'),
|
72 |
+
publicUrlOrPath,
|
73 |
+
};
|
74 |
+
|
75 |
+
|
76 |
+
|
77 |
+
module.exports.moduleFileExtensions = moduleFileExtensions;
|
lama_cleaner/app/config/webpack.config.js
ADDED
@@ -0,0 +1,761 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict'
|
2 |
+
|
3 |
+
const fs = require('fs')
|
4 |
+
const path = require('path')
|
5 |
+
const webpack = require('webpack')
|
6 |
+
const resolve = require('resolve')
|
7 |
+
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
8 |
+
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
|
9 |
+
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin')
|
10 |
+
const TerserPlugin = require('terser-webpack-plugin')
|
11 |
+
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
12 |
+
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
|
13 |
+
const { WebpackManifestPlugin } = require('webpack-manifest-plugin')
|
14 |
+
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin')
|
15 |
+
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
|
16 |
+
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin')
|
17 |
+
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent')
|
18 |
+
const ESLintPlugin = require('eslint-webpack-plugin')
|
19 |
+
const paths = require('./paths')
|
20 |
+
const modules = require('./modules')
|
21 |
+
const getClientEnvironment = require('./env')
|
22 |
+
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin')
|
23 |
+
const ForkTsCheckerWebpackPlugin =
|
24 |
+
process.env.TSC_COMPILE_ON_ERROR === 'true'
|
25 |
+
? require('react-dev-utils/ForkTsCheckerWarningWebpackPlugin')
|
26 |
+
: require('react-dev-utils/ForkTsCheckerWebpackPlugin')
|
27 |
+
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
|
28 |
+
|
29 |
+
const createEnvironmentHash = require('./webpack/persistentCache/createEnvironmentHash')
|
30 |
+
|
31 |
+
// Source maps are resource heavy and can cause out of memory issue for large source files.
|
32 |
+
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'
|
33 |
+
|
34 |
+
const reactRefreshRuntimeEntry = require.resolve('react-refresh/runtime')
|
35 |
+
const reactRefreshWebpackPluginRuntimeEntry = require.resolve(
|
36 |
+
'@pmmmwh/react-refresh-webpack-plugin'
|
37 |
+
)
|
38 |
+
const babelRuntimeEntry = require.resolve('babel-preset-react-app')
|
39 |
+
const babelRuntimeEntryHelpers = require.resolve(
|
40 |
+
'@babel/runtime/helpers/esm/assertThisInitialized',
|
41 |
+
{ paths: [babelRuntimeEntry] }
|
42 |
+
)
|
43 |
+
const babelRuntimeRegenerator = require.resolve('@babel/runtime/regenerator', {
|
44 |
+
paths: [babelRuntimeEntry],
|
45 |
+
})
|
46 |
+
|
47 |
+
// Some apps do not need the benefits of saving a web request, so not inlining the chunk
|
48 |
+
// makes for a smoother build process.
|
49 |
+
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false'
|
50 |
+
|
51 |
+
const emitErrorsAsWarnings = process.env.ESLINT_NO_DEV_ERRORS === 'true'
|
52 |
+
const disableESLintPlugin = process.env.DISABLE_ESLINT_PLUGIN === 'true'
|
53 |
+
|
54 |
+
const imageInlineSizeLimit = parseInt(
|
55 |
+
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
|
56 |
+
)
|
57 |
+
|
58 |
+
// Check if TypeScript is setup
|
59 |
+
const useTypeScript = fs.existsSync(paths.appTsConfig)
|
60 |
+
|
61 |
+
// Check if Tailwind config exists
|
62 |
+
const useTailwind = fs.existsSync(
|
63 |
+
path.join(paths.appPath, 'tailwind.config.js')
|
64 |
+
)
|
65 |
+
|
66 |
+
// Get the path to the uncompiled service worker (if it exists).
|
67 |
+
const swSrc = paths.swSrc
|
68 |
+
|
69 |
+
// style files regexes
|
70 |
+
const cssRegex = /\.css$/
|
71 |
+
const cssModuleRegex = /\.module\.css$/
|
72 |
+
const sassRegex = /\.(scss|sass)$/
|
73 |
+
const sassModuleRegex = /\.module\.(scss|sass)$/
|
74 |
+
|
75 |
+
const hasJsxRuntime = (() => {
|
76 |
+
if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {
|
77 |
+
return false
|
78 |
+
}
|
79 |
+
|
80 |
+
try {
|
81 |
+
require.resolve('react/jsx-runtime')
|
82 |
+
return true
|
83 |
+
} catch (e) {
|
84 |
+
return false
|
85 |
+
}
|
86 |
+
})()
|
87 |
+
|
88 |
+
// This is the production and development configuration.
|
89 |
+
// It is focused on developer experience, fast rebuilds, and a minimal bundle.
|
90 |
+
module.exports = function (webpackEnv) {
|
91 |
+
const isEnvDevelopment = webpackEnv === 'development'
|
92 |
+
const isEnvProduction = webpackEnv === 'production'
|
93 |
+
|
94 |
+
// Variable used for enabling profiling in Production
|
95 |
+
// passed into alias object. Uses a flag if passed into the build command
|
96 |
+
const isEnvProductionProfile =
|
97 |
+
isEnvProduction && process.argv.includes('--profile')
|
98 |
+
|
99 |
+
// We will provide `paths.publicUrlOrPath` to our app
|
100 |
+
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
|
101 |
+
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
|
102 |
+
// Get environment variables to inject into our app.
|
103 |
+
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1))
|
104 |
+
|
105 |
+
const shouldUseReactRefresh = env.raw.FAST_REFRESH
|
106 |
+
|
107 |
+
// common function to get style loaders
|
108 |
+
const getStyleLoaders = (cssOptions, preProcessor) => {
|
109 |
+
const loaders = [
|
110 |
+
isEnvDevelopment && require.resolve('style-loader'),
|
111 |
+
isEnvProduction && {
|
112 |
+
loader: MiniCssExtractPlugin.loader,
|
113 |
+
// css is located in `static/css`, use '../../' to locate index.html folder
|
114 |
+
// in production `paths.publicUrlOrPath` can be a relative path
|
115 |
+
options: paths.publicUrlOrPath.startsWith('.')
|
116 |
+
? { publicPath: '../../' }
|
117 |
+
: {},
|
118 |
+
},
|
119 |
+
{
|
120 |
+
loader: require.resolve('css-loader'),
|
121 |
+
options: cssOptions,
|
122 |
+
},
|
123 |
+
{
|
124 |
+
// Options for PostCSS as we reference these options twice
|
125 |
+
// Adds vendor prefixing based on your specified browser support in
|
126 |
+
// package.json
|
127 |
+
loader: require.resolve('postcss-loader'),
|
128 |
+
options: {
|
129 |
+
postcssOptions: {
|
130 |
+
// Necessary for external CSS imports to work
|
131 |
+
// https://github.com/facebook/create-react-app/issues/2677
|
132 |
+
ident: 'postcss',
|
133 |
+
config: false,
|
134 |
+
plugins: !useTailwind
|
135 |
+
? [
|
136 |
+
'postcss-flexbugs-fixes',
|
137 |
+
[
|
138 |
+
'postcss-preset-env',
|
139 |
+
{
|
140 |
+
autoprefixer: {
|
141 |
+
flexbox: 'no-2009',
|
142 |
+
},
|
143 |
+
stage: 3,
|
144 |
+
},
|
145 |
+
],
|
146 |
+
// Adds PostCSS Normalize as the reset css with default options,
|
147 |
+
// so that it honors browserslist config in package.json
|
148 |
+
// which in turn let's users customize the target behavior as per their needs.
|
149 |
+
'postcss-normalize',
|
150 |
+
]
|
151 |
+
: [
|
152 |
+
'tailwindcss',
|
153 |
+
'postcss-flexbugs-fixes',
|
154 |
+
[
|
155 |
+
'postcss-preset-env',
|
156 |
+
{
|
157 |
+
autoprefixer: {
|
158 |
+
flexbox: 'no-2009',
|
159 |
+
},
|
160 |
+
stage: 3,
|
161 |
+
},
|
162 |
+
],
|
163 |
+
],
|
164 |
+
},
|
165 |
+
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
|
166 |
+
},
|
167 |
+
},
|
168 |
+
].filter(Boolean)
|
169 |
+
if (preProcessor) {
|
170 |
+
loaders.push(
|
171 |
+
{
|
172 |
+
loader: require.resolve('resolve-url-loader'),
|
173 |
+
options: {
|
174 |
+
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
|
175 |
+
root: paths.appSrc,
|
176 |
+
},
|
177 |
+
},
|
178 |
+
{
|
179 |
+
loader: require.resolve(preProcessor),
|
180 |
+
options: {
|
181 |
+
sourceMap: true,
|
182 |
+
},
|
183 |
+
}
|
184 |
+
)
|
185 |
+
}
|
186 |
+
return loaders
|
187 |
+
}
|
188 |
+
|
189 |
+
return {
|
190 |
+
target: ['browserslist'],
|
191 |
+
// Webpack noise constrained to errors and warnings
|
192 |
+
stats: 'errors-warnings',
|
193 |
+
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
|
194 |
+
// Stop compilation early in production
|
195 |
+
bail: isEnvProduction,
|
196 |
+
devtool: isEnvProduction
|
197 |
+
? shouldUseSourceMap
|
198 |
+
? 'source-map'
|
199 |
+
: false
|
200 |
+
: isEnvDevelopment && 'cheap-module-source-map',
|
201 |
+
// These are the "entry points" to our application.
|
202 |
+
// This means they will be the "root" imports that are included in JS bundle.
|
203 |
+
entry: paths.appIndexJs,
|
204 |
+
output: {
|
205 |
+
// The build folder.
|
206 |
+
path: paths.appBuild,
|
207 |
+
// Add /* filename */ comments to generated require()s in the output.
|
208 |
+
pathinfo: isEnvDevelopment,
|
209 |
+
// There will be one main bundle, and one file per asynchronous chunk.
|
210 |
+
// In development, it does not produce real files.
|
211 |
+
filename: isEnvProduction
|
212 |
+
? 'static/js/[name].[contenthash:8].js'
|
213 |
+
: isEnvDevelopment && 'static/js/bundle.js',
|
214 |
+
// There are also additional JS chunk files if you use code splitting.
|
215 |
+
chunkFilename: isEnvProduction
|
216 |
+
? 'static/js/[name].[contenthash:8].chunk.js'
|
217 |
+
: isEnvDevelopment && 'static/js/[name].chunk.js',
|
218 |
+
assetModuleFilename: 'static/media/[name].[hash][ext]',
|
219 |
+
// webpack uses `publicPath` to determine where the app is being served from.
|
220 |
+
// It requires a trailing slash, or the file assets will get an incorrect path.
|
221 |
+
// We inferred the "public path" (such as / or /my-project) from homepage.
|
222 |
+
publicPath: paths.publicUrlOrPath,
|
223 |
+
// Point sourcemap entries to original disk location (format as URL on Windows)
|
224 |
+
devtoolModuleFilenameTemplate: isEnvProduction
|
225 |
+
? info =>
|
226 |
+
path
|
227 |
+
.relative(paths.appSrc, info.absoluteResourcePath)
|
228 |
+
.replace(/\\/g, '/')
|
229 |
+
: isEnvDevelopment &&
|
230 |
+
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
|
231 |
+
},
|
232 |
+
cache: {
|
233 |
+
type: 'filesystem',
|
234 |
+
version: createEnvironmentHash(env.raw),
|
235 |
+
cacheDirectory: paths.appWebpackCache,
|
236 |
+
store: 'pack',
|
237 |
+
buildDependencies: {
|
238 |
+
defaultWebpack: ['webpack/lib/'],
|
239 |
+
config: [__filename],
|
240 |
+
tsconfig: [paths.appTsConfig, paths.appJsConfig].filter(f =>
|
241 |
+
fs.existsSync(f)
|
242 |
+
),
|
243 |
+
},
|
244 |
+
},
|
245 |
+
infrastructureLogging: {
|
246 |
+
level: 'none',
|
247 |
+
},
|
248 |
+
optimization: {
|
249 |
+
minimize: isEnvProduction,
|
250 |
+
minimizer: [
|
251 |
+
// This is only used in production mode
|
252 |
+
new TerserPlugin({
|
253 |
+
terserOptions: {
|
254 |
+
parse: {
|
255 |
+
// We want terser to parse ecma 8 code. However, we don't want it
|
256 |
+
// to apply any minification steps that turns valid ecma 5 code
|
257 |
+
// into invalid ecma 5 code. This is why the 'compress' and 'output'
|
258 |
+
// sections only apply transformations that are ecma 5 safe
|
259 |
+
// https://github.com/facebook/create-react-app/pull/4234
|
260 |
+
ecma: 8,
|
261 |
+
},
|
262 |
+
compress: {
|
263 |
+
ecma: 5,
|
264 |
+
warnings: false,
|
265 |
+
// Disabled because of an issue with Uglify breaking seemingly valid code:
|
266 |
+
// https://github.com/facebook/create-react-app/issues/2376
|
267 |
+
// Pending further investigation:
|
268 |
+
// https://github.com/mishoo/UglifyJS2/issues/2011
|
269 |
+
comparisons: false,
|
270 |
+
// Disabled because of an issue with Terser breaking valid code:
|
271 |
+
// https://github.com/facebook/create-react-app/issues/5250
|
272 |
+
// Pending further investigation:
|
273 |
+
// https://github.com/terser-js/terser/issues/120
|
274 |
+
inline: 2,
|
275 |
+
},
|
276 |
+
mangle: {
|
277 |
+
safari10: true,
|
278 |
+
},
|
279 |
+
// Added for profiling in devtools
|
280 |
+
keep_classnames: isEnvProductionProfile,
|
281 |
+
keep_fnames: isEnvProductionProfile,
|
282 |
+
output: {
|
283 |
+
ecma: 5,
|
284 |
+
comments: false,
|
285 |
+
// Turned on because emoji and regex is not minified properly using default
|
286 |
+
// https://github.com/facebook/create-react-app/issues/2488
|
287 |
+
ascii_only: true,
|
288 |
+
},
|
289 |
+
},
|
290 |
+
}),
|
291 |
+
// This is only used in production mode
|
292 |
+
new CssMinimizerPlugin(),
|
293 |
+
],
|
294 |
+
},
|
295 |
+
resolve: {
|
296 |
+
// This allows you to set a fallback for where webpack should look for modules.
|
297 |
+
// We placed these paths second because we want `node_modules` to "win"
|
298 |
+
// if there are any conflicts. This matches Node resolution mechanism.
|
299 |
+
// https://github.com/facebook/create-react-app/issues/253
|
300 |
+
modules: ['node_modules', paths.appNodeModules].concat(
|
301 |
+
modules.additionalModulePaths || []
|
302 |
+
),
|
303 |
+
// These are the reasonable defaults supported by the Node ecosystem.
|
304 |
+
// We also include JSX as a common component filename extension to support
|
305 |
+
// some tools, although we do not recommend using it, see:
|
306 |
+
// https://github.com/facebook/create-react-app/issues/290
|
307 |
+
// `web` extension prefixes have been added for better support
|
308 |
+
// for React Native Web.
|
309 |
+
extensions: paths.moduleFileExtensions
|
310 |
+
.map(ext => `.${ext}`)
|
311 |
+
.filter(ext => useTypeScript || !ext.includes('ts')),
|
312 |
+
alias: {
|
313 |
+
// Support React Native Web
|
314 |
+
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
315 |
+
'react-native': 'react-native-web',
|
316 |
+
// Allows for better profiling with ReactDevTools
|
317 |
+
...(isEnvProductionProfile && {
|
318 |
+
'react-dom$': 'react-dom/profiling',
|
319 |
+
'scheduler/tracing': 'scheduler/tracing-profiling',
|
320 |
+
}),
|
321 |
+
...(modules.webpackAliases || {}),
|
322 |
+
},
|
323 |
+
plugins: [
|
324 |
+
// Prevents users from importing files from outside of src/ (or node_modules/).
|
325 |
+
// This often causes confusion because we only process files within src/ with babel.
|
326 |
+
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
|
327 |
+
// please link the files into your node_modules/ and let module-resolution kick in.
|
328 |
+
// Make sure your source files are compiled, as they will not be processed in any way.
|
329 |
+
new ModuleScopePlugin(paths.appSrc, [
|
330 |
+
paths.appPackageJson,
|
331 |
+
reactRefreshRuntimeEntry,
|
332 |
+
reactRefreshWebpackPluginRuntimeEntry,
|
333 |
+
babelRuntimeEntry,
|
334 |
+
babelRuntimeEntryHelpers,
|
335 |
+
babelRuntimeRegenerator,
|
336 |
+
]),
|
337 |
+
],
|
338 |
+
},
|
339 |
+
module: {
|
340 |
+
strictExportPresence: true,
|
341 |
+
rules: [
|
342 |
+
{
|
343 |
+
test: /\.m?js/,
|
344 |
+
resolve: {
|
345 |
+
fullySpecified: false,
|
346 |
+
},
|
347 |
+
},
|
348 |
+
// Handle node_modules packages that contain sourcemaps
|
349 |
+
shouldUseSourceMap && {
|
350 |
+
enforce: 'pre',
|
351 |
+
exclude: /@babel(?:\/|\\{1,2})runtime/,
|
352 |
+
test: /\.(js|mjs|jsx|ts|tsx|css)$/,
|
353 |
+
loader: require.resolve('source-map-loader'),
|
354 |
+
},
|
355 |
+
{
|
356 |
+
// "oneOf" will traverse all following loaders until one will
|
357 |
+
// match the requirements. When no loader matches it will fall
|
358 |
+
// back to the "file" loader at the end of the loader list.
|
359 |
+
oneOf: [
|
360 |
+
// TODO: Merge this config once `image/avif` is in the mime-db
|
361 |
+
// https://github.com/jshttp/mime-db
|
362 |
+
{
|
363 |
+
test: [/\.avif$/],
|
364 |
+
type: 'asset',
|
365 |
+
mimetype: 'image/avif',
|
366 |
+
parser: {
|
367 |
+
dataUrlCondition: {
|
368 |
+
maxSize: imageInlineSizeLimit,
|
369 |
+
},
|
370 |
+
},
|
371 |
+
},
|
372 |
+
// "url" loader works like "file" loader except that it embeds assets
|
373 |
+
// smaller than specified limit in bytes as data URLs to avoid requests.
|
374 |
+
// A missing `test` is equivalent to a match.
|
375 |
+
{
|
376 |
+
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
|
377 |
+
type: 'asset',
|
378 |
+
parser: {
|
379 |
+
dataUrlCondition: {
|
380 |
+
maxSize: imageInlineSizeLimit,
|
381 |
+
},
|
382 |
+
},
|
383 |
+
},
|
384 |
+
{
|
385 |
+
test: /\.svg$/,
|
386 |
+
use: [
|
387 |
+
{
|
388 |
+
loader: require.resolve('@svgr/webpack'),
|
389 |
+
options: {
|
390 |
+
prettier: false,
|
391 |
+
svgo: false,
|
392 |
+
svgoConfig: {
|
393 |
+
plugins: [{ removeViewBox: false }],
|
394 |
+
},
|
395 |
+
titleProp: true,
|
396 |
+
ref: true,
|
397 |
+
},
|
398 |
+
},
|
399 |
+
{
|
400 |
+
loader: require.resolve('file-loader'),
|
401 |
+
options: {
|
402 |
+
name: 'static/media/[name].[hash].[ext]',
|
403 |
+
},
|
404 |
+
},
|
405 |
+
],
|
406 |
+
issuer: {
|
407 |
+
and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
|
408 |
+
},
|
409 |
+
},
|
410 |
+
// Process application JS with Babel.
|
411 |
+
// The preset includes JSX, Flow, TypeScript, and some ESnext features.
|
412 |
+
{
|
413 |
+
test: /\.(js|mjs|jsx|ts|tsx)$/,
|
414 |
+
include: paths.appSrc,
|
415 |
+
loader: require.resolve('babel-loader'),
|
416 |
+
options: {
|
417 |
+
customize: require.resolve(
|
418 |
+
'babel-preset-react-app/webpack-overrides'
|
419 |
+
),
|
420 |
+
presets: [
|
421 |
+
[
|
422 |
+
require.resolve('babel-preset-react-app'),
|
423 |
+
{
|
424 |
+
runtime: hasJsxRuntime ? 'automatic' : 'classic',
|
425 |
+
},
|
426 |
+
],
|
427 |
+
],
|
428 |
+
|
429 |
+
plugins: [
|
430 |
+
isEnvDevelopment &&
|
431 |
+
shouldUseReactRefresh &&
|
432 |
+
require.resolve('react-refresh/babel'),
|
433 |
+
].filter(Boolean),
|
434 |
+
// This is a feature of `babel-loader` for webpack (not Babel itself).
|
435 |
+
// It enables caching results in ./node_modules/.cache/babel-loader/
|
436 |
+
// directory for faster rebuilds.
|
437 |
+
cacheDirectory: true,
|
438 |
+
// See #6846 for context on why cacheCompression is disabled
|
439 |
+
cacheCompression: false,
|
440 |
+
compact: isEnvProduction,
|
441 |
+
},
|
442 |
+
},
|
443 |
+
// Process any JS outside of the app with Babel.
|
444 |
+
// Unlike the application JS, we only compile the standard ES features.
|
445 |
+
{
|
446 |
+
test: /\.(js|mjs)$/,
|
447 |
+
exclude: /@babel(?:\/|\\{1,2})runtime/,
|
448 |
+
loader: require.resolve('babel-loader'),
|
449 |
+
options: {
|
450 |
+
babelrc: false,
|
451 |
+
configFile: false,
|
452 |
+
compact: false,
|
453 |
+
presets: [
|
454 |
+
[
|
455 |
+
require.resolve('babel-preset-react-app/dependencies'),
|
456 |
+
{ helpers: true },
|
457 |
+
],
|
458 |
+
],
|
459 |
+
cacheDirectory: true,
|
460 |
+
// See #6846 for context on why cacheCompression is disabled
|
461 |
+
cacheCompression: false,
|
462 |
+
|
463 |
+
// Babel sourcemaps are needed for debugging into node_modules
|
464 |
+
// code. Without the options below, debuggers like VSCode
|
465 |
+
// show incorrect code and set breakpoints on the wrong lines.
|
466 |
+
sourceMaps: shouldUseSourceMap,
|
467 |
+
inputSourceMap: shouldUseSourceMap,
|
468 |
+
},
|
469 |
+
},
|
470 |
+
// "postcss" loader applies autoprefixer to our CSS.
|
471 |
+
// "css" loader resolves paths in CSS and adds assets as dependencies.
|
472 |
+
// "style" loader turns CSS into JS modules that inject <style> tags.
|
473 |
+
// In production, we use MiniCSSExtractPlugin to extract that CSS
|
474 |
+
// to a file, but in development "style" loader enables hot editing
|
475 |
+
// of CSS.
|
476 |
+
// By default we support CSS Modules with the extension .module.css
|
477 |
+
{
|
478 |
+
test: cssRegex,
|
479 |
+
exclude: cssModuleRegex,
|
480 |
+
use: getStyleLoaders({
|
481 |
+
importLoaders: 1,
|
482 |
+
sourceMap: isEnvProduction
|
483 |
+
? shouldUseSourceMap
|
484 |
+
: isEnvDevelopment,
|
485 |
+
modules: {
|
486 |
+
mode: 'icss',
|
487 |
+
},
|
488 |
+
}),
|
489 |
+
// Don't consider CSS imports dead code even if the
|
490 |
+
// containing package claims to have no side effects.
|
491 |
+
// Remove this when webpack adds a warning or an error for this.
|
492 |
+
// See https://github.com/webpack/webpack/issues/6571
|
493 |
+
sideEffects: true,
|
494 |
+
},
|
495 |
+
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
|
496 |
+
// using the extension .module.css
|
497 |
+
{
|
498 |
+
test: cssModuleRegex,
|
499 |
+
use: getStyleLoaders({
|
500 |
+
importLoaders: 1,
|
501 |
+
sourceMap: isEnvProduction
|
502 |
+
? shouldUseSourceMap
|
503 |
+
: isEnvDevelopment,
|
504 |
+
modules: {
|
505 |
+
mode: 'local',
|
506 |
+
getLocalIdent: getCSSModuleLocalIdent,
|
507 |
+
},
|
508 |
+
}),
|
509 |
+
},
|
510 |
+
// Opt-in support for SASS (using .scss or .sass extensions).
|
511 |
+
// By default we support SASS Modules with the
|
512 |
+
// extensions .module.scss or .module.sass
|
513 |
+
{
|
514 |
+
test: sassRegex,
|
515 |
+
exclude: sassModuleRegex,
|
516 |
+
use: getStyleLoaders(
|
517 |
+
{
|
518 |
+
importLoaders: 3,
|
519 |
+
sourceMap: isEnvProduction
|
520 |
+
? shouldUseSourceMap
|
521 |
+
: isEnvDevelopment,
|
522 |
+
modules: {
|
523 |
+
mode: 'icss',
|
524 |
+
},
|
525 |
+
},
|
526 |
+
'sass-loader'
|
527 |
+
),
|
528 |
+
// Don't consider CSS imports dead code even if the
|
529 |
+
// containing package claims to have no side effects.
|
530 |
+
// Remove this when webpack adds a warning or an error for this.
|
531 |
+
// See https://github.com/webpack/webpack/issues/6571
|
532 |
+
sideEffects: true,
|
533 |
+
},
|
534 |
+
// Adds support for CSS Modules, but using SASS
|
535 |
+
// using the extension .module.scss or .module.sass
|
536 |
+
{
|
537 |
+
test: sassModuleRegex,
|
538 |
+
use: getStyleLoaders(
|
539 |
+
{
|
540 |
+
importLoaders: 3,
|
541 |
+
sourceMap: isEnvProduction
|
542 |
+
? shouldUseSourceMap
|
543 |
+
: isEnvDevelopment,
|
544 |
+
modules: {
|
545 |
+
mode: 'local',
|
546 |
+
getLocalIdent: getCSSModuleLocalIdent,
|
547 |
+
},
|
548 |
+
},
|
549 |
+
'sass-loader'
|
550 |
+
),
|
551 |
+
},
|
552 |
+
// "file" loader makes sure those assets get served by WebpackDevServer.
|
553 |
+
// When you `import` an asset, you get its (virtual) filename.
|
554 |
+
// In production, they would get copied to the `build` folder.
|
555 |
+
// This loader doesn't use a "test" so it will catch all modules
|
556 |
+
// that fall through the other loaders.
|
557 |
+
{
|
558 |
+
// Exclude `js` files to keep "css" loader working as it injects
|
559 |
+
// its runtime that would otherwise be processed through "file" loader.
|
560 |
+
// Also exclude `html` and `json` extensions so they get processed
|
561 |
+
// by webpacks internal loaders.
|
562 |
+
exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
|
563 |
+
type: 'asset/resource',
|
564 |
+
},
|
565 |
+
// ** STOP ** Are you adding a new loader?
|
566 |
+
// Make sure to add the new loader(s) before the "file" loader.
|
567 |
+
],
|
568 |
+
},
|
569 |
+
].filter(Boolean),
|
570 |
+
},
|
571 |
+
plugins: [
|
572 |
+
// Generates an `index.html` file with the <script> injected.
|
573 |
+
new HtmlWebpackPlugin(
|
574 |
+
Object.assign(
|
575 |
+
{},
|
576 |
+
{
|
577 |
+
inject: true,
|
578 |
+
template: paths.appHtml,
|
579 |
+
},
|
580 |
+
isEnvProduction
|
581 |
+
? {
|
582 |
+
minify: {
|
583 |
+
removeComments: true,
|
584 |
+
collapseWhitespace: true,
|
585 |
+
removeRedundantAttributes: true,
|
586 |
+
useShortDoctype: true,
|
587 |
+
removeEmptyAttributes: true,
|
588 |
+
removeStyleLinkTypeAttributes: true,
|
589 |
+
keepClosingSlash: true,
|
590 |
+
minifyJS: true,
|
591 |
+
minifyCSS: true,
|
592 |
+
minifyURLs: true,
|
593 |
+
},
|
594 |
+
}
|
595 |
+
: undefined
|
596 |
+
)
|
597 |
+
),
|
598 |
+
// Inlines the webpack runtime script. This script is too small to warrant
|
599 |
+
// a network request.
|
600 |
+
// https://github.com/facebook/create-react-app/issues/5358
|
601 |
+
isEnvProduction &&
|
602 |
+
shouldInlineRuntimeChunk &&
|
603 |
+
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
|
604 |
+
// Makes some environment variables available in index.html.
|
605 |
+
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
|
606 |
+
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
|
607 |
+
// It will be an empty string unless you specify "homepage"
|
608 |
+
// in `package.json`, in which case it will be the pathname of that URL.
|
609 |
+
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
|
610 |
+
// This gives some necessary context to module not found errors, such as
|
611 |
+
// the requesting resource.
|
612 |
+
new ModuleNotFoundPlugin(paths.appPath),
|
613 |
+
// Makes some environment variables available to the JS code, for example:
|
614 |
+
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
|
615 |
+
// It is absolutely essential that NODE_ENV is set to production
|
616 |
+
// during a production build.
|
617 |
+
// Otherwise React will be compiled in the very slow development mode.
|
618 |
+
new webpack.DefinePlugin(env.stringified),
|
619 |
+
// Experimental hot reloading for React .
|
620 |
+
// https://github.com/facebook/react/tree/main/packages/react-refresh
|
621 |
+
isEnvDevelopment &&
|
622 |
+
shouldUseReactRefresh &&
|
623 |
+
new ReactRefreshWebpackPlugin({
|
624 |
+
overlay: false,
|
625 |
+
}),
|
626 |
+
// Watcher doesn't work well if you mistype casing in a path so we use
|
627 |
+
// a plugin that prints an error when you attempt to do this.
|
628 |
+
// See https://github.com/facebook/create-react-app/issues/240
|
629 |
+
isEnvDevelopment && new CaseSensitivePathsPlugin(),
|
630 |
+
isEnvProduction &&
|
631 |
+
new MiniCssExtractPlugin({
|
632 |
+
// Options similar to the same options in webpackOptions.output
|
633 |
+
// both options are optional
|
634 |
+
filename: 'static/css/[name].[contenthash:8].css',
|
635 |
+
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
|
636 |
+
}),
|
637 |
+
// Generate an asset manifest file with the following content:
|
638 |
+
// - "files" key: Mapping of all asset filenames to their corresponding
|
639 |
+
// output file so that tools can pick it up without having to parse
|
640 |
+
// `index.html`
|
641 |
+
// - "entrypoints" key: Array of files which are included in `index.html`,
|
642 |
+
// can be used to reconstruct the HTML if necessary
|
643 |
+
new WebpackManifestPlugin({
|
644 |
+
fileName: 'asset-manifest.json',
|
645 |
+
publicPath: paths.publicUrlOrPath,
|
646 |
+
generate: (seed, files, entrypoints) => {
|
647 |
+
const manifestFiles = files.reduce((manifest, file) => {
|
648 |
+
manifest[file.name] = file.path
|
649 |
+
return manifest
|
650 |
+
}, seed)
|
651 |
+
const entrypointFiles = entrypoints.main.filter(
|
652 |
+
fileName => !fileName.endsWith('.map')
|
653 |
+
)
|
654 |
+
|
655 |
+
return {
|
656 |
+
files: manifestFiles,
|
657 |
+
entrypoints: entrypointFiles,
|
658 |
+
}
|
659 |
+
},
|
660 |
+
}),
|
661 |
+
// Moment.js is an extremely popular library that bundles large locale files
|
662 |
+
// by default due to how webpack interprets its code. This is a practical
|
663 |
+
// solution that requires the user to opt into importing specific locales.
|
664 |
+
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
|
665 |
+
// You can remove this if you don't use Moment.js:
|
666 |
+
new webpack.IgnorePlugin({
|
667 |
+
resourceRegExp: /^\.\/locale$/,
|
668 |
+
contextRegExp: /moment$/,
|
669 |
+
}),
|
670 |
+
// Generate a service worker script that will precache, and keep up to date,
|
671 |
+
// the HTML & assets that are part of the webpack build.
|
672 |
+
isEnvProduction &&
|
673 |
+
fs.existsSync(swSrc) &&
|
674 |
+
new WorkboxWebpackPlugin.InjectManifest({
|
675 |
+
swSrc,
|
676 |
+
dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,
|
677 |
+
exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/],
|
678 |
+
// Bump up the default maximum size (2mb) that's precached,
|
679 |
+
// to make lazy-loading failure scenarios less likely.
|
680 |
+
// See https://github.com/cra-template/pwa/issues/13#issuecomment-722667270
|
681 |
+
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
|
682 |
+
}),
|
683 |
+
// TypeScript type checking
|
684 |
+
useTypeScript &&
|
685 |
+
new ForkTsCheckerWebpackPlugin({
|
686 |
+
async: isEnvDevelopment,
|
687 |
+
typescript: {
|
688 |
+
typescriptPath: resolve.sync('typescript', {
|
689 |
+
basedir: paths.appNodeModules,
|
690 |
+
}),
|
691 |
+
configOverwrite: {
|
692 |
+
compilerOptions: {
|
693 |
+
sourceMap: isEnvProduction
|
694 |
+
? shouldUseSourceMap
|
695 |
+
: isEnvDevelopment,
|
696 |
+
skipLibCheck: true,
|
697 |
+
inlineSourceMap: false,
|
698 |
+
declarationMap: false,
|
699 |
+
noEmit: true,
|
700 |
+
incremental: true,
|
701 |
+
tsBuildInfoFile: paths.appTsBuildInfoFile,
|
702 |
+
},
|
703 |
+
},
|
704 |
+
context: paths.appPath,
|
705 |
+
diagnosticOptions: {
|
706 |
+
syntactic: true,
|
707 |
+
},
|
708 |
+
mode: 'write-references',
|
709 |
+
// profile: true,
|
710 |
+
},
|
711 |
+
issue: {
|
712 |
+
// This one is specifically to match during CI tests,
|
713 |
+
// as micromatch doesn't match
|
714 |
+
// '../cra-template-typescript/template/src/App.tsx'
|
715 |
+
// otherwise.
|
716 |
+
include: [
|
717 |
+
{ file: '../**/src/**/*.{ts,tsx}' },
|
718 |
+
{ file: '**/src/**/*.{ts,tsx}' },
|
719 |
+
],
|
720 |
+
exclude: [
|
721 |
+
{ file: '**/src/**/__tests__/**' },
|
722 |
+
{ file: '**/src/**/?(*.){spec|test}.*' },
|
723 |
+
{ file: '**/src/setupProxy.*' },
|
724 |
+
{ file: '**/src/setupTests.*' },
|
725 |
+
],
|
726 |
+
},
|
727 |
+
logger: {
|
728 |
+
infrastructure: 'silent',
|
729 |
+
},
|
730 |
+
}),
|
731 |
+
!disableESLintPlugin &&
|
732 |
+
new ESLintPlugin({
|
733 |
+
// Plugin options
|
734 |
+
extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
|
735 |
+
formatter: require.resolve('react-dev-utils/eslintFormatter'),
|
736 |
+
eslintPath: require.resolve('eslint'),
|
737 |
+
failOnError: !(isEnvDevelopment && emitErrorsAsWarnings),
|
738 |
+
context: paths.appSrc,
|
739 |
+
cache: true,
|
740 |
+
cacheLocation: path.resolve(
|
741 |
+
paths.appNodeModules,
|
742 |
+
'.cache/.eslintcache'
|
743 |
+
),
|
744 |
+
// ESLint class options
|
745 |
+
cwd: paths.appPath,
|
746 |
+
resolvePluginsRelativeTo: __dirname,
|
747 |
+
baseConfig: {
|
748 |
+
extends: [require.resolve('eslint-config-react-app/base')],
|
749 |
+
rules: {
|
750 |
+
...(!hasJsxRuntime && {
|
751 |
+
'react/react-in-jsx-scope': 'error',
|
752 |
+
}),
|
753 |
+
},
|
754 |
+
},
|
755 |
+
}),
|
756 |
+
].filter(Boolean),
|
757 |
+
// Turn off performance processing because we utilize
|
758 |
+
// our own hints via the FileSizeReporter
|
759 |
+
performance: false,
|
760 |
+
}
|
761 |
+
}
|
lama_cleaner/app/config/webpack/persistentCache/createEnvironmentHash.js
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict';
|
2 |
+
const { createHash } = require('crypto');
|
3 |
+
|
4 |
+
module.exports = env => {
|
5 |
+
const hash = createHash('md5');
|
6 |
+
hash.update(JSON.stringify(env));
|
7 |
+
|
8 |
+
return hash.digest('hex');
|
9 |
+
};
|
lama_cleaner/app/config/webpackDevServer.config.js
ADDED
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict';
|
2 |
+
|
3 |
+
const fs = require('fs');
|
4 |
+
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
|
5 |
+
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
|
6 |
+
const ignoredFiles = require('react-dev-utils/ignoredFiles');
|
7 |
+
const redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware');
|
8 |
+
const paths = require('./paths');
|
9 |
+
const getHttpsConfig = require('./getHttpsConfig');
|
10 |
+
|
11 |
+
const host = process.env.HOST || '0.0.0.0';
|
12 |
+
const sockHost = process.env.WDS_SOCKET_HOST;
|
13 |
+
const sockPath = process.env.WDS_SOCKET_PATH; // default: '/ws'
|
14 |
+
const sockPort = process.env.WDS_SOCKET_PORT;
|
15 |
+
|
16 |
+
module.exports = function (proxy, allowedHost) {
|
17 |
+
const disableFirewall =
|
18 |
+
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true';
|
19 |
+
return {
|
20 |
+
// WebpackDevServer 2.4.3 introduced a security fix that prevents remote
|
21 |
+
// websites from potentially accessing local content through DNS rebinding:
|
22 |
+
// https://github.com/webpack/webpack-dev-server/issues/887
|
23 |
+
// https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
|
24 |
+
// However, it made several existing use cases such as development in cloud
|
25 |
+
// environment or subdomains in development significantly more complicated:
|
26 |
+
// https://github.com/facebook/create-react-app/issues/2271
|
27 |
+
// https://github.com/facebook/create-react-app/issues/2233
|
28 |
+
// While we're investigating better solutions, for now we will take a
|
29 |
+
// compromise. Since our WDS configuration only serves files in the `public`
|
30 |
+
// folder we won't consider accessing them a vulnerability. However, if you
|
31 |
+
// use the `proxy` feature, it gets more dangerous because it can expose
|
32 |
+
// remote code execution vulnerabilities in backends like Django and Rails.
|
33 |
+
// So we will disable the host check normally, but enable it if you have
|
34 |
+
// specified the `proxy` setting. Finally, we let you override it if you
|
35 |
+
// really know what you're doing with a special environment variable.
|
36 |
+
// Note: ["localhost", ".localhost"] will support subdomains - but we might
|
37 |
+
// want to allow setting the allowedHosts manually for more complex setups
|
38 |
+
allowedHosts: disableFirewall ? 'all' : [allowedHost],
|
39 |
+
headers: {
|
40 |
+
'Access-Control-Allow-Origin': '*',
|
41 |
+
'Access-Control-Allow-Methods': '*',
|
42 |
+
'Access-Control-Allow-Headers': '*',
|
43 |
+
},
|
44 |
+
// Enable gzip compression of generated files.
|
45 |
+
compress: true,
|
46 |
+
static: {
|
47 |
+
// By default WebpackDevServer serves physical files from current directory
|
48 |
+
// in addition to all the virtual build products that it serves from memory.
|
49 |
+
// This is confusing because those files won’t automatically be available in
|
50 |
+
// production build folder unless we copy them. However, copying the whole
|
51 |
+
// project directory is dangerous because we may expose sensitive files.
|
52 |
+
// Instead, we establish a convention that only files in `public` directory
|
53 |
+
// get served. Our build script will copy `public` into the `build` folder.
|
54 |
+
// In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%:
|
55 |
+
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
|
56 |
+
// In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
|
57 |
+
// Note that we only recommend to use `public` folder as an escape hatch
|
58 |
+
// for files like `favicon.ico`, `manifest.json`, and libraries that are
|
59 |
+
// for some reason broken when imported through webpack. If you just want to
|
60 |
+
// use an image, put it in `src` and `import` it from JavaScript instead.
|
61 |
+
directory: paths.appPublic,
|
62 |
+
publicPath: [paths.publicUrlOrPath],
|
63 |
+
// By default files from `contentBase` will not trigger a page reload.
|
64 |
+
watch: {
|
65 |
+
// Reportedly, this avoids CPU overload on some systems.
|
66 |
+
// https://github.com/facebook/create-react-app/issues/293
|
67 |
+
// src/node_modules is not ignored to support absolute imports
|
68 |
+
// https://github.com/facebook/create-react-app/issues/1065
|
69 |
+
ignored: ignoredFiles(paths.appSrc),
|
70 |
+
},
|
71 |
+
},
|
72 |
+
client: {
|
73 |
+
webSocketURL: {
|
74 |
+
// Enable custom sockjs pathname for websocket connection to hot reloading server.
|
75 |
+
// Enable custom sockjs hostname, pathname and port for websocket connection
|
76 |
+
// to hot reloading server.
|
77 |
+
hostname: sockHost,
|
78 |
+
pathname: sockPath,
|
79 |
+
port: sockPort,
|
80 |
+
},
|
81 |
+
overlay: {
|
82 |
+
errors: true,
|
83 |
+
warnings: false,
|
84 |
+
},
|
85 |
+
},
|
86 |
+
devMiddleware: {
|
87 |
+
// It is important to tell WebpackDevServer to use the same "publicPath" path as
|
88 |
+
// we specified in the webpack config. When homepage is '.', default to serving
|
89 |
+
// from the root.
|
90 |
+
// remove last slash so user can land on `/test` instead of `/test/`
|
91 |
+
publicPath: paths.publicUrlOrPath.slice(0, -1),
|
92 |
+
},
|
93 |
+
|
94 |
+
https: getHttpsConfig(),
|
95 |
+
host,
|
96 |
+
historyApiFallback: {
|
97 |
+
// Paths with dots should still use the history fallback.
|
98 |
+
// See https://github.com/facebook/create-react-app/issues/387.
|
99 |
+
disableDotRule: true,
|
100 |
+
index: paths.publicUrlOrPath,
|
101 |
+
},
|
102 |
+
// `proxy` is run between `before` and `after` `webpack-dev-server` hooks
|
103 |
+
proxy,
|
104 |
+
onBeforeSetupMiddleware(devServer) {
|
105 |
+
// Keep `evalSourceMapMiddleware`
|
106 |
+
// middlewares before `redirectServedPath` otherwise will not have any effect
|
107 |
+
// This lets us fetch source contents from webpack for the error overlay
|
108 |
+
devServer.app.use(evalSourceMapMiddleware(devServer));
|
109 |
+
|
110 |
+
if (fs.existsSync(paths.proxySetup)) {
|
111 |
+
// This registers user provided middleware for proxy reasons
|
112 |
+
require(paths.proxySetup)(devServer.app);
|
113 |
+
}
|
114 |
+
},
|
115 |
+
onAfterSetupMiddleware(devServer) {
|
116 |
+
// Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match
|
117 |
+
devServer.app.use(redirectServedPath(paths.publicUrlOrPath));
|
118 |
+
|
119 |
+
// This service worker file is effectively a 'no-op' that will reset any
|
120 |
+
// previous service worker registered for the same host:port combination.
|
121 |
+
// We do this in development to avoid hitting the production cache if
|
122 |
+
// it used the same host and port.
|
123 |
+
// https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432
|
124 |
+
devServer.app.use(noopServiceWorkerMiddleware(paths.publicUrlOrPath));
|
125 |
+
},
|
126 |
+
};
|
127 |
+
};
|
lama_cleaner/app/package.json
ADDED
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "lama-cleaner",
|
3 |
+
"version": "0.1.0",
|
4 |
+
"private": true,
|
5 |
+
"proxy": "http://localhost:8080",
|
6 |
+
"dependencies": {
|
7 |
+
"@babel/core": "^7.16.0",
|
8 |
+
"@heroicons/react": "^2.0.0",
|
9 |
+
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
|
10 |
+
"@radix-ui/colors": "^0.1.8",
|
11 |
+
"@radix-ui/react-dialog": "0.1.8-rc.25",
|
12 |
+
"@radix-ui/react-icons": "^1.1.1",
|
13 |
+
"@radix-ui/react-popover": "^1.0.0",
|
14 |
+
"@radix-ui/react-scroll-area": "^1.0.2",
|
15 |
+
"@radix-ui/react-select": "0.1.2-rc.27",
|
16 |
+
"@radix-ui/react-switch": "^0.1.5",
|
17 |
+
"@radix-ui/react-tabs": "^1.0.1",
|
18 |
+
"@radix-ui/react-toast": "^0.1.1",
|
19 |
+
"@radix-ui/react-tooltip": "^0.1.7",
|
20 |
+
"@svgr/webpack": "^5.5.0",
|
21 |
+
"@testing-library/jest-dom": "^5.14.1",
|
22 |
+
"@testing-library/react": "^12.1.2",
|
23 |
+
"@testing-library/user-event": "^13.5.0",
|
24 |
+
"@types/flexsearch": "^0.7.3",
|
25 |
+
"@types/jest": "^27.0.2",
|
26 |
+
"@types/lodash": "^4.14.182",
|
27 |
+
"@types/node": "^16.11.1",
|
28 |
+
"@types/react": "^17.0.30",
|
29 |
+
"@types/react-dom": "^17.0.9",
|
30 |
+
"babel-jest": "^27.4.2",
|
31 |
+
"babel-loader": "^8.2.3",
|
32 |
+
"babel-plugin-named-asset-import": "^0.3.8",
|
33 |
+
"babel-preset-react-app": "^10.0.1",
|
34 |
+
"bfj": "^7.0.2",
|
35 |
+
"browserslist": "^4.18.1",
|
36 |
+
"camelcase": "^6.2.1",
|
37 |
+
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
38 |
+
"cross-env": "7.x",
|
39 |
+
"css-loader": "^6.5.1",
|
40 |
+
"css-minimizer-webpack-plugin": "^3.2.0",
|
41 |
+
"dotenv": "^10.0.0",
|
42 |
+
"dotenv-expand": "^5.1.0",
|
43 |
+
"eslint": "^8.3.0",
|
44 |
+
"eslint-config-react-app": "^7.0.1",
|
45 |
+
"eslint-webpack-plugin": "^3.1.1",
|
46 |
+
"file-loader": "^6.2.0",
|
47 |
+
"flexsearch": "0.7.21",
|
48 |
+
"fs-extra": "^10.0.0",
|
49 |
+
"hacktimer": "^1.1.3",
|
50 |
+
"html-webpack-plugin": "^5.5.0",
|
51 |
+
"identity-obj-proxy": "^3.0.0",
|
52 |
+
"jest": "^27.4.3",
|
53 |
+
"jest-resolve": "^27.4.2",
|
54 |
+
"jest-watch-typeahead": "^1.0.0",
|
55 |
+
"lodash": "^4.17.21",
|
56 |
+
"mini-css-extract-plugin": "^2.4.5",
|
57 |
+
"mitt": "^3.0.0",
|
58 |
+
"nanoid": "^4.0.0",
|
59 |
+
"npm-run-all": "4.x",
|
60 |
+
"postcss": "^8.4.4",
|
61 |
+
"postcss-flexbugs-fixes": "^5.0.2",
|
62 |
+
"postcss-loader": "^6.2.1",
|
63 |
+
"postcss-normalize": "^10.0.1",
|
64 |
+
"postcss-preset-env": "^7.0.1",
|
65 |
+
"prompts": "^2.4.2",
|
66 |
+
"react": "^17.0.2",
|
67 |
+
"react-app-polyfill": "^3.0.0",
|
68 |
+
"react-dev-utils": "^12.0.1",
|
69 |
+
"react-dom": "^17.0.2",
|
70 |
+
"react-feather": "^2.0.10",
|
71 |
+
"react-hotkeys-hook": "^3.4.7",
|
72 |
+
"react-photo-album": "^2.0.0",
|
73 |
+
"react-refresh": "^0.11.0",
|
74 |
+
"react-use": "^17.3.1",
|
75 |
+
"react-zoom-pan-pinch": "^2.1.3",
|
76 |
+
"recoil": "^0.6.1",
|
77 |
+
"resolve": "^1.20.0",
|
78 |
+
"resolve-url-loader": "^4.0.0",
|
79 |
+
"sass-loader": "^12.3.0",
|
80 |
+
"semver": "^7.3.5",
|
81 |
+
"socket.io-client": "^4.5.2",
|
82 |
+
"source-map-loader": "^3.0.0",
|
83 |
+
"style-loader": "^3.3.1",
|
84 |
+
"tailwindcss": "^3.0.2",
|
85 |
+
"terser-webpack-plugin": "^5.2.5",
|
86 |
+
"typescript": "4.x",
|
87 |
+
"webpack": "^5.64.4",
|
88 |
+
"webpack-dev-server": "^4.6.0",
|
89 |
+
"webpack-manifest-plugin": "^4.0.2",
|
90 |
+
"workbox-webpack-plugin": "^6.4.1"
|
91 |
+
},
|
92 |
+
"scripts": {
|
93 |
+
"start": "cross-env GENERATE_SOURCEMAP=false node scripts/start.js",
|
94 |
+
"build": "cross-env GENERATE_SOURCEMAP=false node scripts/build.js",
|
95 |
+
"test": "node scripts/test.js"
|
96 |
+
},
|
97 |
+
"eslintConfig": {
|
98 |
+
"extends": "react-app"
|
99 |
+
},
|
100 |
+
"browserslist": {
|
101 |
+
"production": [
|
102 |
+
">0.2%",
|
103 |
+
"not dead",
|
104 |
+
"not op_mini all"
|
105 |
+
],
|
106 |
+
"development": [
|
107 |
+
"last 1 chrome version",
|
108 |
+
"last 1 firefox version",
|
109 |
+
"last 1 safari version"
|
110 |
+
]
|
111 |
+
},
|
112 |
+
"devDependencies": {
|
113 |
+
"@typescript-eslint/eslint-plugin": "^5.1.0",
|
114 |
+
"eslint-config-airbnb": "^18.2.1",
|
115 |
+
"eslint-config-prettier": "^8.3.0",
|
116 |
+
"eslint-plugin-import": "^2.25.2",
|
117 |
+
"eslint-plugin-jsx-a11y": "^6.4.1",
|
118 |
+
"eslint-plugin-prettier": "^4.0.0",
|
119 |
+
"eslint-plugin-react": "^7.27.1",
|
120 |
+
"eslint-plugin-react-hooks": "^4.3.0",
|
121 |
+
"prettier": "^2.4.1",
|
122 |
+
"sass": "^1.49.9"
|
123 |
+
},
|
124 |
+
"jest": {
|
125 |
+
"roots": [
|
126 |
+
"<rootDir>/src"
|
127 |
+
],
|
128 |
+
"collectCoverageFrom": [
|
129 |
+
"src/**/*.{js,jsx,ts,tsx}",
|
130 |
+
"!src/**/*.d.ts"
|
131 |
+
],
|
132 |
+
"setupFiles": [
|
133 |
+
"react-app-polyfill/jsdom"
|
134 |
+
],
|
135 |
+
"setupFilesAfterEnv": [
|
136 |
+
"<rootDir>/src/setupTests.ts"
|
137 |
+
],
|
138 |
+
"testMatch": [
|
139 |
+
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
|
140 |
+
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
|
141 |
+
],
|
142 |
+
"testEnvironment": "jsdom",
|
143 |
+
"transform": {
|
144 |
+
"^.+\\.(js|jsx|mjs|cjs|ts|tsx)$": "<rootDir>/config/jest/babelTransform.js",
|
145 |
+
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
|
146 |
+
"^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
|
147 |
+
},
|
148 |
+
"transformIgnorePatterns": [
|
149 |
+
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$",
|
150 |
+
"^.+\\.module\\.(css|sass|scss)$"
|
151 |
+
],
|
152 |
+
"modulePaths": [],
|
153 |
+
"moduleNameMapper": {
|
154 |
+
"^react-native$": "react-native-web",
|
155 |
+
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
|
156 |
+
},
|
157 |
+
"moduleFileExtensions": [
|
158 |
+
"web.js",
|
159 |
+
"js",
|
160 |
+
"web.ts",
|
161 |
+
"ts",
|
162 |
+
"web.tsx",
|
163 |
+
"tsx",
|
164 |
+
"json",
|
165 |
+
"web.jsx",
|
166 |
+
"jsx",
|
167 |
+
"node"
|
168 |
+
],
|
169 |
+
"watchPlugins": [
|
170 |
+
"jest-watch-typeahead/filename",
|
171 |
+
"jest-watch-typeahead/testname"
|
172 |
+
],
|
173 |
+
"resetMocks": true
|
174 |
+
},
|
175 |
+
"babel": {
|
176 |
+
"presets": [
|
177 |
+
"react-app"
|
178 |
+
]
|
179 |
+
}
|
180 |
+
}
|
lama_cleaner/app/public/index.html
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta
|
5 |
+
http-equiv="Cache-Control"
|
6 |
+
content="no-cache, no-store, must-revalidate"
|
7 |
+
/>
|
8 |
+
<meta http-equiv="Pragma" content="no-cache" />
|
9 |
+
<meta http-equiv="Expires" content="0" />
|
10 |
+
|
11 |
+
<meta charset="utf-8" />
|
12 |
+
<meta
|
13 |
+
name="viewport"
|
14 |
+
content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0"
|
15 |
+
/>
|
16 |
+
|
17 |
+
<meta name="theme-color" content="#ffffff" />
|
18 |
+
<!--
|
19 |
+
Notice the use of %PUBLIC_URL% in the tags above.
|
20 |
+
It will be replaced with the URL of the `public` folder during the build.
|
21 |
+
Only files inside the `public` folder can be referenced from the HTML.
|
22 |
+
|
23 |
+
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
24 |
+
work correctly both with client-side routing and a non-root public URL.
|
25 |
+
Learn how to configure a non-root public URL by running `npm run build`.
|
26 |
+
-->
|
27 |
+
<title>lama-cleaner - Image inpainting powered by SOTA AI model</title>
|
28 |
+
</head>
|
29 |
+
<body>
|
30 |
+
<noscript>You need to enable JavaScript to run this app.</noscript>
|
31 |
+
<div id="root"></div>
|
32 |
+
</body>
|
33 |
+
</html>
|
lama_cleaner/app/scripts/build.js
ADDED
@@ -0,0 +1,217 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict';
|
2 |
+
|
3 |
+
// Do this as the first thing so that any code reading it knows the right env.
|
4 |
+
process.env.BABEL_ENV = 'production';
|
5 |
+
process.env.NODE_ENV = 'production';
|
6 |
+
|
7 |
+
// Makes the script crash on unhandled rejections instead of silently
|
8 |
+
// ignoring them. In the future, promise rejections that are not handled will
|
9 |
+
// terminate the Node.js process with a non-zero exit code.
|
10 |
+
process.on('unhandledRejection', err => {
|
11 |
+
throw err;
|
12 |
+
});
|
13 |
+
|
14 |
+
// Ensure environment variables are read.
|
15 |
+
require('../config/env');
|
16 |
+
|
17 |
+
const path = require('path');
|
18 |
+
const chalk = require('react-dev-utils/chalk');
|
19 |
+
const fs = require('fs-extra');
|
20 |
+
const bfj = require('bfj');
|
21 |
+
const webpack = require('webpack');
|
22 |
+
const configFactory = require('../config/webpack.config');
|
23 |
+
const paths = require('../config/paths');
|
24 |
+
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
|
25 |
+
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
|
26 |
+
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
|
27 |
+
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
|
28 |
+
const printBuildError = require('react-dev-utils/printBuildError');
|
29 |
+
|
30 |
+
const measureFileSizesBeforeBuild =
|
31 |
+
FileSizeReporter.measureFileSizesBeforeBuild;
|
32 |
+
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
|
33 |
+
const useYarn = fs.existsSync(paths.yarnLockFile);
|
34 |
+
|
35 |
+
// These sizes are pretty large. We'll warn for bundles exceeding them.
|
36 |
+
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
|
37 |
+
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
|
38 |
+
|
39 |
+
const isInteractive = process.stdout.isTTY;
|
40 |
+
|
41 |
+
// Warn and crash if required files are missing
|
42 |
+
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
43 |
+
process.exit(1);
|
44 |
+
}
|
45 |
+
|
46 |
+
const argv = process.argv.slice(2);
|
47 |
+
const writeStatsJson = argv.indexOf('--stats') !== -1;
|
48 |
+
|
49 |
+
// Generate configuration
|
50 |
+
const config = configFactory('production');
|
51 |
+
|
52 |
+
// We require that you explicitly set browsers and do not fall back to
|
53 |
+
// browserslist defaults.
|
54 |
+
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
|
55 |
+
checkBrowsers(paths.appPath, isInteractive)
|
56 |
+
.then(() => {
|
57 |
+
// First, read the current file sizes in build directory.
|
58 |
+
// This lets us display how much they changed later.
|
59 |
+
return measureFileSizesBeforeBuild(paths.appBuild);
|
60 |
+
})
|
61 |
+
.then(previousFileSizes => {
|
62 |
+
// Remove all content but keep the directory so that
|
63 |
+
// if you're in it, you don't end up in Trash
|
64 |
+
fs.emptyDirSync(paths.appBuild);
|
65 |
+
// Merge with the public folder
|
66 |
+
copyPublicFolder();
|
67 |
+
// Start the webpack build
|
68 |
+
return build(previousFileSizes);
|
69 |
+
})
|
70 |
+
.then(
|
71 |
+
({ stats, previousFileSizes, warnings }) => {
|
72 |
+
if (warnings.length) {
|
73 |
+
console.log(chalk.yellow('Compiled with warnings.\n'));
|
74 |
+
console.log(warnings.join('\n\n'));
|
75 |
+
console.log(
|
76 |
+
'\nSearch for the ' +
|
77 |
+
chalk.underline(chalk.yellow('keywords')) +
|
78 |
+
' to learn more about each warning.'
|
79 |
+
);
|
80 |
+
console.log(
|
81 |
+
'To ignore, add ' +
|
82 |
+
chalk.cyan('// eslint-disable-next-line') +
|
83 |
+
' to the line before.\n'
|
84 |
+
);
|
85 |
+
} else {
|
86 |
+
console.log(chalk.green('Compiled successfully.\n'));
|
87 |
+
}
|
88 |
+
|
89 |
+
console.log('File sizes after gzip:\n');
|
90 |
+
printFileSizesAfterBuild(
|
91 |
+
stats,
|
92 |
+
previousFileSizes,
|
93 |
+
paths.appBuild,
|
94 |
+
WARN_AFTER_BUNDLE_GZIP_SIZE,
|
95 |
+
WARN_AFTER_CHUNK_GZIP_SIZE
|
96 |
+
);
|
97 |
+
console.log();
|
98 |
+
|
99 |
+
const appPackage = require(paths.appPackageJson);
|
100 |
+
const publicUrl = paths.publicUrlOrPath;
|
101 |
+
const publicPath = config.output.publicPath;
|
102 |
+
const buildFolder = path.relative(process.cwd(), paths.appBuild);
|
103 |
+
printHostingInstructions(
|
104 |
+
appPackage,
|
105 |
+
publicUrl,
|
106 |
+
publicPath,
|
107 |
+
buildFolder,
|
108 |
+
useYarn
|
109 |
+
);
|
110 |
+
},
|
111 |
+
err => {
|
112 |
+
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
|
113 |
+
if (tscCompileOnError) {
|
114 |
+
console.log(
|
115 |
+
chalk.yellow(
|
116 |
+
'Compiled with the following type errors (you may want to check these before deploying your app):\n'
|
117 |
+
)
|
118 |
+
);
|
119 |
+
printBuildError(err);
|
120 |
+
} else {
|
121 |
+
console.log(chalk.red('Failed to compile.\n'));
|
122 |
+
printBuildError(err);
|
123 |
+
process.exit(1);
|
124 |
+
}
|
125 |
+
}
|
126 |
+
)
|
127 |
+
.catch(err => {
|
128 |
+
if (err && err.message) {
|
129 |
+
console.log(err.message);
|
130 |
+
}
|
131 |
+
process.exit(1);
|
132 |
+
});
|
133 |
+
|
134 |
+
// Create the production build and print the deployment instructions.
|
135 |
+
function build(previousFileSizes) {
|
136 |
+
console.log('Creating an optimized production build...');
|
137 |
+
|
138 |
+
const compiler = webpack(config);
|
139 |
+
return new Promise((resolve, reject) => {
|
140 |
+
compiler.run((err, stats) => {
|
141 |
+
let messages;
|
142 |
+
if (err) {
|
143 |
+
if (!err.message) {
|
144 |
+
return reject(err);
|
145 |
+
}
|
146 |
+
|
147 |
+
let errMessage = err.message;
|
148 |
+
|
149 |
+
// Add additional information for postcss errors
|
150 |
+
if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
|
151 |
+
errMessage +=
|
152 |
+
'\nCompileError: Begins at CSS selector ' +
|
153 |
+
err['postcssNode'].selector;
|
154 |
+
}
|
155 |
+
|
156 |
+
messages = formatWebpackMessages({
|
157 |
+
errors: [errMessage],
|
158 |
+
warnings: [],
|
159 |
+
});
|
160 |
+
} else {
|
161 |
+
messages = formatWebpackMessages(
|
162 |
+
stats.toJson({ all: false, warnings: true, errors: true })
|
163 |
+
);
|
164 |
+
}
|
165 |
+
if (messages.errors.length) {
|
166 |
+
// Only keep the first error. Others are often indicative
|
167 |
+
// of the same problem, but confuse the reader with noise.
|
168 |
+
if (messages.errors.length > 1) {
|
169 |
+
messages.errors.length = 1;
|
170 |
+
}
|
171 |
+
return reject(new Error(messages.errors.join('\n\n')));
|
172 |
+
}
|
173 |
+
if (
|
174 |
+
process.env.CI &&
|
175 |
+
(typeof process.env.CI !== 'string' ||
|
176 |
+
process.env.CI.toLowerCase() !== 'false') &&
|
177 |
+
messages.warnings.length
|
178 |
+
) {
|
179 |
+
// Ignore sourcemap warnings in CI builds. See #8227 for more info.
|
180 |
+
const filteredWarnings = messages.warnings.filter(
|
181 |
+
w => !/Failed to parse source map/.test(w)
|
182 |
+
);
|
183 |
+
if (filteredWarnings.length) {
|
184 |
+
console.log(
|
185 |
+
chalk.yellow(
|
186 |
+
'\nTreating warnings as errors because process.env.CI = true.\n' +
|
187 |
+
'Most CI servers set it automatically.\n'
|
188 |
+
)
|
189 |
+
);
|
190 |
+
return reject(new Error(filteredWarnings.join('\n\n')));
|
191 |
+
}
|
192 |
+
}
|
193 |
+
|
194 |
+
const resolveArgs = {
|
195 |
+
stats,
|
196 |
+
previousFileSizes,
|
197 |
+
warnings: messages.warnings,
|
198 |
+
};
|
199 |
+
|
200 |
+
if (writeStatsJson) {
|
201 |
+
return bfj
|
202 |
+
.write(paths.appBuild + '/bundle-stats.json', stats.toJson())
|
203 |
+
.then(() => resolve(resolveArgs))
|
204 |
+
.catch(error => reject(new Error(error)));
|
205 |
+
}
|
206 |
+
|
207 |
+
return resolve(resolveArgs);
|
208 |
+
});
|
209 |
+
});
|
210 |
+
}
|
211 |
+
|
212 |
+
function copyPublicFolder() {
|
213 |
+
fs.copySync(paths.appPublic, paths.appBuild, {
|
214 |
+
dereference: true,
|
215 |
+
filter: file => file !== paths.appHtml,
|
216 |
+
});
|
217 |
+
}
|
lama_cleaner/app/scripts/start.js
ADDED
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict';
|
2 |
+
|
3 |
+
// Do this as the first thing so that any code reading it knows the right env.
|
4 |
+
process.env.BABEL_ENV = 'development';
|
5 |
+
process.env.NODE_ENV = 'development';
|
6 |
+
|
7 |
+
// Makes the script crash on unhandled rejections instead of silently
|
8 |
+
// ignoring them. In the future, promise rejections that are not handled will
|
9 |
+
// terminate the Node.js process with a non-zero exit code.
|
10 |
+
process.on('unhandledRejection', err => {
|
11 |
+
throw err;
|
12 |
+
});
|
13 |
+
|
14 |
+
// Ensure environment variables are read.
|
15 |
+
require('../config/env');
|
16 |
+
|
17 |
+
const fs = require('fs');
|
18 |
+
const chalk = require('react-dev-utils/chalk');
|
19 |
+
const webpack = require('webpack');
|
20 |
+
const WebpackDevServer = require('webpack-dev-server');
|
21 |
+
const clearConsole = require('react-dev-utils/clearConsole');
|
22 |
+
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
|
23 |
+
const {
|
24 |
+
choosePort,
|
25 |
+
createCompiler,
|
26 |
+
prepareProxy,
|
27 |
+
prepareUrls,
|
28 |
+
} = require('react-dev-utils/WebpackDevServerUtils');
|
29 |
+
const openBrowser = require('react-dev-utils/openBrowser');
|
30 |
+
const semver = require('semver');
|
31 |
+
const paths = require('../config/paths');
|
32 |
+
const configFactory = require('../config/webpack.config');
|
33 |
+
const createDevServerConfig = require('../config/webpackDevServer.config');
|
34 |
+
const getClientEnvironment = require('../config/env');
|
35 |
+
const react = require(require.resolve('react', { paths: [paths.appPath] }));
|
36 |
+
|
37 |
+
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
|
38 |
+
const useYarn = fs.existsSync(paths.yarnLockFile);
|
39 |
+
const isInteractive = process.stdout.isTTY;
|
40 |
+
|
41 |
+
// Warn and crash if required files are missing
|
42 |
+
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
43 |
+
process.exit(1);
|
44 |
+
}
|
45 |
+
|
46 |
+
// Tools like Cloud9 rely on this.
|
47 |
+
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
|
48 |
+
const HOST = process.env.HOST || '0.0.0.0';
|
49 |
+
|
50 |
+
if (process.env.HOST) {
|
51 |
+
console.log(
|
52 |
+
chalk.cyan(
|
53 |
+
`Attempting to bind to HOST environment variable: ${chalk.yellow(
|
54 |
+
chalk.bold(process.env.HOST)
|
55 |
+
)}`
|
56 |
+
)
|
57 |
+
);
|
58 |
+
console.log(
|
59 |
+
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
|
60 |
+
);
|
61 |
+
console.log(
|
62 |
+
`Learn more here: ${chalk.yellow('https://cra.link/advanced-config')}`
|
63 |
+
);
|
64 |
+
console.log();
|
65 |
+
}
|
66 |
+
|
67 |
+
// We require that you explicitly set browsers and do not fall back to
|
68 |
+
// browserslist defaults.
|
69 |
+
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
|
70 |
+
checkBrowsers(paths.appPath, isInteractive)
|
71 |
+
.then(() => {
|
72 |
+
// We attempt to use the default port but if it is busy, we offer the user to
|
73 |
+
// run on a different port. `choosePort()` Promise resolves to the next free port.
|
74 |
+
return choosePort(HOST, DEFAULT_PORT);
|
75 |
+
})
|
76 |
+
.then(port => {
|
77 |
+
if (port == null) {
|
78 |
+
// We have not found a port.
|
79 |
+
return;
|
80 |
+
}
|
81 |
+
|
82 |
+
const config = configFactory('development');
|
83 |
+
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
|
84 |
+
const appName = require(paths.appPackageJson).name;
|
85 |
+
|
86 |
+
const useTypeScript = fs.existsSync(paths.appTsConfig);
|
87 |
+
const urls = prepareUrls(
|
88 |
+
protocol,
|
89 |
+
HOST,
|
90 |
+
port,
|
91 |
+
paths.publicUrlOrPath.slice(0, -1)
|
92 |
+
);
|
93 |
+
// Create a webpack compiler that is configured with custom messages.
|
94 |
+
const compiler = createCompiler({
|
95 |
+
appName,
|
96 |
+
config,
|
97 |
+
urls,
|
98 |
+
useYarn,
|
99 |
+
useTypeScript,
|
100 |
+
webpack,
|
101 |
+
});
|
102 |
+
// Load proxy config
|
103 |
+
const proxySetting = require(paths.appPackageJson).proxy;
|
104 |
+
const proxyConfig = prepareProxy(
|
105 |
+
proxySetting,
|
106 |
+
paths.appPublic,
|
107 |
+
paths.publicUrlOrPath
|
108 |
+
);
|
109 |
+
// Serve webpack assets generated by the compiler over a web server.
|
110 |
+
const serverConfig = {
|
111 |
+
...createDevServerConfig(proxyConfig, urls.lanUrlForConfig),
|
112 |
+
host: HOST,
|
113 |
+
port,
|
114 |
+
};
|
115 |
+
const devServer = new WebpackDevServer(serverConfig, compiler);
|
116 |
+
// Launch WebpackDevServer.
|
117 |
+
devServer.startCallback(() => {
|
118 |
+
if (isInteractive) {
|
119 |
+
clearConsole();
|
120 |
+
}
|
121 |
+
|
122 |
+
if (env.raw.FAST_REFRESH && semver.lt(react.version, '16.10.0')) {
|
123 |
+
console.log(
|
124 |
+
chalk.yellow(
|
125 |
+
`Fast Refresh requires React 16.10 or higher. You are using React ${react.version}.`
|
126 |
+
)
|
127 |
+
);
|
128 |
+
}
|
129 |
+
|
130 |
+
console.log(chalk.cyan('Starting the development server...\n'));
|
131 |
+
openBrowser(urls.localUrlForBrowser);
|
132 |
+
});
|
133 |
+
|
134 |
+
['SIGINT', 'SIGTERM'].forEach(function (sig) {
|
135 |
+
process.on(sig, function () {
|
136 |
+
devServer.close();
|
137 |
+
process.exit();
|
138 |
+
});
|
139 |
+
});
|
140 |
+
|
141 |
+
if (process.env.CI !== 'true') {
|
142 |
+
// Gracefully exit when stdin ends
|
143 |
+
process.stdin.on('end', function () {
|
144 |
+
devServer.close();
|
145 |
+
process.exit();
|
146 |
+
});
|
147 |
+
}
|
148 |
+
})
|
149 |
+
.catch(err => {
|
150 |
+
if (err && err.message) {
|
151 |
+
console.log(err.message);
|
152 |
+
}
|
153 |
+
process.exit(1);
|
154 |
+
});
|
lama_cleaner/app/scripts/test.js
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict';
|
2 |
+
|
3 |
+
// Do this as the first thing so that any code reading it knows the right env.
|
4 |
+
process.env.BABEL_ENV = 'test';
|
5 |
+
process.env.NODE_ENV = 'test';
|
6 |
+
process.env.PUBLIC_URL = '';
|
7 |
+
|
8 |
+
// Makes the script crash on unhandled rejections instead of silently
|
9 |
+
// ignoring them. In the future, promise rejections that are not handled will
|
10 |
+
// terminate the Node.js process with a non-zero exit code.
|
11 |
+
process.on('unhandledRejection', err => {
|
12 |
+
throw err;
|
13 |
+
});
|
14 |
+
|
15 |
+
// Ensure environment variables are read.
|
16 |
+
require('../config/env');
|
17 |
+
|
18 |
+
const jest = require('jest');
|
19 |
+
const execSync = require('child_process').execSync;
|
20 |
+
let argv = process.argv.slice(2);
|
21 |
+
|
22 |
+
function isInGitRepository() {
|
23 |
+
try {
|
24 |
+
execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
|
25 |
+
return true;
|
26 |
+
} catch (e) {
|
27 |
+
return false;
|
28 |
+
}
|
29 |
+
}
|
30 |
+
|
31 |
+
function isInMercurialRepository() {
|
32 |
+
try {
|
33 |
+
execSync('hg --cwd . root', { stdio: 'ignore' });
|
34 |
+
return true;
|
35 |
+
} catch (e) {
|
36 |
+
return false;
|
37 |
+
}
|
38 |
+
}
|
39 |
+
|
40 |
+
// Watch unless on CI or explicitly running all tests
|
41 |
+
if (
|
42 |
+
!process.env.CI &&
|
43 |
+
argv.indexOf('--watchAll') === -1 &&
|
44 |
+
argv.indexOf('--watchAll=false') === -1
|
45 |
+
) {
|
46 |
+
// https://github.com/facebook/create-react-app/issues/5210
|
47 |
+
const hasSourceControl = isInGitRepository() || isInMercurialRepository();
|
48 |
+
argv.push(hasSourceControl ? '--watch' : '--watchAll');
|
49 |
+
}
|
50 |
+
|
51 |
+
|
52 |
+
jest.run(argv);
|
lama_cleaner/app/src/App.tsx
ADDED
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, { useCallback, useEffect, useMemo } from 'react'
|
2 |
+
import { useRecoilState, useSetRecoilState } from 'recoil'
|
3 |
+
import { nanoid } from 'nanoid'
|
4 |
+
import useInputImage from './hooks/useInputImage'
|
5 |
+
import { themeState } from './components/Header/ThemeChanger'
|
6 |
+
import Workspace from './components/Workspace'
|
7 |
+
import {
|
8 |
+
enableFileManagerState,
|
9 |
+
fileState,
|
10 |
+
isDisableModelSwitchState,
|
11 |
+
toastState,
|
12 |
+
} from './store/Atoms'
|
13 |
+
import { keepGUIAlive } from './utils'
|
14 |
+
import Header from './components/Header/Header'
|
15 |
+
import useHotKey from './hooks/useHotkey'
|
16 |
+
import {
|
17 |
+
getEnableFileManager,
|
18 |
+
getIsDisableModelSwitch,
|
19 |
+
isDesktop,
|
20 |
+
} from './adapters/inpainting'
|
21 |
+
|
22 |
+
const SUPPORTED_FILE_TYPE = [
|
23 |
+
'image/jpeg',
|
24 |
+
'image/png',
|
25 |
+
'image/webp',
|
26 |
+
'image/bmp',
|
27 |
+
'image/tiff',
|
28 |
+
]
|
29 |
+
|
30 |
+
function App() {
|
31 |
+
const [file, setFile] = useRecoilState(fileState)
|
32 |
+
const [theme, setTheme] = useRecoilState(themeState)
|
33 |
+
const setToastState = useSetRecoilState(toastState)
|
34 |
+
const userInputImage = useInputImage()
|
35 |
+
const setIsDisableModelSwitch = useSetRecoilState(isDisableModelSwitchState)
|
36 |
+
const setEnableFileManager = useSetRecoilState(enableFileManagerState)
|
37 |
+
|
38 |
+
// Set Input Image
|
39 |
+
useEffect(() => {
|
40 |
+
setFile(userInputImage)
|
41 |
+
}, [userInputImage, setFile])
|
42 |
+
|
43 |
+
// Keeping GUI Window Open
|
44 |
+
useEffect(() => {
|
45 |
+
const fetchData = async () => {
|
46 |
+
const isRunDesktop = await isDesktop().then(res => res.text())
|
47 |
+
if (isRunDesktop === 'True') {
|
48 |
+
keepGUIAlive()
|
49 |
+
}
|
50 |
+
}
|
51 |
+
fetchData()
|
52 |
+
}, [])
|
53 |
+
|
54 |
+
useEffect(() => {
|
55 |
+
const fetchData = async () => {
|
56 |
+
const isDisable: string = await getIsDisableModelSwitch().then(res =>
|
57 |
+
res.text()
|
58 |
+
)
|
59 |
+
setIsDisableModelSwitch(isDisable === 'true')
|
60 |
+
}
|
61 |
+
|
62 |
+
fetchData()
|
63 |
+
|
64 |
+
const fetchData2 = async () => {
|
65 |
+
const isEnabled = await getEnableFileManager().then(res => res.text())
|
66 |
+
setEnableFileManager(isEnabled === 'true')
|
67 |
+
}
|
68 |
+
fetchData2()
|
69 |
+
}, [setEnableFileManager, setIsDisableModelSwitch])
|
70 |
+
|
71 |
+
// Dark Mode Hotkey
|
72 |
+
useHotKey(
|
73 |
+
'shift+d',
|
74 |
+
() => {
|
75 |
+
const newTheme = theme === 'light' ? 'dark' : 'light'
|
76 |
+
setTheme(newTheme)
|
77 |
+
},
|
78 |
+
{},
|
79 |
+
[theme]
|
80 |
+
)
|
81 |
+
|
82 |
+
useEffect(() => {
|
83 |
+
document.body.setAttribute('data-theme', theme)
|
84 |
+
}, [theme])
|
85 |
+
|
86 |
+
const workspaceId = useMemo(() => {
|
87 |
+
return nanoid()
|
88 |
+
}, [file])
|
89 |
+
|
90 |
+
///
|
91 |
+
|
92 |
+
const [isDragging, setIsDragging] = React.useState(false)
|
93 |
+
const dragCounter = React.useRef(0)
|
94 |
+
|
95 |
+
const handleDrag = React.useCallback(event => {
|
96 |
+
event.preventDefault()
|
97 |
+
event.stopPropagation()
|
98 |
+
}, [])
|
99 |
+
|
100 |
+
const handleDragIn = React.useCallback(event => {
|
101 |
+
event.preventDefault()
|
102 |
+
event.stopPropagation()
|
103 |
+
dragCounter.current += 1
|
104 |
+
if (event.dataTransfer.items && event.dataTransfer.items.length > 0) {
|
105 |
+
setIsDragging(true)
|
106 |
+
}
|
107 |
+
}, [])
|
108 |
+
|
109 |
+
const handleDragOut = React.useCallback(event => {
|
110 |
+
event.preventDefault()
|
111 |
+
event.stopPropagation()
|
112 |
+
dragCounter.current -= 1
|
113 |
+
if (dragCounter.current > 0) return
|
114 |
+
setIsDragging(false)
|
115 |
+
}, [])
|
116 |
+
|
117 |
+
const handleDrop = React.useCallback(
|
118 |
+
event => {
|
119 |
+
event.preventDefault()
|
120 |
+
event.stopPropagation()
|
121 |
+
setIsDragging(false)
|
122 |
+
if (event.dataTransfer.files && event.dataTransfer.files.length > 0) {
|
123 |
+
if (event.dataTransfer.files.length > 1) {
|
124 |
+
setToastState({
|
125 |
+
open: true,
|
126 |
+
desc: 'Please drag and drop only one file',
|
127 |
+
state: 'error',
|
128 |
+
duration: 3000,
|
129 |
+
})
|
130 |
+
} else {
|
131 |
+
const dragFile = event.dataTransfer.files[0]
|
132 |
+
const fileType = dragFile.type
|
133 |
+
if (SUPPORTED_FILE_TYPE.includes(fileType)) {
|
134 |
+
setFile(dragFile)
|
135 |
+
} else {
|
136 |
+
setToastState({
|
137 |
+
open: true,
|
138 |
+
desc: 'Please drag and drop an image file',
|
139 |
+
state: 'error',
|
140 |
+
duration: 3000,
|
141 |
+
})
|
142 |
+
}
|
143 |
+
}
|
144 |
+
event.dataTransfer.clearData()
|
145 |
+
}
|
146 |
+
},
|
147 |
+
[setToastState, setFile]
|
148 |
+
)
|
149 |
+
|
150 |
+
const onPaste = useCallback((event: any) => {
|
151 |
+
// TODO: when sd side panel open, ctrl+v not work
|
152 |
+
// https://htmldom.dev/paste-an-image-from-the-clipboard/
|
153 |
+
if (!event.clipboardData) {
|
154 |
+
return
|
155 |
+
}
|
156 |
+
const clipboardItems = event.clipboardData.items
|
157 |
+
const items: DataTransferItem[] = [].slice
|
158 |
+
.call(clipboardItems)
|
159 |
+
.filter((item: DataTransferItem) => {
|
160 |
+
// Filter the image items only
|
161 |
+
return item.type.indexOf('image') !== -1
|
162 |
+
})
|
163 |
+
|
164 |
+
if (items.length === 0) {
|
165 |
+
return
|
166 |
+
}
|
167 |
+
|
168 |
+
event.preventDefault()
|
169 |
+
event.stopPropagation()
|
170 |
+
|
171 |
+
// TODO: add confirm dialog
|
172 |
+
|
173 |
+
const item = items[0]
|
174 |
+
// Get the blob of image
|
175 |
+
const blob = item.getAsFile()
|
176 |
+
if (blob) {
|
177 |
+
setFile(blob)
|
178 |
+
}
|
179 |
+
}, [])
|
180 |
+
|
181 |
+
React.useEffect(() => {
|
182 |
+
window.addEventListener('dragenter', handleDragIn)
|
183 |
+
window.addEventListener('dragleave', handleDragOut)
|
184 |
+
window.addEventListener('dragover', handleDrag)
|
185 |
+
window.addEventListener('drop', handleDrop)
|
186 |
+
window.addEventListener('paste', onPaste)
|
187 |
+
return function cleanUp() {
|
188 |
+
window.removeEventListener('dragenter', handleDragIn)
|
189 |
+
window.removeEventListener('dragleave', handleDragOut)
|
190 |
+
window.removeEventListener('dragover', handleDrag)
|
191 |
+
window.removeEventListener('drop', handleDrop)
|
192 |
+
window.removeEventListener('paste', onPaste)
|
193 |
+
}
|
194 |
+
})
|
195 |
+
|
196 |
+
return (
|
197 |
+
<div className="lama-cleaner">
|
198 |
+
<Header />
|
199 |
+
<Workspace key={workspaceId} />
|
200 |
+
</div>
|
201 |
+
)
|
202 |
+
}
|
203 |
+
|
204 |
+
export default App
|
lama_cleaner/app/src/adapters/inpainting.ts
ADDED
@@ -0,0 +1,225 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Rect, Settings } from '../store/Atoms'
|
2 |
+
import { dataURItoBlob, srcToFile } from '../utils'
|
3 |
+
|
4 |
+
export const API_ENDPOINT = `${process.env.REACT_APP_INPAINTING_URL}`
|
5 |
+
|
6 |
+
export default async function inpaint(
|
7 |
+
imageFile: File,
|
8 |
+
settings: Settings,
|
9 |
+
croperRect: Rect,
|
10 |
+
prompt?: string,
|
11 |
+
negativePrompt?: string,
|
12 |
+
sizeLimit?: string,
|
13 |
+
seed?: number,
|
14 |
+
maskBase64?: string,
|
15 |
+
customMask?: File,
|
16 |
+
paintByExampleImage?: File
|
17 |
+
) {
|
18 |
+
// 1080, 2000, Original
|
19 |
+
const fd = new FormData()
|
20 |
+
fd.append('image', imageFile)
|
21 |
+
if (maskBase64 !== undefined) {
|
22 |
+
fd.append('mask', dataURItoBlob(maskBase64))
|
23 |
+
} else if (customMask !== undefined) {
|
24 |
+
fd.append('mask', customMask)
|
25 |
+
}
|
26 |
+
|
27 |
+
const hdSettings = settings.hdSettings[settings.model]
|
28 |
+
fd.append('ldmSteps', settings.ldmSteps.toString())
|
29 |
+
fd.append('ldmSampler', settings.ldmSampler.toString())
|
30 |
+
fd.append('zitsWireframe', settings.zitsWireframe.toString())
|
31 |
+
fd.append('hdStrategy', hdSettings.hdStrategy)
|
32 |
+
fd.append('hdStrategyCropMargin', hdSettings.hdStrategyCropMargin.toString())
|
33 |
+
fd.append(
|
34 |
+
'hdStrategyCropTrigerSize',
|
35 |
+
hdSettings.hdStrategyCropTrigerSize.toString()
|
36 |
+
)
|
37 |
+
fd.append(
|
38 |
+
'hdStrategyResizeLimit',
|
39 |
+
hdSettings.hdStrategyResizeLimit.toString()
|
40 |
+
)
|
41 |
+
|
42 |
+
fd.append('prompt', prompt === undefined ? '' : prompt)
|
43 |
+
fd.append(
|
44 |
+
'negativePrompt',
|
45 |
+
negativePrompt === undefined ? '' : negativePrompt
|
46 |
+
)
|
47 |
+
fd.append('croperX', croperRect.x.toString())
|
48 |
+
fd.append('croperY', croperRect.y.toString())
|
49 |
+
fd.append('croperHeight', croperRect.height.toString())
|
50 |
+
fd.append('croperWidth', croperRect.width.toString())
|
51 |
+
fd.append('useCroper', settings.showCroper ? 'true' : 'false')
|
52 |
+
|
53 |
+
fd.append('sdMaskBlur', settings.sdMaskBlur.toString())
|
54 |
+
fd.append('sdStrength', settings.sdStrength.toString())
|
55 |
+
fd.append('sdSteps', settings.sdSteps.toString())
|
56 |
+
fd.append('sdGuidanceScale', settings.sdGuidanceScale.toString())
|
57 |
+
fd.append('sdSampler', settings.sdSampler.toString())
|
58 |
+
fd.append('sdSeed', seed ? seed.toString() : '-1')
|
59 |
+
fd.append('sdMatchHistograms', settings.sdMatchHistograms ? 'true' : 'false')
|
60 |
+
fd.append('sdScale', (settings.sdScale / 100).toString())
|
61 |
+
|
62 |
+
fd.append('cv2Radius', settings.cv2Radius.toString())
|
63 |
+
fd.append('cv2Flag', settings.cv2Flag.toString())
|
64 |
+
|
65 |
+
fd.append('paintByExampleSteps', settings.paintByExampleSteps.toString())
|
66 |
+
fd.append(
|
67 |
+
'paintByExampleGuidanceScale',
|
68 |
+
settings.paintByExampleGuidanceScale.toString()
|
69 |
+
)
|
70 |
+
fd.append('paintByExampleSeed', seed ? seed.toString() : '-1')
|
71 |
+
fd.append(
|
72 |
+
'paintByExampleMaskBlur',
|
73 |
+
settings.paintByExampleMaskBlur.toString()
|
74 |
+
)
|
75 |
+
fd.append(
|
76 |
+
'paintByExampleMatchHistograms',
|
77 |
+
settings.paintByExampleMatchHistograms ? 'true' : 'false'
|
78 |
+
)
|
79 |
+
// TODO: resize image's shortest_edge to 224 before pass to backend, save network time?
|
80 |
+
// https://huggingface.co/docs/transformers/model_doc/clip#transformers.CLIPImageProcessor
|
81 |
+
if (paintByExampleImage) {
|
82 |
+
fd.append('paintByExampleImage', paintByExampleImage)
|
83 |
+
}
|
84 |
+
|
85 |
+
if (sizeLimit === undefined) {
|
86 |
+
fd.append('sizeLimit', '1080')
|
87 |
+
} else {
|
88 |
+
fd.append('sizeLimit', sizeLimit)
|
89 |
+
}
|
90 |
+
|
91 |
+
try {
|
92 |
+
const res = await fetch(`${API_ENDPOINT}/inpaint`, {
|
93 |
+
method: 'POST',
|
94 |
+
body: fd,
|
95 |
+
})
|
96 |
+
if (res.ok) {
|
97 |
+
const blob = await res.blob()
|
98 |
+
const newSeed = res.headers.get('x-seed')
|
99 |
+
return { blob: URL.createObjectURL(blob), seed: newSeed }
|
100 |
+
}
|
101 |
+
const errMsg = await res.text()
|
102 |
+
throw new Error(errMsg)
|
103 |
+
} catch (error) {
|
104 |
+
throw new Error(`Something went wrong: ${error}`)
|
105 |
+
}
|
106 |
+
}
|
107 |
+
|
108 |
+
export function getIsDisableModelSwitch() {
|
109 |
+
return fetch(`${API_ENDPOINT}/is_disable_model_switch`, {
|
110 |
+
method: 'GET',
|
111 |
+
})
|
112 |
+
}
|
113 |
+
|
114 |
+
export function getEnableFileManager() {
|
115 |
+
return fetch(`${API_ENDPOINT}/is_enable_file_manager`, {
|
116 |
+
method: 'GET',
|
117 |
+
})
|
118 |
+
}
|
119 |
+
|
120 |
+
export function switchModel(name: string) {
|
121 |
+
const fd = new FormData()
|
122 |
+
fd.append('name', name)
|
123 |
+
return fetch(`${API_ENDPOINT}/model`, {
|
124 |
+
method: 'POST',
|
125 |
+
body: fd,
|
126 |
+
})
|
127 |
+
}
|
128 |
+
|
129 |
+
export function currentModel() {
|
130 |
+
return fetch(`${API_ENDPOINT}/model`, {
|
131 |
+
method: 'GET',
|
132 |
+
})
|
133 |
+
}
|
134 |
+
|
135 |
+
export function isDesktop() {
|
136 |
+
return fetch(`${API_ENDPOINT}/is_desktop`, {
|
137 |
+
method: 'GET',
|
138 |
+
})
|
139 |
+
}
|
140 |
+
|
141 |
+
export function modelDownloaded(name: string) {
|
142 |
+
return fetch(`${API_ENDPOINT}/model_downloaded/${name}`, {
|
143 |
+
method: 'GET',
|
144 |
+
})
|
145 |
+
}
|
146 |
+
|
147 |
+
export async function postInteractiveSeg(
|
148 |
+
imageFile: File,
|
149 |
+
maskFile: File | null,
|
150 |
+
clicks: number[][]
|
151 |
+
) {
|
152 |
+
const fd = new FormData()
|
153 |
+
fd.append('image', imageFile)
|
154 |
+
fd.append('clicks', JSON.stringify(clicks))
|
155 |
+
if (maskFile !== null) {
|
156 |
+
fd.append('mask', maskFile)
|
157 |
+
}
|
158 |
+
|
159 |
+
try {
|
160 |
+
const res = await fetch(`${API_ENDPOINT}/interactive_seg`, {
|
161 |
+
method: 'POST',
|
162 |
+
body: fd,
|
163 |
+
})
|
164 |
+
if (res.ok) {
|
165 |
+
const blob = await res.blob()
|
166 |
+
return { blob: URL.createObjectURL(blob) }
|
167 |
+
}
|
168 |
+
const errMsg = await res.text()
|
169 |
+
throw new Error(errMsg)
|
170 |
+
} catch (error) {
|
171 |
+
throw new Error(`Something went wrong: ${error}`)
|
172 |
+
}
|
173 |
+
}
|
174 |
+
|
175 |
+
export async function getMediaFile(tab: string, filename: string) {
|
176 |
+
const res = await fetch(
|
177 |
+
`${API_ENDPOINT}/media/${tab}/${encodeURIComponent(filename)}`,
|
178 |
+
{
|
179 |
+
method: 'GET',
|
180 |
+
}
|
181 |
+
)
|
182 |
+
if (res.ok) {
|
183 |
+
const blob = await res.blob()
|
184 |
+
const file = new File([blob], filename)
|
185 |
+
return file
|
186 |
+
}
|
187 |
+
const errMsg = await res.text()
|
188 |
+
throw new Error(errMsg)
|
189 |
+
}
|
190 |
+
|
191 |
+
export async function getMedias(tab: string) {
|
192 |
+
const res = await fetch(`${API_ENDPOINT}/medias/${tab}`, {
|
193 |
+
method: 'GET',
|
194 |
+
})
|
195 |
+
if (res.ok) {
|
196 |
+
const filenames = await res.json()
|
197 |
+
return filenames
|
198 |
+
}
|
199 |
+
const errMsg = await res.text()
|
200 |
+
throw new Error(errMsg)
|
201 |
+
}
|
202 |
+
|
203 |
+
export async function downloadToOutput(
|
204 |
+
image: HTMLImageElement,
|
205 |
+
filename: string,
|
206 |
+
mimeType: string
|
207 |
+
) {
|
208 |
+
const file = await srcToFile(image.src, filename, mimeType)
|
209 |
+
const fd = new FormData()
|
210 |
+
fd.append('image', file)
|
211 |
+
fd.append('filename', filename)
|
212 |
+
|
213 |
+
try {
|
214 |
+
const res = await fetch(`${API_ENDPOINT}/save_image`, {
|
215 |
+
method: 'POST',
|
216 |
+
body: fd,
|
217 |
+
})
|
218 |
+
if (!res.ok) {
|
219 |
+
const errMsg = await res.text()
|
220 |
+
throw new Error(errMsg)
|
221 |
+
}
|
222 |
+
} catch (error) {
|
223 |
+
throw new Error(`Something went wrong: ${error}`)
|
224 |
+
}
|
225 |
+
}
|
lama_cleaner/app/src/components/CoffeeIcon/CoffeeIcon.tsx
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, { useState } from 'react'
|
2 |
+
import { Coffee } from 'react-feather'
|
3 |
+
import Button from '../shared/Button'
|
4 |
+
import Modal from '../shared/Modal'
|
5 |
+
|
6 |
+
const CoffeeIcon = () => {
|
7 |
+
const [show, setShow] = useState(false)
|
8 |
+
const onClick = () => {
|
9 |
+
setShow(true)
|
10 |
+
}
|
11 |
+
|
12 |
+
return (
|
13 |
+
<div>
|
14 |
+
<Button
|
15 |
+
onClick={onClick}
|
16 |
+
toolTip="Buy me a coffee"
|
17 |
+
style={{ border: 0 }}
|
18 |
+
icon={<Coffee />}
|
19 |
+
/>
|
20 |
+
<Modal
|
21 |
+
onClose={() => setShow(false)}
|
22 |
+
title="Buy Me a Coffee"
|
23 |
+
className="modal-setting"
|
24 |
+
show={show}
|
25 |
+
showCloseIcon={false}
|
26 |
+
>
|
27 |
+
<h4 style={{ lineHeight: '24px' }}>
|
28 |
+
Hi there, If you found my project is useful, and want to help keep it
|
29 |
+
alive please consider donating! Thank you for your support!
|
30 |
+
</h4>
|
31 |
+
<div
|
32 |
+
style={{
|
33 |
+
display: 'flex',
|
34 |
+
width: '100%',
|
35 |
+
justifyContent: 'flex-end',
|
36 |
+
alignItems: 'center',
|
37 |
+
gap: '12px',
|
38 |
+
}}
|
39 |
+
>
|
40 |
+
<Button onClick={() => setShow(false)}> No thanks </Button>
|
41 |
+
<a
|
42 |
+
href="https://ko-fi.com/Z8Z1CZJGY"
|
43 |
+
target="_blank"
|
44 |
+
rel="noreferrer"
|
45 |
+
>
|
46 |
+
<Button border onClick={() => setShow(false)}>
|
47 |
+
<div
|
48 |
+
style={{
|
49 |
+
display: 'flex',
|
50 |
+
justifyContent: 'center',
|
51 |
+
alignItems: 'center',
|
52 |
+
gap: '8px',
|
53 |
+
}}
|
54 |
+
>
|
55 |
+
Sure
|
56 |
+
<Coffee />
|
57 |
+
</div>
|
58 |
+
</Button>
|
59 |
+
</a>
|
60 |
+
</div>
|
61 |
+
</Modal>
|
62 |
+
</div>
|
63 |
+
)
|
64 |
+
}
|
65 |
+
|
66 |
+
export default CoffeeIcon
|
lama_cleaner/app/src/components/Croper/Croper.scss
ADDED
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@use 'sass:math';
|
2 |
+
|
3 |
+
$drag-handle-shortside: 12px;
|
4 |
+
$drag-handle-longside: 40px;
|
5 |
+
$drag-bar-size: 12px;
|
6 |
+
|
7 |
+
$half-handle-shortside: math.div($drag-handle-shortside, 2);
|
8 |
+
$half-handle-longside: math.div($drag-handle-longside, 2);
|
9 |
+
$half-drag-bar-size: math.div($drag-bar-size, 2);
|
10 |
+
|
11 |
+
.crop-border {
|
12 |
+
outline-color: var(--yellow-accent);
|
13 |
+
outline-style: dashed;
|
14 |
+
}
|
15 |
+
|
16 |
+
.info-bar {
|
17 |
+
position: absolute;
|
18 |
+
pointer-events: auto;
|
19 |
+
font-size: 1rem;
|
20 |
+
padding: 0.2rem 0.8rem;
|
21 |
+
display: flex;
|
22 |
+
align-items: center;
|
23 |
+
justify-content: center;
|
24 |
+
gap: 12px;
|
25 |
+
color: var(--text-color);
|
26 |
+
background-color: var(--page-bg);
|
27 |
+
border-radius: 9999px;
|
28 |
+
|
29 |
+
border: var(--editor-toolkit-panel-border);
|
30 |
+
box-shadow: 0 0 0 1px #0000001a, 0 3px 16px #00000014, 0 2px 6px 1px #00000017;
|
31 |
+
|
32 |
+
&:hover {
|
33 |
+
cursor: move;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
.croper-wrapper {
|
38 |
+
position: absolute;
|
39 |
+
height: 100%;
|
40 |
+
width: 100%;
|
41 |
+
z-index: 2;
|
42 |
+
overflow: hidden;
|
43 |
+
pointer-events: none;
|
44 |
+
}
|
45 |
+
|
46 |
+
.croper {
|
47 |
+
position: relative;
|
48 |
+
top: 0;
|
49 |
+
bottom: 0;
|
50 |
+
left: 0;
|
51 |
+
right: 0;
|
52 |
+
z-index: 2;
|
53 |
+
pointer-events: none;
|
54 |
+
|
55 |
+
// display: flex;
|
56 |
+
// flex-direction: column;
|
57 |
+
// align-items: center;
|
58 |
+
|
59 |
+
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5);
|
60 |
+
}
|
61 |
+
|
62 |
+
.drag-bar {
|
63 |
+
position: absolute;
|
64 |
+
pointer-events: auto;
|
65 |
+
// display: none;
|
66 |
+
|
67 |
+
&.ord-top {
|
68 |
+
top: 0;
|
69 |
+
left: 0;
|
70 |
+
width: 100%;
|
71 |
+
height: $drag-bar-size;
|
72 |
+
margin-top: -$half-drag-bar-size;
|
73 |
+
cursor: ns-resize;
|
74 |
+
}
|
75 |
+
&.ord-right {
|
76 |
+
right: 0;
|
77 |
+
top: 0;
|
78 |
+
width: $drag-bar-size;
|
79 |
+
height: 100%;
|
80 |
+
margin-right: -$half-drag-bar-size;
|
81 |
+
cursor: ew-resize;
|
82 |
+
}
|
83 |
+
&.ord-bottom {
|
84 |
+
bottom: 0;
|
85 |
+
left: 0;
|
86 |
+
width: 100%;
|
87 |
+
height: $drag-bar-size;
|
88 |
+
margin-bottom: -$half-drag-bar-size;
|
89 |
+
cursor: ns-resize;
|
90 |
+
}
|
91 |
+
&.ord-left {
|
92 |
+
top: 0;
|
93 |
+
left: 0;
|
94 |
+
width: $drag-bar-size;
|
95 |
+
height: 100%;
|
96 |
+
margin-left: -$half-drag-bar-size;
|
97 |
+
cursor: ew-resize;
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
.drag-handle {
|
102 |
+
width: $drag-handle-shortside;
|
103 |
+
height: $drag-handle-shortside;
|
104 |
+
z-index: 4;
|
105 |
+
position: absolute;
|
106 |
+
display: block;
|
107 |
+
content: '';
|
108 |
+
border: 2px solid var(--yellow-accent);
|
109 |
+
background-color: var(--yellow-accent-light);
|
110 |
+
pointer-events: auto;
|
111 |
+
|
112 |
+
&:hover {
|
113 |
+
background-color: var(--yellow-accent);
|
114 |
+
}
|
115 |
+
|
116 |
+
&.ord-topleft {
|
117 |
+
cursor: nw-resize;
|
118 |
+
top: (-$half-handle-shortside)-1px;
|
119 |
+
left: (-$half-handle-shortside)-1px;
|
120 |
+
}
|
121 |
+
|
122 |
+
&.ord-topright {
|
123 |
+
cursor: ne-resize;
|
124 |
+
top: -($half-handle-shortside)-1px;
|
125 |
+
right: -($half-handle-shortside)-1px;
|
126 |
+
}
|
127 |
+
|
128 |
+
&.ord-bottomright {
|
129 |
+
cursor: se-resize;
|
130 |
+
bottom: -($half-handle-shortside)-1px;
|
131 |
+
right: -($half-handle-shortside)-1px;
|
132 |
+
}
|
133 |
+
|
134 |
+
&.ord-bottomleft {
|
135 |
+
cursor: sw-resize;
|
136 |
+
bottom: -($half-handle-shortside)-1px;
|
137 |
+
left: -($half-handle-shortside)-1px;
|
138 |
+
}
|
139 |
+
|
140 |
+
&.ord-top,
|
141 |
+
&.ord-bottom {
|
142 |
+
left: calc(50% - $half-handle-shortside);
|
143 |
+
cursor: ns-resize;
|
144 |
+
}
|
145 |
+
|
146 |
+
&.ord-top {
|
147 |
+
top: (-$half-handle-shortside)-1px;
|
148 |
+
}
|
149 |
+
|
150 |
+
&.ord-bottom {
|
151 |
+
bottom: -($half-handle-shortside)-1px;
|
152 |
+
}
|
153 |
+
|
154 |
+
&.ord-left,
|
155 |
+
&.ord-right {
|
156 |
+
top: calc(50% - $half-handle-shortside);
|
157 |
+
cursor: ew-resize;
|
158 |
+
}
|
159 |
+
|
160 |
+
&.ord-left {
|
161 |
+
left: (-$half-handle-shortside)-1px;
|
162 |
+
}
|
163 |
+
|
164 |
+
&.ord-right {
|
165 |
+
right: -($half-handle-shortside)-1px;
|
166 |
+
}
|
167 |
+
}
|
lama_cleaner/app/src/components/Croper/Croper.tsx
ADDED
@@ -0,0 +1,408 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, { useEffect, useState } from 'react'
|
2 |
+
import { useRecoilState, useRecoilValue } from 'recoil'
|
3 |
+
import {
|
4 |
+
croperHeight,
|
5 |
+
croperWidth,
|
6 |
+
croperX,
|
7 |
+
croperY,
|
8 |
+
isInpaintingState,
|
9 |
+
} from '../../store/Atoms'
|
10 |
+
|
11 |
+
const DOC_MOVE_OPTS = { capture: true, passive: false }
|
12 |
+
|
13 |
+
const DRAG_HANDLE_BORDER = 2
|
14 |
+
const DRAG_HANDLE_SHORT = 12
|
15 |
+
const DRAG_HANDLE_LONG = 40
|
16 |
+
|
17 |
+
interface EVData {
|
18 |
+
initX: number
|
19 |
+
initY: number
|
20 |
+
initHeight: number
|
21 |
+
initWidth: number
|
22 |
+
startResizeX: number
|
23 |
+
startResizeY: number
|
24 |
+
ord: string // top/right/bottom/left
|
25 |
+
}
|
26 |
+
|
27 |
+
interface Props {
|
28 |
+
maxHeight: number
|
29 |
+
maxWidth: number
|
30 |
+
scale: number
|
31 |
+
minHeight: number
|
32 |
+
minWidth: number
|
33 |
+
show: boolean
|
34 |
+
}
|
35 |
+
|
36 |
+
const clamp = (
|
37 |
+
newPos: number,
|
38 |
+
newLength: number,
|
39 |
+
oldPos: number,
|
40 |
+
oldLength: number,
|
41 |
+
minLength: number,
|
42 |
+
maxLength: number
|
43 |
+
) => {
|
44 |
+
if (newPos !== oldPos && newLength === oldLength) {
|
45 |
+
if (newPos < 0) {
|
46 |
+
return [0, oldLength]
|
47 |
+
}
|
48 |
+
if (newPos + newLength > maxLength) {
|
49 |
+
return [maxLength - oldLength, oldLength]
|
50 |
+
}
|
51 |
+
} else {
|
52 |
+
if (newLength < minLength) {
|
53 |
+
if (newPos === oldPos) {
|
54 |
+
return [newPos, minLength]
|
55 |
+
}
|
56 |
+
return [newPos + newLength - minLength, minLength]
|
57 |
+
}
|
58 |
+
if (newPos < 0) {
|
59 |
+
return [0, newPos + newLength]
|
60 |
+
}
|
61 |
+
if (newPos + newLength > maxLength) {
|
62 |
+
return [newPos, maxLength - newPos]
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
return [newPos, newLength]
|
67 |
+
}
|
68 |
+
|
69 |
+
const Croper = (props: Props) => {
|
70 |
+
const { minHeight, minWidth, maxHeight, maxWidth, scale, show } = props
|
71 |
+
const [x, setX] = useRecoilState(croperX)
|
72 |
+
const [y, setY] = useRecoilState(croperY)
|
73 |
+
const [height, setHeight] = useRecoilState(croperHeight)
|
74 |
+
const [width, setWidth] = useRecoilState(croperWidth)
|
75 |
+
const isInpainting = useRecoilValue(isInpaintingState)
|
76 |
+
|
77 |
+
const [isResizing, setIsResizing] = useState(false)
|
78 |
+
const [isMoving, setIsMoving] = useState(false)
|
79 |
+
|
80 |
+
useEffect(() => {
|
81 |
+
setX(Math.round((maxWidth - 512) / 2))
|
82 |
+
setY(Math.round((maxHeight - 512) / 2))
|
83 |
+
}, [maxHeight, maxWidth])
|
84 |
+
|
85 |
+
const [evData, setEVData] = useState<EVData>({
|
86 |
+
initX: 0,
|
87 |
+
initY: 0,
|
88 |
+
initHeight: 0,
|
89 |
+
initWidth: 0,
|
90 |
+
startResizeX: 0,
|
91 |
+
startResizeY: 0,
|
92 |
+
ord: 'top',
|
93 |
+
})
|
94 |
+
|
95 |
+
const onDragFocus = () => {
|
96 |
+
console.log('focus')
|
97 |
+
}
|
98 |
+
|
99 |
+
const clampLeftRight = (newX: number, newWidth: number) => {
|
100 |
+
return clamp(newX, newWidth, x, width, minWidth, maxWidth)
|
101 |
+
}
|
102 |
+
|
103 |
+
const clampTopBottom = (newY: number, newHeight: number) => {
|
104 |
+
return clamp(newY, newHeight, y, height, minHeight, maxHeight)
|
105 |
+
}
|
106 |
+
|
107 |
+
const onPointerMove = (e: PointerEvent) => {
|
108 |
+
if (isInpainting) {
|
109 |
+
return
|
110 |
+
}
|
111 |
+
const curX = e.clientX
|
112 |
+
const curY = e.clientY
|
113 |
+
|
114 |
+
const offsetY = Math.round((curY - evData.startResizeY) / scale)
|
115 |
+
const offsetX = Math.round((curX - evData.startResizeX) / scale)
|
116 |
+
|
117 |
+
const moveTop = () => {
|
118 |
+
const newHeight = evData.initHeight - offsetY
|
119 |
+
const newY = evData.initY + offsetY
|
120 |
+
const [clampedY, clampedHeight] = clampTopBottom(newY, newHeight)
|
121 |
+
setHeight(clampedHeight)
|
122 |
+
setY(clampedY)
|
123 |
+
}
|
124 |
+
|
125 |
+
const moveBottom = () => {
|
126 |
+
const newHeight = evData.initHeight + offsetY
|
127 |
+
const [clampedY, clampedHeight] = clampTopBottom(evData.initY, newHeight)
|
128 |
+
setHeight(clampedHeight)
|
129 |
+
setY(clampedY)
|
130 |
+
}
|
131 |
+
|
132 |
+
const moveLeft = () => {
|
133 |
+
const newWidth = evData.initWidth - offsetX
|
134 |
+
const newX = evData.initX + offsetX
|
135 |
+
const [clampedX, clampedWidth] = clampLeftRight(newX, newWidth)
|
136 |
+
setWidth(clampedWidth)
|
137 |
+
setX(clampedX)
|
138 |
+
}
|
139 |
+
|
140 |
+
const moveRight = () => {
|
141 |
+
const newWidth = evData.initWidth + offsetX
|
142 |
+
const [clampedX, clampedWidth] = clampLeftRight(evData.initX, newWidth)
|
143 |
+
setWidth(clampedWidth)
|
144 |
+
setX(clampedX)
|
145 |
+
}
|
146 |
+
|
147 |
+
if (isResizing) {
|
148 |
+
switch (evData.ord) {
|
149 |
+
case 'topleft': {
|
150 |
+
moveTop()
|
151 |
+
moveLeft()
|
152 |
+
break
|
153 |
+
}
|
154 |
+
case 'topright': {
|
155 |
+
moveTop()
|
156 |
+
moveRight()
|
157 |
+
break
|
158 |
+
}
|
159 |
+
case 'bottomleft': {
|
160 |
+
moveBottom()
|
161 |
+
moveLeft()
|
162 |
+
break
|
163 |
+
}
|
164 |
+
case 'bottomright': {
|
165 |
+
moveBottom()
|
166 |
+
moveRight()
|
167 |
+
break
|
168 |
+
}
|
169 |
+
case 'top': {
|
170 |
+
moveTop()
|
171 |
+
break
|
172 |
+
}
|
173 |
+
case 'right': {
|
174 |
+
moveRight()
|
175 |
+
break
|
176 |
+
}
|
177 |
+
case 'bottom': {
|
178 |
+
moveBottom()
|
179 |
+
break
|
180 |
+
}
|
181 |
+
case 'left': {
|
182 |
+
moveLeft()
|
183 |
+
break
|
184 |
+
}
|
185 |
+
|
186 |
+
default:
|
187 |
+
break
|
188 |
+
}
|
189 |
+
}
|
190 |
+
|
191 |
+
if (isMoving) {
|
192 |
+
const newX = evData.initX + offsetX
|
193 |
+
const newY = evData.initY + offsetY
|
194 |
+
const [clampedX, clampedWidth] = clampLeftRight(newX, evData.initWidth)
|
195 |
+
const [clampedY, clampedHeight] = clampTopBottom(newY, evData.initHeight)
|
196 |
+
setWidth(clampedWidth)
|
197 |
+
setHeight(clampedHeight)
|
198 |
+
setX(clampedX)
|
199 |
+
setY(clampedY)
|
200 |
+
}
|
201 |
+
}
|
202 |
+
|
203 |
+
const onPointerDone = (e: PointerEvent) => {
|
204 |
+
if (isResizing) {
|
205 |
+
setIsResizing(false)
|
206 |
+
}
|
207 |
+
|
208 |
+
if (isMoving) {
|
209 |
+
setIsMoving(false)
|
210 |
+
}
|
211 |
+
}
|
212 |
+
|
213 |
+
useEffect(() => {
|
214 |
+
if (isResizing || isMoving) {
|
215 |
+
document.addEventListener('pointermove', onPointerMove, DOC_MOVE_OPTS)
|
216 |
+
document.addEventListener('pointerup', onPointerDone, DOC_MOVE_OPTS)
|
217 |
+
document.addEventListener('pointercancel', onPointerDone, DOC_MOVE_OPTS)
|
218 |
+
return () => {
|
219 |
+
document.removeEventListener(
|
220 |
+
'pointermove',
|
221 |
+
onPointerMove,
|
222 |
+
DOC_MOVE_OPTS
|
223 |
+
)
|
224 |
+
document.removeEventListener('pointerup', onPointerDone, DOC_MOVE_OPTS)
|
225 |
+
document.removeEventListener(
|
226 |
+
'pointercancel',
|
227 |
+
onPointerDone,
|
228 |
+
DOC_MOVE_OPTS
|
229 |
+
)
|
230 |
+
}
|
231 |
+
}
|
232 |
+
}, [isResizing, isMoving, width, height, evData])
|
233 |
+
|
234 |
+
const onCropPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
|
235 |
+
const { ord } = (e.target as HTMLElement).dataset
|
236 |
+
if (ord) {
|
237 |
+
setIsResizing(true)
|
238 |
+
setEVData({
|
239 |
+
initX: x,
|
240 |
+
initY: y,
|
241 |
+
initHeight: height,
|
242 |
+
initWidth: width,
|
243 |
+
startResizeX: e.clientX,
|
244 |
+
startResizeY: e.clientY,
|
245 |
+
ord,
|
246 |
+
})
|
247 |
+
}
|
248 |
+
}
|
249 |
+
|
250 |
+
const createCropSelection = () => {
|
251 |
+
return (
|
252 |
+
<div
|
253 |
+
className="drag-elements"
|
254 |
+
onFocus={onDragFocus}
|
255 |
+
onPointerDown={onCropPointerDown}
|
256 |
+
>
|
257 |
+
<div
|
258 |
+
className="drag-bar ord-top"
|
259 |
+
data-ord="top"
|
260 |
+
style={{ transform: `scale(${1 / scale})` }}
|
261 |
+
/>
|
262 |
+
<div
|
263 |
+
className="drag-bar ord-right"
|
264 |
+
data-ord="right"
|
265 |
+
style={{ transform: `scale(${1 / scale})` }}
|
266 |
+
/>
|
267 |
+
<div
|
268 |
+
className="drag-bar ord-bottom"
|
269 |
+
data-ord="bottom"
|
270 |
+
style={{ transform: `scale(${1 / scale})` }}
|
271 |
+
/>
|
272 |
+
<div
|
273 |
+
className="drag-bar ord-left"
|
274 |
+
data-ord="left"
|
275 |
+
style={{ transform: `scale(${1 / scale})` }}
|
276 |
+
/>
|
277 |
+
|
278 |
+
<div
|
279 |
+
className="drag-handle ord-topleft"
|
280 |
+
data-ord="topleft"
|
281 |
+
aria-label="topleft"
|
282 |
+
tabIndex={0}
|
283 |
+
role="button"
|
284 |
+
style={{ transform: `scale(${1 / scale})` }}
|
285 |
+
/>
|
286 |
+
|
287 |
+
<div
|
288 |
+
className="drag-handle ord-topright"
|
289 |
+
data-ord="topright"
|
290 |
+
aria-label="topright"
|
291 |
+
tabIndex={0}
|
292 |
+
role="button"
|
293 |
+
style={{ transform: `scale(${1 / scale})` }}
|
294 |
+
/>
|
295 |
+
|
296 |
+
<div
|
297 |
+
className="drag-handle ord-bottomleft"
|
298 |
+
data-ord="bottomleft"
|
299 |
+
aria-label="bottomleft"
|
300 |
+
tabIndex={0}
|
301 |
+
role="button"
|
302 |
+
style={{ transform: `scale(${1 / scale})` }}
|
303 |
+
/>
|
304 |
+
|
305 |
+
<div
|
306 |
+
className="drag-handle ord-bottomright"
|
307 |
+
data-ord="bottomright"
|
308 |
+
aria-label="bottomright"
|
309 |
+
tabIndex={0}
|
310 |
+
role="button"
|
311 |
+
style={{ transform: `scale(${1 / scale})` }}
|
312 |
+
/>
|
313 |
+
|
314 |
+
<div
|
315 |
+
className="drag-handle ord-top"
|
316 |
+
data-ord="top"
|
317 |
+
aria-label="top"
|
318 |
+
tabIndex={0}
|
319 |
+
role="button"
|
320 |
+
style={{ transform: `scale(${1 / scale})` }}
|
321 |
+
/>
|
322 |
+
<div
|
323 |
+
className="drag-handle ord-right"
|
324 |
+
data-ord="right"
|
325 |
+
aria-label="right"
|
326 |
+
tabIndex={0}
|
327 |
+
role="button"
|
328 |
+
style={{ transform: `scale(${1 / scale})` }}
|
329 |
+
/>
|
330 |
+
<div
|
331 |
+
className="drag-handle ord-bottom"
|
332 |
+
data-ord="bottom"
|
333 |
+
aria-label="bottom"
|
334 |
+
tabIndex={0}
|
335 |
+
role="button"
|
336 |
+
style={{ transform: `scale(${1 / scale})` }}
|
337 |
+
/>
|
338 |
+
<div
|
339 |
+
className="drag-handle ord-left"
|
340 |
+
data-ord="left"
|
341 |
+
aria-label="left"
|
342 |
+
tabIndex={0}
|
343 |
+
role="button"
|
344 |
+
style={{ transform: `scale(${1 / scale})` }}
|
345 |
+
/>
|
346 |
+
</div>
|
347 |
+
)
|
348 |
+
}
|
349 |
+
|
350 |
+
const onInfoBarPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
|
351 |
+
setIsMoving(true)
|
352 |
+
setEVData({
|
353 |
+
initX: x,
|
354 |
+
initY: y,
|
355 |
+
initHeight: height,
|
356 |
+
initWidth: width,
|
357 |
+
startResizeX: e.clientX,
|
358 |
+
startResizeY: e.clientY,
|
359 |
+
ord: '',
|
360 |
+
})
|
361 |
+
}
|
362 |
+
|
363 |
+
const createInfoBar = () => {
|
364 |
+
return (
|
365 |
+
<div
|
366 |
+
className="info-bar"
|
367 |
+
onPointerDown={onInfoBarPointerDown}
|
368 |
+
style={{
|
369 |
+
transform: `scale(${1 / scale})`,
|
370 |
+
top: `${10 / scale}px`,
|
371 |
+
left: `${10 / scale}px`,
|
372 |
+
}}
|
373 |
+
>
|
374 |
+
<div className="crop-size">
|
375 |
+
{width} x {height}
|
376 |
+
</div>
|
377 |
+
</div>
|
378 |
+
)
|
379 |
+
}
|
380 |
+
|
381 |
+
const createBorder = () => {
|
382 |
+
return (
|
383 |
+
<div
|
384 |
+
className="crop-border"
|
385 |
+
style={{
|
386 |
+
height,
|
387 |
+
width,
|
388 |
+
outlineWidth: `${DRAG_HANDLE_BORDER / scale}px`,
|
389 |
+
}}
|
390 |
+
/>
|
391 |
+
)
|
392 |
+
}
|
393 |
+
|
394 |
+
return (
|
395 |
+
<div
|
396 |
+
className="croper-wrapper"
|
397 |
+
style={{ visibility: show ? 'visible' : 'hidden' }}
|
398 |
+
>
|
399 |
+
<div className="croper" style={{ height, width, left: x, top: y }}>
|
400 |
+
{createBorder()}
|
401 |
+
{createInfoBar()}
|
402 |
+
{createCropSelection()}
|
403 |
+
</div>
|
404 |
+
</div>
|
405 |
+
)
|
406 |
+
}
|
407 |
+
|
408 |
+
export default Croper
|
lama_cleaner/app/src/components/Editor/Editor.scss
ADDED
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@use '../../styles/Mixins' as *;
|
2 |
+
|
3 |
+
.editor-container {
|
4 |
+
display: flex;
|
5 |
+
width: 100vw;
|
6 |
+
height: 100vh;
|
7 |
+
justify-content: center;
|
8 |
+
align-items: center;
|
9 |
+
}
|
10 |
+
|
11 |
+
.react-transform-wrapper {
|
12 |
+
display: grid !important;
|
13 |
+
width: 100% !important;
|
14 |
+
height: 100% !important;
|
15 |
+
}
|
16 |
+
|
17 |
+
.editor-canvas-container {
|
18 |
+
display: grid;
|
19 |
+
grid-template-areas: 'editor-content';
|
20 |
+
row-gap: 1rem;
|
21 |
+
}
|
22 |
+
|
23 |
+
.editor-canvas {
|
24 |
+
grid-area: editor-content;
|
25 |
+
z-index: 2;
|
26 |
+
}
|
27 |
+
|
28 |
+
.original-image-container {
|
29 |
+
grid-area: editor-content;
|
30 |
+
pointer-events: none;
|
31 |
+
display: grid;
|
32 |
+
grid-template-areas: 'original-image-content';
|
33 |
+
|
34 |
+
img {
|
35 |
+
grid-area: original-image-content;
|
36 |
+
}
|
37 |
+
|
38 |
+
.editor-slider {
|
39 |
+
grid-area: original-image-content;
|
40 |
+
height: 100%;
|
41 |
+
width: 6px;
|
42 |
+
justify-self: end;
|
43 |
+
background-color: var(--yellow-accent);
|
44 |
+
transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
45 |
+
z-index: 2;
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
+
.editor-canvas-loading {
|
50 |
+
pointer-events: none;
|
51 |
+
animation: pulsing 750ms infinite;
|
52 |
+
}
|
53 |
+
|
54 |
+
.editor-toolkit-panel {
|
55 |
+
position: fixed;
|
56 |
+
bottom: 0.5rem;
|
57 |
+
border-radius: 3rem;
|
58 |
+
padding: 0.6rem 3rem;
|
59 |
+
display: grid;
|
60 |
+
grid-template-areas: 'toolkit-size-selector toolkit-brush-slider toolkit-btns';
|
61 |
+
column-gap: 2rem;
|
62 |
+
align-items: center;
|
63 |
+
justify-content: center;
|
64 |
+
backdrop-filter: blur(12px);
|
65 |
+
background-color: var(--page-bg-light);
|
66 |
+
animation: slideUp 0.2s ease-out;
|
67 |
+
border: var(--editor-toolkit-panel-border);
|
68 |
+
box-shadow: 0 0 0 1px #0000001a, 0 3px 16px #00000014, 0 2px 6px 1px #00000017;
|
69 |
+
|
70 |
+
@include mobile {
|
71 |
+
padding: 1rem 2rem;
|
72 |
+
grid-template-areas:
|
73 |
+
'toolkit-size-selector toolkit-size-selector'
|
74 |
+
'toolkit-brush-slider toolkit-brush-slider'
|
75 |
+
'toolkit-btns toolkit-btns';
|
76 |
+
row-gap: 2rem;
|
77 |
+
justify-items: center;
|
78 |
+
}
|
79 |
+
|
80 |
+
.eyeicon-active {
|
81 |
+
background-color: var(--yellow-accent);
|
82 |
+
color: var(--btn-text-hover-color);
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
.editor-brush-slider {
|
87 |
+
grid-area: toolkit-brush-slider;
|
88 |
+
user-select: none;
|
89 |
+
display: grid;
|
90 |
+
grid-template-columns: repeat(2, max-content);
|
91 |
+
height: max-content;
|
92 |
+
column-gap: 1rem;
|
93 |
+
align-items: center;
|
94 |
+
|
95 |
+
@include slider-bar;
|
96 |
+
}
|
97 |
+
|
98 |
+
.editor-toolkit-btns {
|
99 |
+
grid-area: toolkit-btns;
|
100 |
+
display: grid;
|
101 |
+
grid-auto-flow: column;
|
102 |
+
column-gap: 1rem;
|
103 |
+
}
|
104 |
+
|
105 |
+
.brush-shape {
|
106 |
+
position: absolute;
|
107 |
+
border-radius: 50%;
|
108 |
+
background-color: #ffcc00bb;
|
109 |
+
border: 1px solid var(--yellow-accent);
|
110 |
+
pointer-events: none;
|
111 |
+
}
|