From cc258f8b777aa7b4321a0c4bf67bb3145efa7100 Mon Sep 17 00:00:00 2001 From: juanarias8 Date: Thu, 5 Mar 2026 01:33:46 -0500 Subject: [PATCH 01/28] update .gitignore to exclude /infra/charts --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a8aa541..4c0b84d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ etc/cloudflare/**/*.json *.pyc node_modules .vscode/settings.json +/infra/charts/** \ No newline at end of file From bf9c2a353ca7ccd0a10ef01e01fb5c393fad4a7b Mon Sep 17 00:00:00 2001 From: juanarias8 Date: Thu, 5 Mar 2026 01:33:56 -0500 Subject: [PATCH 02/28] add CLAUDE.md with project guidelines and development instructions --- CLAUDE.md | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..6810191 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,175 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Morpheus is an open-source web platform for AI image generation using Stable Diffusion. It is a multi-service monorepo where each service is independently containerized and orchestrated via Docker Compose locally, and deployed to AWS EKS in production. + +## Services and Architecture + +``` +morpheus-client (Next.js, port 3000) +morpheus-admin (Next.js, port 3001) +morpheus-collaborative (Node.js/Socket.io, port 3002) + | +morpheus-server (FastAPI, port 8001) + | | | +PostgreSQL (5432) AWS S3 morpheus-worker (Ray, ports 8000/8265) + | + Firebase (Auth/Collab) +``` + +- **morpheus-data** is a shared Python library (built as a wheel) used by `morpheus-server` and `morpheus-worker`. It owns all SQLAlchemy models, Pydantic schemas, Alembic migrations, and S3/Firebase repository implementations. +- **morpheus-server** is the FastAPI backend. It depends on the `morpheus-data` wheel being built first. +- **morpheus-worker** runs a Ray cluster for GPU-accelerated Stable Diffusion inference. +- The client uses Firebase for authentication and Socket.io for real-time collaboration. + +## Development Commands + +### Starting the environment + +```bash +# Copy secrets templates and fill in values +cp morpheus-server/secrets.env.dist morpheus-server/secrets.env +cp morpheus-client/env.local.dist morpheus-client/.env.local +cp morpheus-client/env.local.dist morpheus-admin/.env.local + +# Apply DB migrations (required before first start) +docker compose run --rm datalib alembic upgrade head + +# Start all services +docker compose up + +# Start specific services +docker compose up api client admin +``` + +### Backend (morpheus-server / morpheus-data) + +```bash +# Run all tests +docker compose run --rm api pytest + +# Run a single test file +docker compose run --rm api pytest tests/test_module.py + +# Run a single test +docker compose run --rm api pytest tests/test_module.py::test_function + +# Lint +docker compose run --rm api flake8 --max-line-length 120 --exclude app/migrations/ . + +# Format +docker compose run --rm api black --line-length 120 --exclude app/migrations/ . +``` + +### Database migrations + +```bash +# Auto-generate a migration from model changes +docker compose run --rm datalib alembic revision --autogenerate -m "Description" + +# Apply pending migrations +docker compose run --rm datalib alembic upgrade head +``` + +### Frontend (morpheus-client / morpheus-admin) + +```bash +# Lint +docker compose exec client yarn lint +docker compose exec admin yarn lint + +# Direct yarn usage (outside Docker) +cd morpheus-client && yarn dev # port 3000 +cd morpheus-admin && yarn dev # port 3001 +``` + +### Collaborative server + +```bash +docker compose exec collaborative yarn test:code # ESLint +docker compose exec collaborative yarn fix # Prettier + ESLint fix +``` + +### Building Docker images + +```bash +# Build order matters: datalib must be built first +docker compose build datalib # generates wheel file consumed by api/worker +docker compose build api +docker compose build client admin collaborative + +# Build all +docker compose build +``` + +### Model management CLI + +```bash +docker compose --profile manage build # build the model-script service +docker compose run --rm model-script --help +docker compose run --rm model-script s3 list +docker compose run --rm model-script db register +``` + +## Code Architecture Details + +### morpheus-data (shared library) + +All database models live in `morpheus_data/models/models.py` (SQLAlchemy) and `morpheus_data/models/schemas.py` (Pydantic). Changes here require rebuilding the wheel (`docker compose build datalib`) before dependent services pick them up. + +Repository classes in `morpheus_data/repository/` follow the repository pattern and are the only place that touches the database or S3 directly. + +### morpheus-server structure + +``` +app/ + api/ # FastAPI route handlers (thin layer, delegates to services) + services/ # Business logic + models/ # Pydantic request/response models (distinct from DB models) + integrations/ # Third-party integrations + config.py # Pydantic Settings (reads from secrets.env) + app.py # FastAPI app setup, router registration +main.py # Uvicorn entry point +``` + +### Key configuration + +| File | Purpose | +|------|---------| +| `morpheus-server/secrets.env` | Backend secrets (DB, Firebase, AWS, Ray URL) | +| `morpheus-client/.env.local` | Frontend env (API URL, Firebase config, WS URL) | +| `morpheus-server/app/config.py` | Pydantic Settings class | +| `morpheus-worker/models.yaml` | Ray Serve deployment configuration | +| `docker-compose.yaml` | Service orchestration for local dev | + +### Python code standards + +- Black formatter with `--line-length 120` +- Flake8 with `--max-line-length 120 --exclude app/migrations/` +- Alembic migrations live in `morpheus-data/morpheus_data/migrations/` + +### TypeScript/JavaScript code standards + +- ESLint for both frontend apps and collaborative server +- Prettier for collaborative server (`yarn fix`) + +## Commit conventions + +Follow Conventional Commits: +- `feat:` new feature +- `fix:` bug fix +- `chore:` tooling/deps +- `docs:` documentation +- `refactor:` restructuring +- `test:` tests +- `perf:` performance + +## Infrastructure + +- Production runs on AWS EKS (Kubernetes), provisioned with Terraform in `infra/` +- Helm charts are in `infra/charts/` +- CI/CD is via GitHub Actions (`.github/workflows/`); `monorepo/cicd.py` detects which services changed to run targeted pipelines +- Monitoring: Sentry (errors), Ray Dashboard (port 8265), Prometheus/Grafana (production) \ No newline at end of file From 11ddc19650747692b35827e8f05fe0eeeb7ef0c8 Mon Sep 17 00:00:00 2001 From: juanarias8 Date: Thu, 5 Mar 2026 01:34:31 -0500 Subject: [PATCH 03/28] update Dockerfiles to use node:20-slim and simplify dependencies installation --- docker-compose.yaml | 3 ++- morpheus-admin/Dockerfile | 16 +++------------- morpheus-client/Dockerfile | 14 ++------------ morpheus-collaborative/Dockerfile | 16 +++------------- morpheus-server/Dockerfile | 2 +- 5 files changed, 11 insertions(+), 40 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 290a9ed..40f6899 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,4 +1,3 @@ -version: "3.8" services: postgres: image: postgres:15-alpine @@ -57,6 +56,8 @@ services: args: DOCKER_BUILDKIT: 1 image: monadicalsas/morpheus-data:${TAG:-latest} + env_file: + - morpheus-server/secrets.env volumes: - ./wheels:/wheels - ./morpheus-data:/app diff --git a/morpheus-admin/Dockerfile b/morpheus-admin/Dockerfile index 3ed7c3e..b1389db 100644 --- a/morpheus-admin/Dockerfile +++ b/morpheus-admin/Dockerfile @@ -1,22 +1,12 @@ -ARG BUILD_ENV="copy" -FROM debian:latest as base +ARG BUILD_ENV="no_copy" +FROM node:20-slim as base ENV LC_ALL C.UTF-8 ENV LANG C.UTF-8 -ENV NODE_MAJOR=18 ENV CLIENT_ROOT "/app" -# Install system requirements -RUN apt-get update && apt-get install -y \ - curl ca-certificates curl gnupg && \ - rm -rf /var/lib/apt/lists/* - -RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg -RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list -RUN apt-get update && apt-get install nodejs -y - -RUN npm install --global npm yarn next sass +RUN npm install --global next sass WORKDIR ${CLIENT_ROOT} diff --git a/morpheus-client/Dockerfile b/morpheus-client/Dockerfile index 22e64ce..5b220d5 100644 --- a/morpheus-client/Dockerfile +++ b/morpheus-client/Dockerfile @@ -1,22 +1,12 @@ ARG BUILD_ENV="copy" -FROM debian:latest as base +FROM node:20-slim as base ENV LC_ALL C.UTF-8 ENV LANG C.UTF-8 -ENV NODE_MAJOR=18 ENV CLIENT_ROOT "/app" -# Install system requirements -RUN apt-get update && apt-get install -y \ - curl ca-certificates curl gnupg && \ - rm -rf /var/lib/apt/lists/* - -RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg -RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list -RUN apt-get update && apt-get install nodejs -y - -RUN npm install --global npm yarn next sass +RUN npm install --global next sass WORKDIR ${CLIENT_ROOT} diff --git a/morpheus-collaborative/Dockerfile b/morpheus-collaborative/Dockerfile index 22e64ce..48769eb 100644 --- a/morpheus-collaborative/Dockerfile +++ b/morpheus-collaborative/Dockerfile @@ -1,22 +1,12 @@ -ARG BUILD_ENV="copy" -FROM debian:latest as base +ARG BUILD_ENV="no_copy" +FROM node:20-slim as base ENV LC_ALL C.UTF-8 ENV LANG C.UTF-8 -ENV NODE_MAJOR=18 ENV CLIENT_ROOT "/app" -# Install system requirements -RUN apt-get update && apt-get install -y \ - curl ca-certificates curl gnupg && \ - rm -rf /var/lib/apt/lists/* - -RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg -RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list -RUN apt-get update && apt-get install nodejs -y - -RUN npm install --global npm yarn next sass +RUN npm install --global next sass WORKDIR ${CLIENT_ROOT} diff --git a/morpheus-server/Dockerfile b/morpheus-server/Dockerfile index cd5c873..90d8b7d 100644 --- a/morpheus-server/Dockerfile +++ b/morpheus-server/Dockerfile @@ -34,7 +34,7 @@ ENV PATH="/root/.cargo/bin:${PATH}" # Install dependencies RUN pip install --upgrade pip COPY requirements.txt . -RUN pip install torch==1.13.1 && pip install -r requirements.txt --no-cache-dir +RUN pip install "torch>=2.0.0" && pip install -r requirements.txt --no-cache-dir # Find the latest wheel file of morpheus-data in the /wheels directory and install it COPY --from=lib /wheels /wheels From 95d5270066b6f0e8a7a6b3a704568221e6683b1b Mon Sep 17 00:00:00 2001 From: juanarias8 Date: Thu, 5 Mar 2026 01:34:38 -0500 Subject: [PATCH 04/28] update dependencies: bump torch to >=2.0.0, diffusers to >=0.28.0, and add pydantic to requirements --- morpheus-data/pyproject.toml | 4 ++-- morpheus-worker/requirements.txt | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/morpheus-data/pyproject.toml b/morpheus-data/pyproject.toml index 5c3ed18..3aabcab 100644 --- a/morpheus-data/pyproject.toml +++ b/morpheus-data/pyproject.toml @@ -17,8 +17,8 @@ dependencies = [ "tqdm>=4.65.0", "pillow>=9.5.0", "fastapi>=0.95.1", - "torch==1.13.1", - "diffusers==0.20.0", + "torch>=2.0.0", + "diffusers>=0.28.0", "dynamicprompts[attentiongrabber,magicprompt]", "safetensors", "loguru" diff --git a/morpheus-worker/requirements.txt b/morpheus-worker/requirements.txt index f30108d..5943e03 100644 --- a/morpheus-worker/requirements.txt +++ b/morpheus-worker/requirements.txt @@ -1,6 +1,7 @@ # Web serving ray[serve] loguru +pydantic>=1.10.7,<2 # Image handling and upload boto3 @@ -13,7 +14,7 @@ psycopg2-binary # Image generation torch -diffusers==0.21.1 +diffusers>=0.28.0 transformers accelerate xformers From c4f7171b4636233d08cbf188665c0d2adfdabab5 Mon Sep 17 00:00:00 2001 From: juanarias8 Date: Thu, 5 Mar 2026 01:39:30 -0500 Subject: [PATCH 05/28] feat(s3): implement presigned URLs for S3 file access - add expiration parameter to generate_public_url method - replace static public URLs with presigned URLs in relevant methods - update logic to handle presigned URLs in filename parsing - modify S3 upload method to return file key instead of static URL --- .../repository/files/files_interface.py | 3 +-- .../repository/files/s3_files_repository.py | 12 ++++++++---- .../app/services/sdiffusion_services.py | 15 +++++++++++++++ morpheus-worker/app/app.py | 2 +- morpheus-worker/app/integrations/s3_client.py | 2 +- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/morpheus-data/morpheus_data/repository/files/files_interface.py b/morpheus-data/morpheus_data/repository/files/files_interface.py index 6b56ca9..4fb27e6 100644 --- a/morpheus-data/morpheus_data/repository/files/files_interface.py +++ b/morpheus-data/morpheus_data/repository/files/files_interface.py @@ -48,9 +48,8 @@ def get_file_url(self, *, filename: str): def get_file_urls(self, filenames: list[str]): raise NotImplementedError("This method is not implemented") - @staticmethod @abstractmethod - def generate_public_url(*, file_name: str): + def generate_public_url(self, *, file_name: str, expiration: int = 3600): raise NotImplementedError("This method is not implemented") diff --git a/morpheus-data/morpheus_data/repository/files/s3_files_repository.py b/morpheus-data/morpheus_data/repository/files/s3_files_repository.py index 0a5fc68..fc7cc89 100644 --- a/morpheus-data/morpheus_data/repository/files/s3_files_repository.py +++ b/morpheus-data/morpheus_data/repository/files/s3_files_repository.py @@ -101,12 +101,15 @@ def get_files( logger.error("Error getting the images from AWS S3") logger.error(e) - @staticmethod - def generate_public_url(*, file_name: str): + def generate_public_url(self, *, file_name: str, expiration: int = 3600): try: - return f"https://{IMAGES_BUCKET}.s3.amazonaws.com/{file_name}" + return self.s3.generate_presigned_url( + "get_object", + Params={"Bucket": IMAGES_BUCKET, "Key": file_name}, + ExpiresIn=expiration, + ) except Exception as e: - logger.error("Error generating the public url") + logger.error("Error generating the presigned url") logger.error(e) def get_file_url(self, *, filename: str): @@ -174,4 +177,5 @@ def get_file_name(*, file: Union[UploadFile, Image.Image], folder_name: str): def get_file_path(*, object_url: str): splits = object_url.split("/") folder, filename = splits[-2], splits[-1] + filename = filename.split("?")[0] # strip query params from pre-signed URLs return folder, filename diff --git a/morpheus-server/app/services/sdiffusion_services.py b/morpheus-server/app/services/sdiffusion_services.py index b4e2ecf..2b5d1f5 100644 --- a/morpheus-server/app/services/sdiffusion_services.py +++ b/morpheus-server/app/services/sdiffusion_services.py @@ -9,6 +9,7 @@ ) from morpheus_data.models.schemas import GenerationRequest, TextGenerationRequest from morpheus_data.models.schemas import MagicPrompt, Prompt, PromptControlNet +from morpheus_data.repository.files.s3_files_repository import S3ImagesRepository from morpheus_data.repository.generation_repository import GenerationRepository from morpheus_data.repository.model_repository import ModelRepository from morpheus_data.repository.user_repository import UserRepository @@ -22,14 +23,28 @@ def __init__(self, generative_ai_generator: GenerativeAIInterface): self.generation_repository = GenerationRepository() self.model_repository = ModelRepository() self.user_repository = UserRepository() + self.files_repository = S3ImagesRepository() self.settings = get_settings() def get_generation_result(self, db: Session, task_id: str) -> str: generation = self.generation_repository.get_generation(db=db, generation_id=task_id) if generation is None: raise GenerationNotFoundError(f"Generation with id {task_id} not found") + if generation.results: + generation.results = [self._to_presigned_url(r) for r in generation.results] return generation + def _to_presigned_url(self, result: str) -> str: + """Convert an S3 key or legacy public URL to a pre-signed URL.""" + if result.startswith("https://"): + # Legacy format: extract key from URL (everything after the bucket domain) + # e.g. https://bucket.s3.amazonaws.com/folder/file.png -> folder/file.png + parts = result.split(".s3.amazonaws.com/", 1) + key = parts[1] if len(parts) == 2 else result + else: + key = result + return self.files_repository.generate_public_url(file_name=key) + def generate_text2img_images(self, db: Session, prompt: Prompt, email: str) -> str: backend_request = self._build_backend_request(db=db, prompt=prompt, email=email) if backend_request.model_id == "stabilityai/stable-diffusion-xl-base-1.0": diff --git a/morpheus-worker/app/app.py b/morpheus-worker/app/app.py index 87c488f..51bac28 100644 --- a/morpheus-worker/app/app.py +++ b/morpheus-worker/app/app.py @@ -26,7 +26,7 @@ app = FastAPI() -@serve.deployment(num_replicas=1, route_prefix="/") +@serve.deployment(num_replicas=1) @serve.ingress(app) class APIIngress: def __init__(self) -> None: diff --git a/morpheus-worker/app/integrations/s3_client.py b/morpheus-worker/app/integrations/s3_client.py index 1b276db..5a0242b 100644 --- a/morpheus-worker/app/integrations/s3_client.py +++ b/morpheus-worker/app/integrations/s3_client.py @@ -39,7 +39,7 @@ def upload_file(self, *, file: Any, file_name: str): Key=key, ) self.logger.info(f"Image uploaded to S3: {key}") - return f"https://{self.IMAGES_BUCKET}.s3.amazonaws.com/{key}" + return key except Exception as e: self.logger.error(f"Error uploading image to S3: {key}") self.logger.error(e) From 6cc005bb656f626b002311f4c1b813675ef089c8 Mon Sep 17 00:00:00 2001 From: juanarias8 Date: Thu, 5 Mar 2026 01:39:50 -0500 Subject: [PATCH 06/28] feat(artwork-card): move click handler to container div - remove redundant onClick from AppImage component - add onClick to outer div for better event handling --- morpheus-client/components/ArtworkCard/ArtworkCard.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/morpheus-client/components/ArtworkCard/ArtworkCard.tsx b/morpheus-client/components/ArtworkCard/ArtworkCard.tsx index 1ef3eab..d6c2c90 100644 --- a/morpheus-client/components/ArtworkCard/ArtworkCard.tsx +++ b/morpheus-client/components/ArtworkCard/ArtworkCard.tsx @@ -38,10 +38,9 @@ const ArtworkCard = (props: ImageCardProps) => { return ( -
+
{props.artwork?.image ? ( From 310548342d12908a642d5c4fbb449fe345247122 Mon Sep 17 00:00:00 2001 From: juanarias8 Date: Thu, 5 Mar 2026 01:40:02 -0500 Subject: [PATCH 07/28] feat(artwork-form): normalize title from prompt if artwork title is missing - handle missing artwork title by normalizing prompt into a valid title - simplify null/undefined checks with optional chaining --- .../ArtworkCard/ArtworkForm/ArtworkForm.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/morpheus-client/components/ArtworkCard/ArtworkForm/ArtworkForm.tsx b/morpheus-client/components/ArtworkCard/ArtworkForm/ArtworkForm.tsx index 499a30d..73a8068 100644 --- a/morpheus-client/components/ArtworkCard/ArtworkForm/ArtworkForm.tsx +++ b/morpheus-client/components/ArtworkCard/ArtworkForm/ArtworkForm.tsx @@ -27,11 +27,18 @@ const ArtworkForm = (props: ArtworkFormProps) => { const [selectedCollectionId, setSelectedCollectionId] = useState(""); useEffect(() => { - if (props.artwork && props.artwork.title) { + if (props.artwork?.title) { setTitle({ value: props.artwork.title, validators: [] }); + } else if (props.artwork?.prompt?.prompt) { + const normalized = props.artwork.prompt.prompt + .replace(/[^a-zA-Z0-9 ]/g, " ") + .replace(/\s+/g, " ") + .trim() + .slice(0, 64); + setTitle({ value: normalized, validators: [] }); } - if (props.artwork && props.artwork.collection_id) { + if (props.artwork?.collection_id) { setSelectedCollectionId(props.artwork.collection_id); } }, [props.artwork]); From 2bbda20f15b084c3972d64e4fbb47b3fb2d510cc Mon Sep 17 00:00:00 2001 From: juanarias8 Date: Thu, 5 Mar 2026 01:40:26 -0500 Subject: [PATCH 08/28] feat(imagine-menu): refactor feature rendering and improve UI handling - replace ModelsAccordion with dynamic feature filtering and rendering - refactor mobile modal logic and active feature label - improve feature item rendering and icon styling with React.cloneElement - remove unused Model and features-related legacy code --- .../components/ImagineMenu/ImagineMenu.tsx | 266 ++++++------------ .../OpenSource/OpenSource.module.scss | 1 + .../atoms/accordion/Accordion.module.scss | 5 + .../components/atoms/accordion/Accordion.tsx | 2 + 4 files changed, 100 insertions(+), 174 deletions(-) diff --git a/morpheus-client/components/ImagineMenu/ImagineMenu.tsx b/morpheus-client/components/ImagineMenu/ImagineMenu.tsx index 5b9151f..b194aa4 100644 --- a/morpheus-client/components/ImagineMenu/ImagineMenu.tsx +++ b/morpheus-client/components/ImagineMenu/ImagineMenu.tsx @@ -1,9 +1,8 @@ -import React, { Fragment, ReactNode, useEffect, useState } from "react"; +import React, { Fragment, ReactNode, useEffect, useRef, useState } from "react"; import { useRouter } from "next/router"; import Brand from "../Typography/Brand/Brand"; import { ModelCategory, useModels } from "@/context/ModelsContext"; -import { Accordion } from "@/components/atoms/accordion/Accordion"; import { Text2ImgIcon } from "../icons/text2img"; import { Img2ImgIcon } from "../icons/img2img"; import { ControlNetIcon } from "../icons/controlnet"; @@ -11,43 +10,59 @@ import { Pix2PixIcon } from "../icons/pix2pix"; import { InpaintingIcon } from "../icons/inpainting"; import { OpenSource } from "@/components/OpenSource/OpenSource"; import { EnhanceIcon } from "../icons/enhance"; -import AppTooltip from "@/components/Tooltip/AppTooltip"; import ButtonPrimary from "@/components/buttons/ButtonPrimary/ButtonPrimary"; import Modal from "@/components/Modal/Modal"; -import { - ControlNetDescription, - Img2ImgDescription, - InpaintingDescription, - Pix2PixDescription, - Text2ImgDescription, - UpscalingDescription, -} from "@/components/ImagineActionsDescription/ImagineActionsDescription"; -import { Model } from "@/models/models"; +import { useToastContext } from "@/context/ToastContext"; import styles from "./ImagineMenu.module.scss"; import useWindowDimensions from "@/hooks/useWindowDimensions"; +const categoryConfigs = [ + { + name: ModelCategory.Text2Image, + title: "Text To Image", + icon: , + }, + { + name: ModelCategory.Image2Image, + title: "Image to Image", + icon: , + }, + { + name: ModelCategory.Pix2Pix, + title: "Pix2Pix", + icon: , + }, + { + name: ModelCategory.ControlNet, + title: "ControlNet", + icon: , + }, + { + name: ModelCategory.Inpainting, + title: "In-painting", + icon: , + }, + { + name: ModelCategory.Upscaling, + title: "Upscaling", + icon: , + }, +]; + const ImagineMenu = () => { const router = useRouter(); - const { - models, - selectedModel, - activeLink, - setActiveLink, - findValidModelForFeature, - } = useModels(); + const { models, selectedModel, activeLink, setActiveLink, findValidModelForFeature } = useModels(); + const { showInfoAlert } = useToastContext(); const imagineOptionPath = router.pathname.split("/").pop(); - const [openItem, setOpenItem] = useState(); - const [showModelsModal, setShowModelsModal] = useState(false); + const [showMobileModal, setShowMobileModal] = useState(false); const { isMobile } = useWindowDimensions(); + const lastShownAlertRef = useRef(null); useEffect(() => { if (!router.pathname.endsWith("paint")) { - const currentModelSupportsFeature = - selectedModel && - selectedModel.categories && - selectedModel.categories.some( - (category) => category.name === imagineOptionPath - ); + const currentModelSupportsFeature = selectedModel?.categories?.some( + (c) => c.name === imagineOptionPath + ); if (currentModelSupportsFeature) { setActiveLink({ @@ -55,51 +70,53 @@ const ImagineMenu = () => { feature: imagineOptionPath as ModelCategory, }); } else { + const compatibleModel = findValidModelForFeature(imagineOptionPath as ModelCategory); setActiveLink({ - model: findValidModelForFeature(imagineOptionPath as ModelCategory), + model: compatibleModel, feature: imagineOptionPath as ModelCategory, }); } } }, [imagineOptionPath]); - const getMobileTitle = () => { - if (activeLink.model && activeLink.feature) { - return `${activeLink.model.name} / ${activeLink.feature}`; - } else { - return "No models found"; - } - }; + const activeFeatureLabel = + categoryConfigs.find((c) => c.name === activeLink.feature)?.title || + activeLink.feature || + "Select feature"; - const ModelsAccordion = models.map((model: Model) => ( - - - - )); + const visibleFeatures = categoryConfigs.filter((f) => + models.some((m) => m.categories.some((c) => c.name === f.name)) + ); + + const FeatureList = ( + + {visibleFeatures.map((feature) => ( + + ))} + + ); return isMobile ? ( setShowModelsModal(true)} + text={activeFeatureLabel} + onClick={() => setShowMobileModal(true)} loading={false} className={styles.mobileButton} /> setShowModelsModal(!showModelsModal)} + isOpen={showMobileModal} + toggleModal={() => setShowMobileModal(!showMobileModal)} > - {ModelsAccordion} + {FeatureList} ) : ( @@ -108,142 +125,43 @@ const ImagineMenu = () => {
-

Models

- {ModelsAccordion} +

Features

+ {FeatureList}
); }; -interface ImagineMenuFeaturesProps { - model: Model; -} - -const ModelMenuFeatures = (props: ImagineMenuFeaturesProps) => { - const { activeLink } = useModels(); - - const getItemActive = (option: ModelCategory | string) => { - return ( - activeLink.model.source === props.model.source && - activeLink.feature === option - ); - }; - - const getIconColor = (option: ModelCategory | string) => { - return getItemActive(option) ? "#B3005E" : "#6D6D94"; - }; - - const categoryConfigs = [ - { - name: ModelCategory.Text2Image, - title: "Text To Image", - description: , - icon: , - }, - { - name: ModelCategory.Image2Image, - title: "Image to Image", - description: , - icon: , - }, - { - name: ModelCategory.Pix2Pix, - title: "Pix2Pix", - description: , - icon: , - }, - { - name: ModelCategory.ControlNet, - title: "ControlNet", - description: , - icon: , - }, - { - name: ModelCategory.Inpainting, - title: "In-painting", - description: , - icon: , - }, - { - name: ModelCategory.Upscaling, - title: "Upscaling", - description: , - icon: , - }, - ]; - - return ( - - {categoryConfigs.map( - (category) => - props.model.categories.some( - (modelCategory) => modelCategory.name === category.name - ) && ( - - ) - )} - - ); -}; - -interface ImagineMenuItemProps { - active?: boolean; - icon: ReactNode; +interface FeatureItemProps { title: string; - description: ReactNode; - option: string; - model: Model; + icon: ReactNode; + feature: ModelCategory | string; + active: boolean; } -const ImagineMenuItem = (props: ImagineMenuItemProps) => { +const FeatureItem = (props: FeatureItemProps) => { const router = useRouter(); - const { setActiveLink, activeLink } = useModels(); - const { isMobile } = useWindowDimensions(); - const getItemStyles = () => { - return `${styles.menuItem} ${props.active && styles.active}`; + const handleClick = () => { + router.push(`/imagine/${props.feature}`); }; - const handleOnClick = () => { - setActiveLink({ - model: props.model, - feature: props.option as ModelCategory, - }); - }; - - useEffect(() => { - if (!router.pathname.endsWith("paint")) { - const baseUrl = !router.pathname.startsWith("imagine") ? "/imagine" : ""; - router.push(`${baseUrl}/${activeLink.feature}`); - } - }, [activeLink]); - return ( - -
- {props.icon} - - - {props.title} - -
-
+ + {React.cloneElement(props.icon as React.ReactElement, { + color: props.active ? "#B3005E" : "#6D6D94", + })} + + + {props.title} + + ); }; -export default ImagineMenu; +export default ImagineMenu; \ No newline at end of file diff --git a/morpheus-client/components/OpenSource/OpenSource.module.scss b/morpheus-client/components/OpenSource/OpenSource.module.scss index 2c98d7c..cf63324 100644 --- a/morpheus-client/components/OpenSource/OpenSource.module.scss +++ b/morpheus-client/components/OpenSource/OpenSource.module.scss @@ -11,6 +11,7 @@ border: 1px solid colors.$white-color; padding: 24px; gap: 14px; + margin-top: 48px !important; .openSourceTitle { display: flex; diff --git a/morpheus-client/components/atoms/accordion/Accordion.module.scss b/morpheus-client/components/atoms/accordion/Accordion.module.scss index 0734147..639bb30 100644 --- a/morpheus-client/components/atoms/accordion/Accordion.module.scss +++ b/morpheus-client/components/atoms/accordion/Accordion.module.scss @@ -24,6 +24,11 @@ span { margin-top: 4px; } + + .accordionIcon { + margin-top: 2px; + margin-right: 6px; + } } .accordionContent { diff --git a/morpheus-client/components/atoms/accordion/Accordion.tsx b/morpheus-client/components/atoms/accordion/Accordion.tsx index bd04d7a..3e2e769 100644 --- a/morpheus-client/components/atoms/accordion/Accordion.tsx +++ b/morpheus-client/components/atoms/accordion/Accordion.tsx @@ -6,6 +6,7 @@ import styles from "./Accordion.module.scss"; interface AccordionProps { itemId: string; title: string; + icon?: ReactNode; isOpen?: boolean; setOpenedItem: (item: string) => void; children: ReactNode; @@ -20,6 +21,7 @@ export const Accordion = (props: AccordionProps) => {
{props.isOpen ? : } + {props.icon && {props.icon}}

{props.title}

{props.isOpen && ( From 83c56a55f94e01fc61587a5945581151bb4331d2 Mon Sep 17 00:00:00 2001 From: juanarias8 Date: Thu, 5 Mar 2026 01:41:44 -0500 Subject: [PATCH 09/28] feat(imagine-base): improve component structure and UI updates - move ImagineSettings and ModelSelect to topBar section - adjust ImagineMenu styles with margin-bottom addition - add topBar styles for alignment and spacing in ImagineBase - refactor ModelSelect initialization and enhance compatibility filtering - add triggerClassName support to InputSelect component --- .../ImagineBase/ImagineBase.module.scss | 11 ++++- .../components/ImagineBase/ImagineBase.tsx | 12 +++++- .../ImagineInput/ImagineInput.module.scss | 1 + .../components/ImagineInput/ImagineInput.tsx | 5 +-- .../ImagineMenu/ImagineMenu.module.scss | 1 + .../Inputs/InputSelect/InputSelect.tsx | 3 +- .../components/ModelSelect/ModelSelect.tsx | 41 +++++++++++-------- 7 files changed, 50 insertions(+), 24 deletions(-) diff --git a/morpheus-client/components/ImagineBase/ImagineBase.module.scss b/morpheus-client/components/ImagineBase/ImagineBase.module.scss index cc9501d..a036e81 100644 --- a/morpheus-client/components/ImagineBase/ImagineBase.module.scss +++ b/morpheus-client/components/ImagineBase/ImagineBase.module.scss @@ -25,10 +25,19 @@ min-width: 300px; max-width: 100vw; + .topBar { + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-end; + padding: 16px 24px 0; + gap: 16px; + background-color: colors.$background-primary; + } + @include media.mobile { flex-direction: column; max-height: 100%; - background-color: colors.$background-secondary; } .imagesContent { diff --git a/morpheus-client/components/ImagineBase/ImagineBase.tsx b/morpheus-client/components/ImagineBase/ImagineBase.tsx index 012b476..ef65754 100644 --- a/morpheus-client/components/ImagineBase/ImagineBase.tsx +++ b/morpheus-client/components/ImagineBase/ImagineBase.tsx @@ -4,6 +4,8 @@ import ImagineImageInput from "@/components/ImagineImageInput/ImagineImageInput" import ImageGallery from "@/components/ImageGallery/ImageGallery"; import ImagineInput from "@/components/ImagineInput/ImagineInput"; import ImagineLayout from "@/layout/ImagineLayout/ImagineLayout"; +import ImagineSettings from "@/components/ImagineSettings/ImagineSettings"; +import ModelSelect from "@/components/ModelSelect/ModelSelect"; import { UploadMaskIcon } from "@/components/icons/uploadMask"; import { useImagine } from "@/context/ImagineContext"; import useWindowDimensions from "@/hooks/useWindowDimensions"; @@ -80,6 +82,13 @@ const ImagineBase = (props: MainContainerProps) => { )} + {!isMobile && ( +
+ + +
+ )} +
{!isMobile && ImageInputs} @@ -88,10 +97,11 @@ const ImagineBase = (props: MainContainerProps) => {
+ {!isMobile && ImagineInputInstance} ); }; -export default ImagineBase; +export default ImagineBase; \ No newline at end of file diff --git a/morpheus-client/components/ImagineInput/ImagineInput.module.scss b/morpheus-client/components/ImagineInput/ImagineInput.module.scss index 97d868b..df27707 100644 --- a/morpheus-client/components/ImagineInput/ImagineInput.module.scss +++ b/morpheus-client/components/ImagineInput/ImagineInput.module.scss @@ -4,6 +4,7 @@ .imagineInputWrapper { width: 100%; padding: 0 24px 24px 0; + background-color: colors.$background-secondary; @include media.mobile { diff --git a/morpheus-client/components/ImagineInput/ImagineInput.tsx b/morpheus-client/components/ImagineInput/ImagineInput.tsx index 11fd638..b974aad 100644 --- a/morpheus-client/components/ImagineInput/ImagineInput.tsx +++ b/morpheus-client/components/ImagineInput/ImagineInput.tsx @@ -2,7 +2,6 @@ import ButtonPrimary from "../buttons/ButtonPrimary/ButtonPrimary"; import InputTextArea from "../Inputs/InputTextArea/InputTextArea"; import { initialText, TextState } from "../Inputs/InputText/InputText"; import MagicPrompt from "../MagicPrompt/MagicPrompt"; -import ImagineSettings from "../ImagineSettings/ImagineSettings"; import { useDiffusion } from "@/context/DiffusionContext"; import { useImagine } from "@/context/ImagineContext"; import { useModels } from "@/context/ModelsContext"; @@ -30,6 +29,7 @@ const ImagineInput = (props: ImagineInputProps) => { const { prompt, setPrompt } = useDiffusion(); const { isLoading } = useImagine(); const isRequestValid = props.isFormValid && !!selectedModel; + return (
@@ -56,11 +56,10 @@ const ImagineInput = (props: ImagineInputProps) => { disabled={!isRequestValid} text={"Generate"} /> -
); }; -export default ImagineInput; +export default ImagineInput; \ No newline at end of file diff --git a/morpheus-client/components/ImagineMenu/ImagineMenu.module.scss b/morpheus-client/components/ImagineMenu/ImagineMenu.module.scss index c9b9918..474035c 100644 --- a/morpheus-client/components/ImagineMenu/ImagineMenu.module.scss +++ b/morpheus-client/components/ImagineMenu/ImagineMenu.module.scss @@ -68,6 +68,7 @@ margin-top: 16px; margin-left: 24px; font-weight: bold; + margin-bottom: 24px; &:hover { color: colors.$white-color !important; diff --git a/morpheus-client/components/Inputs/InputSelect/InputSelect.tsx b/morpheus-client/components/Inputs/InputSelect/InputSelect.tsx index 44770c9..7973e3c 100644 --- a/morpheus-client/components/Inputs/InputSelect/InputSelect.tsx +++ b/morpheus-client/components/Inputs/InputSelect/InputSelect.tsx @@ -15,6 +15,7 @@ export interface InputSelectProps { setSelected: (selected: string) => void; styles?: CSSProperties; optional?: boolean; + triggerClassName?: string; } const InputSelect = (props: InputSelectProps) => { @@ -30,7 +31,7 @@ const InputSelect = (props: InputSelectProps) => { value={props.selected} onValueChange={props.setSelected} > - + diff --git a/morpheus-client/components/ModelSelect/ModelSelect.tsx b/morpheus-client/components/ModelSelect/ModelSelect.tsx index 444ae43..476a33c 100644 --- a/morpheus-client/components/ModelSelect/ModelSelect.tsx +++ b/morpheus-client/components/ModelSelect/ModelSelect.tsx @@ -4,40 +4,45 @@ import { Model } from "@/models/models"; import { useModels } from "@/context/ModelsContext"; const ModelSelect = () => { - const { models, selectedModel, setSelectedModel } = useModels(); - const [modelOptions, setModelOptions] = useState([]); - const [localSelectedModel, setLocalSelectedModel] = useState( - models.find((m) => m.source === selectedModel.name)?.name || "" + const { models, selectedModel, activeLink, setActiveLink } = useModels(); + + const compatibleModels = models.filter((m: Model) => + m.categories.some((c) => c.name === activeLink.feature) + ); + + const modelOptions = compatibleModels.map((m: Model) => m.name); + + const [localSelected, setLocalSelected] = useState( + selectedModel?.name || "" ); useEffect(() => { - if (models && models.length > 0) { - setModelOptions(models.map((model: Model) => model.name) || []); + if (selectedModel?.name) { + setLocalSelected(selectedModel.name); } - }, [models]); + }, [selectedModel]); useEffect(() => { - if (models && models.length > 0) { - if (localSelectedModel && localSelectedModel !== selectedModel.name) { - const selected = models.find( - (m: Model) => m.name === localSelectedModel - ); - setSelectedModel(selected as Model); - } + if (!localSelected || localSelected === selectedModel?.name) return; + const model = models.find((m: Model) => m.name === localSelected); + if (model) { + setActiveLink({ model, feature: activeLink.feature }); } - }, [localSelectedModel]); + }, [localSelected]); return ( {modelOptions.length > 0 && ( )} ); }; -export default ModelSelect; +export default ModelSelect; \ No newline at end of file From 3ae4cbc79cf3906a192615ab7c4966dfe1051909 Mon Sep 17 00:00:00 2001 From: juanarias8 Date: Thu, 5 Mar 2026 12:30:36 -0500 Subject: [PATCH 10/28] refactor(styles): migrate SCSS/SASS to Tailwind CSS in morpheus-client and morpheus-admin Replace all SCSS module files with Tailwind inline classes, remove SASS dependencies and build configuration, and add typography color modifier classes to globals.css via @layer components. Fix visual regressions across auth forms, navbar, gallery, artwork cards, avatar fallbacks, and the about page to match original styling. Co-Authored-By: Claude Sonnet 4.6 --- .../components/atoms/Brand/Brand.module.scss | 10 - .../components/atoms/Brand/Brand.tsx | 3 +- .../atoms/Separator/Separator.module.scss | 19 - .../components/atoms/Separator/Separator.tsx | 9 +- .../CircleLoader/CircleLoader.module.scss | 37 - .../molecules/CircleLoader/CircleLoader.tsx | 7 +- .../molecules/Footer/Footer.module.scss | 54 -- .../components/molecules/Footer/Footer.tsx | 9 +- .../FullScreenLoader.module.scss | 11 - .../FullScreenLoader/FullScreenLoader.tsx | 3 +- .../organisms/AdminForm/AdminForm.module.scss | 22 - .../organisms/Auth/Auth.module.scss | 40 -- .../components/organisms/Auth/Auth.tsx | 7 +- .../Auth/LoginForm/LoginForm.module.scss | 28 - .../organisms/Auth/LoginForm/LoginForm.tsx | 5 +- .../Auth/ResetForm/ResetForm.module.scss | 0 .../organisms/Auth/ResetForm/ResetForm.tsx | 7 +- .../organisms/ModelForm/ModelForm.module.scss | 22 - .../organisms/Navbar/Navbar.module.scss | 133 ---- .../components/organisms/Navbar/Navbar.tsx | 9 +- .../MainContainer/MainLayout.module.scss | 17 - .../layout/MainContainer/MainLayout.tsx | 5 +- morpheus-admin/next.config.js | 4 - morpheus-admin/package.json | 1 - morpheus-admin/pages/404.tsx | 13 +- morpheus-admin/pages/_app.tsx | 2 +- morpheus-admin/pages/_error.tsx | 14 +- morpheus-admin/pages/admins.tsx | 3 +- morpheus-admin/pages/models.tsx | 3 +- morpheus-admin/styles/_buttons.scss | 76 -- morpheus-admin/styles/_colors.scss | 62 -- morpheus-admin/styles/_media.scss | 77 -- morpheus-admin/styles/_variables.scss | 10 - morpheus-admin/styles/fonts/_poppins.scss | 137 ---- morpheus-admin/styles/fonts/_shared.scss | 93 --- morpheus-admin/styles/globals.css | 525 ++++++-------- morpheus-admin/styles/globals.css.map | 1 - morpheus-admin/styles/globals.scss | 113 --- morpheus-admin/styles/pages/Error.module.scss | 44 -- morpheus-admin/styles/pages/Home.module.scss | 5 - morpheus-admin/tailwind.config.js | 1 + morpheus-client/App.scss | 130 ---- .../components/AppImage/AppImage.module.scss | 48 -- .../components/AppImage/AppImage.tsx | 6 +- .../ArtWorkList/ArtWorkList.module.scss | 32 - .../components/ArtWorkList/ArtWorkList.tsx | 7 +- .../ArtworkActions/ArtworkActions.module.scss | 36 - .../ArtworkActions/ArtworkActions.tsx | 7 +- .../ArtworkCard/ArtworkCard.module.scss | 43 -- .../components/ArtworkCard/ArtworkCard.tsx | 7 +- .../ArtworkCardDetails.module.scss | 53 -- .../ArtworkCardDetails/ArtworkCardDetails.tsx | 7 +- .../ArtworkCreator/ArtworkCreator.module.scss | 30 - .../ArtworkCreator/ArtworkCreator.tsx | 18 +- .../ArtworkDetails/ArtworkDetails.module.scss | 95 --- .../ArtworkDetails/ArtworkDetails.tsx | 15 +- .../ArtworkForm/ArtworkForm.module.scss | 33 - .../ArtworkCard/ArtworkForm/ArtworkForm.tsx | 7 +- .../ArtworkSelect/ArtworkSelect.module.scss | 21 - .../ArtworkSelect/ArtworkSelect.tsx | 3 +- .../components/Auth/Auth.module.scss | 17 - morpheus-client/components/Auth/Auth.tsx | 7 +- .../Auth/LoginForm/LoginForm.module.scss | 28 - .../components/Auth/LoginForm/LoginForm.tsx | 9 +- .../PrivateRoute/PrivateRoute.module.scss | 10 - .../Auth/PrivateRoute/PrivateRoute.tsx | 3 +- .../RegisterForm/RegisterForm.module.scss | 14 - .../Auth/RegisterForm/RegisterForm.tsx | 10 +- .../Auth/ResetForm/ResetForm.module.scss | 0 .../components/Auth/ResetForm/ResetForm.tsx | 7 +- .../Auth/Separator/Separator.module.scss | 19 - .../components/Auth/Separator/Separator.tsx | 9 +- .../Auth/ToggleAuth/ToggleAuth.module.scss | 39 - .../components/Auth/ToggleAuth/ToggleAuth.tsx | 8 +- .../CollectionArtWorks.module.scss | 30 - .../CollectionCard/CollectionCard.module.scss | 60 -- .../CollectionCard/CollectionCard.tsx | 27 +- .../CollectionForm/CollectionForm.module.scss | 62 -- .../CollectionForm/CollectionForm.tsx | 15 +- .../CollectionSelect.module.scss | 7 - .../Collections/Collections.module.scss | 35 - .../components/Collections/Collections.tsx | 9 +- .../ControlNetModelSelect.module.scss | 7 - .../CookiesConsent/CookiesConsent.module.scss | 68 -- .../CookiesConsent/CookiesConsent.tsx | 7 +- .../EditProfileForm.module.scss | 37 - .../EditProfileForm/EditProfileForm.tsx | 12 +- .../Excalidraw/Excalidraw.module.scss | 13 - .../components/Excalidraw/Excalidraw.tsx | 3 +- .../components/FAQ/FAQ.module.scss | 61 -- morpheus-client/components/FAQ/FAQ.tsx | 11 +- .../components/Footer/Footer.module.scss | 53 -- morpheus-client/components/Footer/Footer.tsx | 9 +- .../GalleryActions/GalleryActions.module.scss | 5 - .../GalleryActions/GalleryActions.tsx | 3 +- .../HelpPrompt/HelpPrompt.module.scss | 27 - .../components/HelpPrompt/HelpPrompt.tsx | 16 +- .../ImageGallery/ImageGallery.module.scss | 50 -- .../components/ImageGallery/ImageGallery.tsx | 13 +- .../ImagePrompt/ImagePrompt.module.scss | 37 - .../components/ImagePrompt/ImagePrompt.tsx | 5 +- .../ImagineBase/ImagineBase.module.scss | 86 --- .../components/ImagineBase/ImagineBase.tsx | 11 +- .../ImagineImageInput.module.scss | 194 ----- .../ImagineImageInput/ImagineImageInput.tsx | 34 +- .../ImagineInput/ImagineInput.module.scss | 60 -- .../components/ImagineInput/ImagineInput.tsx | 10 +- .../ImagineMenu/ImagineMenu.module.scss | 94 --- .../components/ImagineMenu/ImagineMenu.tsx | 11 +- .../ImagineSettings.module.scss | 111 --- .../ImagineSettings/ImagineSettings.tsx | 45 +- .../components/Inputs/Input.module.scss | 92 --- .../InputCheckbox/InputCheckbox.module.scss | 31 - .../Inputs/InputCheckbox/InputCheckbox.tsx | 9 +- .../Inputs/InputEmail/InputEmail.tsx | 36 +- .../Inputs/InputFile/InputFile.module.scss | 41 -- .../components/Inputs/InputFile/InputFile.tsx | 11 +- .../Inputs/InputNumber/InputNumber.tsx | 8 +- .../Inputs/InputPassword/InputPassword.tsx | 12 +- .../InputSearch/InputSearch.module.scss | 20 - .../Inputs/InputSearch/InputSearch.tsx | 5 +- .../InputSelect/InputSelect.module.scss | 70 -- .../InputSlider/InputSlider.module.scss | 77 -- .../Inputs/InputSlider/InputSlider.tsx | 9 +- .../components/Inputs/InputText/InputText.tsx | 15 +- .../Inputs/InputTextArea/InputTextArea.tsx | 13 +- .../Inputs/InputTextArea/TextArea.module.scss | 44 -- .../FullScreenLoader/Loader.module.scss | 11 - .../Loaders/FullScreenLoader/Loader.tsx | 3 +- .../Loaders/LoaderCircle/Loader.module.scss | 37 - .../Loaders/LoaderCircle/Loader.tsx | 7 +- .../Loaders/LoaderImages/Loader.module.scss | 57 -- .../Loaders/LoaderImages/Loader.tsx | 5 +- .../MagicPrompt/MagicPrompt.module.scss | 44 -- .../components/MagicPrompt/MagicPrompt.tsx | 5 +- .../MaskPaintingCanvas.module.scss | 39 - .../MaskPaintingCanvas/MaskPaintingCanvas.tsx | 11 +- .../components/Modal/Modal.module.scss | 59 -- morpheus-client/components/Modal/Modal.tsx | 11 +- .../ModelSelect/ModelSelect.module.scss | 7 - .../MorpheusStats/MorpheusStats.module.scss | 71 -- .../MorpheusStats/MorpheusStats.tsx | 16 +- .../components/Navbar/Navbar.module.scss | 133 ---- morpheus-client/components/Navbar/Navbar.tsx | 17 +- .../OpenSource/OpenSource.module.scss | 36 - .../components/OpenSource/OpenSource.tsx | 10 +- .../RoundedIcon/RoundedIcon.module.scss | 43 -- .../components/RoundedIcon/RoundedIcon.tsx | 11 +- .../SamplerSelect/SamplerSelect.module.scss | 7 - .../SearchForm/SearchForm.module.scss | 16 - .../components/SearchForm/SearchForm.tsx | 5 +- .../ShareButton/ShareButton.module.scss | 39 - .../components/ShareButton/ShareOptions.tsx | 5 +- .../ShareButton/ShareOptionsModal.tsx | 3 +- .../components/Slider/Slider.module.scss | 23 - morpheus-client/components/Slider/Slider.tsx | 5 +- .../components/Tooltip/AppTooltip.module.scss | 90 --- .../Typography/Brand/Brand.module.scss | 10 - .../components/Typography/Brand/Brand.tsx | 3 +- .../UnderConstruction.module.scss | 38 - .../UnderConstruction/UnderConstruction.tsx | 7 +- .../components/UserCard/UserCard.module.scss | 148 ---- .../components/UserCard/UserCard.tsx | 41 +- .../UserProfile/UserProfile.module.scss | 65 -- .../components/UserProfile/UserProfile.tsx | 17 +- .../atoms/accordion/Accordion.module.scss | 47 -- .../components/atoms/accordion/Accordion.tsx | 15 +- .../ButtonPrimary/ButtonPrimary.module.scss | 37 - .../buttons/ButtonPrimary/ButtonPrimary.tsx | 7 +- .../ButtonSecondary.module.scss | 34 - .../ButtonSecondary/ButtonSecondary.tsx | 9 +- .../SendToImagine/SendToImagine.module.scss | 19 - .../SendToImagine/SendToImagine.tsx | 3 +- .../ImagineLayout/ImagineLayout.module.scss | 19 - .../layout/ImagineLayout/ImagineLayout.tsx | 5 +- .../layout/MainLayout/MainLayout.module.scss | 21 - .../layout/MainLayout/MainLayout.tsx | 5 +- morpheus-client/package.json | 4 +- morpheus-client/pages/404.tsx | 13 +- morpheus-client/pages/_app.tsx | 3 +- morpheus-client/pages/_error.tsx | 13 +- morpheus-client/pages/about.tsx | 23 +- .../pages/gallery/[collectionId].tsx | 25 +- morpheus-client/pages/gallery/index.tsx | 3 +- morpheus-client/pages/imagine/help.tsx | 3 +- morpheus-client/pages/imagine/training.tsx | 3 +- morpheus-client/pages/index.tsx | 11 +- morpheus-client/styles/_buttons.scss | 76 -- morpheus-client/styles/_colors.scss | 65 -- morpheus-client/styles/_media.scss | 77 -- morpheus-client/styles/_typography.scss | 2 - morpheus-client/styles/_variables.scss | 4 - morpheus-client/styles/fonts/_lato.scss | 111 --- morpheus-client/styles/fonts/_poppins.scss | 137 ---- morpheus-client/styles/fonts/_shared.scss | 93 --- morpheus-client/styles/globals.css | 666 +++++++++++++++++- .../styles/pages/About.module.scss | 141 ---- .../pages/CollectionDetails.module.scss | 113 --- .../styles/pages/Error.module.scss | 45 -- .../styles/pages/Gallery.module.scss | 34 - morpheus-client/styles/pages/Help.module.scss | 18 - morpheus-client/styles/pages/Home.module.scss | 74 -- .../styles/pages/Paint.module.scss | 15 - .../styles/pages/Profile.module.scss | 61 -- .../styles/pages/Training.module.scss | 14 - morpheus-client/tailwind.config.js | 7 +- morpheus-client/yarn.lock | 140 +++- morpheus-data/alembic.ini | 105 --- .../repository/artwork_repository.py | 81 --- .../celery/utils/decorators.py | 103 --- .../docker-compose-celery.yaml | 287 -------- .../morpheus/templates/deployment-redis.yaml | 31 - .../deployment-worker-cloudwatch-monitor.yaml | 97 --- .../templates/deployment-worker-monitor.yaml | 99 --- .../deployment-workers-diffusion.yaml | 148 ---- .../templates/deployment-workers-prompt.yaml | 147 ---- .../legacy/ray-workers.yaml | 84 --- 217 files changed, 1377 insertions(+), 7425 deletions(-) delete mode 100644 morpheus-admin/components/atoms/Brand/Brand.module.scss delete mode 100644 morpheus-admin/components/atoms/Separator/Separator.module.scss delete mode 100644 morpheus-admin/components/molecules/CircleLoader/CircleLoader.module.scss delete mode 100644 morpheus-admin/components/molecules/Footer/Footer.module.scss delete mode 100644 morpheus-admin/components/molecules/FullScreenLoader/FullScreenLoader.module.scss delete mode 100644 morpheus-admin/components/organisms/AdminForm/AdminForm.module.scss delete mode 100644 morpheus-admin/components/organisms/Auth/Auth.module.scss delete mode 100644 morpheus-admin/components/organisms/Auth/LoginForm/LoginForm.module.scss delete mode 100644 morpheus-admin/components/organisms/Auth/ResetForm/ResetForm.module.scss delete mode 100644 morpheus-admin/components/organisms/ModelForm/ModelForm.module.scss delete mode 100644 morpheus-admin/components/organisms/Navbar/Navbar.module.scss delete mode 100644 morpheus-admin/layout/MainContainer/MainLayout.module.scss delete mode 100644 morpheus-admin/styles/_buttons.scss delete mode 100644 morpheus-admin/styles/_colors.scss delete mode 100644 morpheus-admin/styles/_media.scss delete mode 100644 morpheus-admin/styles/_variables.scss delete mode 100644 morpheus-admin/styles/fonts/_poppins.scss delete mode 100644 morpheus-admin/styles/fonts/_shared.scss delete mode 100644 morpheus-admin/styles/globals.css.map delete mode 100644 morpheus-admin/styles/globals.scss delete mode 100644 morpheus-admin/styles/pages/Error.module.scss delete mode 100644 morpheus-admin/styles/pages/Home.module.scss delete mode 100644 morpheus-client/App.scss delete mode 100644 morpheus-client/components/AppImage/AppImage.module.scss delete mode 100644 morpheus-client/components/ArtWorkList/ArtWorkList.module.scss delete mode 100644 morpheus-client/components/ArtworkActions/ArtworkActions.module.scss delete mode 100644 morpheus-client/components/ArtworkCard/ArtworkCard.module.scss delete mode 100644 morpheus-client/components/ArtworkCard/ArtworkCardDetails/ArtworkCardDetails.module.scss delete mode 100644 morpheus-client/components/ArtworkCard/ArtworkCreator/ArtworkCreator.module.scss delete mode 100644 morpheus-client/components/ArtworkCard/ArtworkDetails/ArtworkDetails.module.scss delete mode 100644 morpheus-client/components/ArtworkCard/ArtworkForm/ArtworkForm.module.scss delete mode 100644 morpheus-client/components/ArtworkCard/ArtworkSelect/ArtworkSelect.module.scss delete mode 100644 morpheus-client/components/Auth/Auth.module.scss delete mode 100644 morpheus-client/components/Auth/LoginForm/LoginForm.module.scss delete mode 100644 morpheus-client/components/Auth/PrivateRoute/PrivateRoute.module.scss delete mode 100644 morpheus-client/components/Auth/RegisterForm/RegisterForm.module.scss delete mode 100644 morpheus-client/components/Auth/ResetForm/ResetForm.module.scss delete mode 100644 morpheus-client/components/Auth/Separator/Separator.module.scss delete mode 100644 morpheus-client/components/Auth/ToggleAuth/ToggleAuth.module.scss delete mode 100644 morpheus-client/components/CollectionArtWorks/CollectionArtWorks.module.scss delete mode 100644 morpheus-client/components/CollectionCard/CollectionCard.module.scss delete mode 100644 morpheus-client/components/CollectionForm/CollectionForm.module.scss delete mode 100644 morpheus-client/components/CollectionSelect/CollectionSelect.module.scss delete mode 100644 morpheus-client/components/Collections/Collections.module.scss delete mode 100644 morpheus-client/components/ControlNetModelSelect/ControlNetModelSelect.module.scss delete mode 100644 morpheus-client/components/CookiesConsent/CookiesConsent.module.scss delete mode 100644 morpheus-client/components/EditProfileForm/EditProfileForm.module.scss delete mode 100644 morpheus-client/components/Excalidraw/Excalidraw.module.scss delete mode 100644 morpheus-client/components/FAQ/FAQ.module.scss delete mode 100644 morpheus-client/components/Footer/Footer.module.scss delete mode 100644 morpheus-client/components/GalleryActions/GalleryActions.module.scss delete mode 100644 morpheus-client/components/HelpPrompt/HelpPrompt.module.scss delete mode 100644 morpheus-client/components/ImageGallery/ImageGallery.module.scss delete mode 100644 morpheus-client/components/ImagePrompt/ImagePrompt.module.scss delete mode 100644 morpheus-client/components/ImagineBase/ImagineBase.module.scss delete mode 100644 morpheus-client/components/ImagineImageInput/ImagineImageInput.module.scss delete mode 100644 morpheus-client/components/ImagineInput/ImagineInput.module.scss delete mode 100644 morpheus-client/components/ImagineMenu/ImagineMenu.module.scss delete mode 100644 morpheus-client/components/ImagineSettings/ImagineSettings.module.scss delete mode 100644 morpheus-client/components/Inputs/Input.module.scss delete mode 100644 morpheus-client/components/Inputs/InputCheckbox/InputCheckbox.module.scss delete mode 100644 morpheus-client/components/Inputs/InputFile/InputFile.module.scss delete mode 100644 morpheus-client/components/Inputs/InputSearch/InputSearch.module.scss delete mode 100644 morpheus-client/components/Inputs/InputSelect/InputSelect.module.scss delete mode 100644 morpheus-client/components/Inputs/InputSlider/InputSlider.module.scss delete mode 100644 morpheus-client/components/Inputs/InputTextArea/TextArea.module.scss delete mode 100644 morpheus-client/components/Loaders/FullScreenLoader/Loader.module.scss delete mode 100644 morpheus-client/components/Loaders/LoaderCircle/Loader.module.scss delete mode 100644 morpheus-client/components/Loaders/LoaderImages/Loader.module.scss delete mode 100644 morpheus-client/components/MagicPrompt/MagicPrompt.module.scss delete mode 100644 morpheus-client/components/MaskPaintingCanvas/MaskPaintingCanvas.module.scss delete mode 100644 morpheus-client/components/Modal/Modal.module.scss delete mode 100644 morpheus-client/components/ModelSelect/ModelSelect.module.scss delete mode 100644 morpheus-client/components/MorpheusStats/MorpheusStats.module.scss delete mode 100644 morpheus-client/components/Navbar/Navbar.module.scss delete mode 100644 morpheus-client/components/OpenSource/OpenSource.module.scss delete mode 100644 morpheus-client/components/RoundedIcon/RoundedIcon.module.scss delete mode 100644 morpheus-client/components/SamplerSelect/SamplerSelect.module.scss delete mode 100644 morpheus-client/components/SearchForm/SearchForm.module.scss delete mode 100644 morpheus-client/components/ShareButton/ShareButton.module.scss delete mode 100644 morpheus-client/components/Slider/Slider.module.scss delete mode 100644 morpheus-client/components/Tooltip/AppTooltip.module.scss delete mode 100644 morpheus-client/components/Typography/Brand/Brand.module.scss delete mode 100644 morpheus-client/components/UnderConstruction/UnderConstruction.module.scss delete mode 100644 morpheus-client/components/UserCard/UserCard.module.scss delete mode 100644 morpheus-client/components/UserProfile/UserProfile.module.scss delete mode 100644 morpheus-client/components/atoms/accordion/Accordion.module.scss delete mode 100644 morpheus-client/components/buttons/ButtonPrimary/ButtonPrimary.module.scss delete mode 100644 morpheus-client/components/buttons/ButtonSecondary/ButtonSecondary.module.scss delete mode 100644 morpheus-client/excalidraw/components/SendToImagine/SendToImagine.module.scss delete mode 100644 morpheus-client/layout/ImagineLayout/ImagineLayout.module.scss delete mode 100644 morpheus-client/layout/MainLayout/MainLayout.module.scss delete mode 100644 morpheus-client/styles/_buttons.scss delete mode 100644 morpheus-client/styles/_colors.scss delete mode 100644 morpheus-client/styles/_media.scss delete mode 100644 morpheus-client/styles/_typography.scss delete mode 100644 morpheus-client/styles/_variables.scss delete mode 100644 morpheus-client/styles/fonts/_lato.scss delete mode 100644 morpheus-client/styles/fonts/_poppins.scss delete mode 100644 morpheus-client/styles/fonts/_shared.scss delete mode 100644 morpheus-client/styles/pages/About.module.scss delete mode 100644 morpheus-client/styles/pages/CollectionDetails.module.scss delete mode 100644 morpheus-client/styles/pages/Error.module.scss delete mode 100644 morpheus-client/styles/pages/Gallery.module.scss delete mode 100644 morpheus-client/styles/pages/Help.module.scss delete mode 100644 morpheus-client/styles/pages/Home.module.scss delete mode 100644 morpheus-client/styles/pages/Paint.module.scss delete mode 100644 morpheus-client/styles/pages/Profile.module.scss delete mode 100644 morpheus-client/styles/pages/Training.module.scss delete mode 100644 morpheus-data/alembic.ini delete mode 100644 morpheus-data/morpheus_data/repository/artwork_repository.py delete mode 100644 morpheus-worker-legacy/celery/utils/decorators.py delete mode 100644 morpheus-worker-legacy/docker-compose-celery.yaml delete mode 100644 morpheus-worker-legacy/helm/charts/morpheus/templates/deployment-redis.yaml delete mode 100644 morpheus-worker-legacy/helm/charts/morpheus/templates/deployment-worker-cloudwatch-monitor.yaml delete mode 100644 morpheus-worker-legacy/helm/charts/morpheus/templates/deployment-worker-monitor.yaml delete mode 100644 morpheus-worker-legacy/helm/charts/morpheus/templates/deployment-workers-diffusion.yaml delete mode 100644 morpheus-worker-legacy/helm/charts/morpheus/templates/deployment-workers-prompt.yaml delete mode 100644 morpheus-worker/helm/charts/morpheus-worker-ray/legacy/ray-workers.yaml diff --git a/morpheus-admin/components/atoms/Brand/Brand.module.scss b/morpheus-admin/components/atoms/Brand/Brand.module.scss deleted file mode 100644 index 3dabd66..0000000 --- a/morpheus-admin/components/atoms/Brand/Brand.module.scss +++ /dev/null @@ -1,10 +0,0 @@ -.morpheusTitle { - font-size: 32px; - line-height: 48px; - text-transform: uppercase; - background: linear-gradient(107.97deg, #E90064 -14.72%, #FF5F9E 62.24%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - text-fill-color: transparent; -} \ No newline at end of file diff --git a/morpheus-admin/components/atoms/Brand/Brand.tsx b/morpheus-admin/components/atoms/Brand/Brand.tsx index 6580879..fdc59d9 100644 --- a/morpheus-admin/components/atoms/Brand/Brand.tsx +++ b/morpheus-admin/components/atoms/Brand/Brand.tsx @@ -1,5 +1,4 @@ import React, { CSSProperties } from "react"; -import styles from "./Brand.module.scss"; interface BrandProps { onClick?: () => void; @@ -10,7 +9,7 @@ const Brand = (props: BrandProps) => { return (

Morpheus Admin diff --git a/morpheus-admin/components/atoms/Separator/Separator.module.scss b/morpheus-admin/components/atoms/Separator/Separator.module.scss deleted file mode 100644 index 7e0b464..0000000 --- a/morpheus-admin/components/atoms/Separator/Separator.module.scss +++ /dev/null @@ -1,19 +0,0 @@ -@use "styles/colors"; - -.separator { - width: 100%; - height: auto; - display: flex; - align-items: center; - text-align: center; - margin: 32px 0; - - .separatorLine { - flex: 1; - border: 1px solid colors.$background-border; - } - - .separatorText { - margin: 0 24px; - } -} \ No newline at end of file diff --git a/morpheus-admin/components/atoms/Separator/Separator.tsx b/morpheus-admin/components/atoms/Separator/Separator.tsx index 5546ef3..90d927c 100644 --- a/morpheus-admin/components/atoms/Separator/Separator.tsx +++ b/morpheus-admin/components/atoms/Separator/Separator.tsx @@ -1,12 +1,11 @@ import React from "react"; -import styles from "./Separator.module.scss"; export const Separator = () => { return ( -
-
- OR -
+
+
+ OR +
); }; diff --git a/morpheus-admin/components/molecules/CircleLoader/CircleLoader.module.scss b/morpheus-admin/components/molecules/CircleLoader/CircleLoader.module.scss deleted file mode 100644 index 92347c4..0000000 --- a/morpheus-admin/components/molecules/CircleLoader/CircleLoader.module.scss +++ /dev/null @@ -1,37 +0,0 @@ -.loaderContainer { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - - &.primary { - top: 0; - left: 0; - right: 0; - bottom: 0; - position: absolute; - width: 100vw; - height: 100vh; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - } - - .loader { - animation: rotate 1.3s infinite linear; - } - - .loaderText { - margin: 8px; - } -} - -@keyframes rotate { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} \ No newline at end of file diff --git a/morpheus-admin/components/molecules/CircleLoader/CircleLoader.tsx b/morpheus-admin/components/molecules/CircleLoader/CircleLoader.tsx index b8bb7c3..0661261 100644 --- a/morpheus-admin/components/molecules/CircleLoader/CircleLoader.tsx +++ b/morpheus-admin/components/molecules/CircleLoader/CircleLoader.tsx @@ -1,5 +1,4 @@ import { CSSProperties } from "react"; -import styles from "./CircleLoader.module.scss"; const CircleLoader = (props: { primary?: boolean; @@ -13,11 +12,11 @@ const CircleLoader = (props: { }) => { return (
{props.message && ( -

+

{props.message}

)} diff --git a/morpheus-admin/components/molecules/Footer/Footer.module.scss b/morpheus-admin/components/molecules/Footer/Footer.module.scss deleted file mode 100644 index 7e457ca..0000000 --- a/morpheus-admin/components/molecules/Footer/Footer.module.scss +++ /dev/null @@ -1,54 +0,0 @@ -@use "styles/colors"; -@use "styles/media"; -@use "styles/variables"; - -.footerContainer { - width: 100%; - max-height: 80px; - padding: 24px 72px; - display: flex; - align-items: center; - background: colors.$background-primary !important; - - @include media.mobile { - height: auto; - flex-direction: column; - text-align: center; - } - - .leftContent { - flex: 2; - display: flex; - justify-content: flex-start; - gap: 24px; - - @include media.mobile { - margin-bottom: 16px; - order: 1; - } - } - - .middleContent { - flex: 4; - display: flex; - justify-content: center; - gap: 24px; - - @include media.mobile { - margin-bottom: 24px; - order: 3; - } - } - - .rightContent { - flex: 2; - display: flex; - justify-content: flex-end; - gap: 24px; - - @include media.mobile { - margin-bottom: 24px; - order: 2; - } - } -} diff --git a/morpheus-admin/components/molecules/Footer/Footer.tsx b/morpheus-admin/components/molecules/Footer/Footer.tsx index ca54e73..7129523 100644 --- a/morpheus-admin/components/molecules/Footer/Footer.tsx +++ b/morpheus-admin/components/molecules/Footer/Footer.tsx @@ -4,22 +4,21 @@ import Brand from "@/components/atoms/Brand/Brand"; import { GithubIcon } from "@/components/atoms/icons/github"; import { TwitterIcon } from "@/components/atoms/icons/twitter"; import { LinkedinIcon } from "@/components/atoms/icons/linkedin"; -import styles from "./Footer.module.scss"; const Footer = () => { return ( -