Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,10 @@ All notable changes to this repository will be documented in this file.
- Added build and deployment script


## [1.1.0] Fri, Dec 05, 2025

- Contact Us page Added
- 404 error handling
- NavBar CSS fixed

[Unreleased]
3 changes: 3 additions & 0 deletions backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
submit,
uploads,
validate_image,
contact
)
from tools.mcpserver import sse_app
from utils.emoji_logger import get_logger



class MyApp(FastAPI):
mongo_client: MongoClient
database: Database
Expand Down Expand Up @@ -122,6 +124,7 @@ async def lifespan(app: MyApp):
app.include_router(media.router, prefix=API_PREFIX)
app.include_router(chat.router, prefix=API_PREFIX)
app.include_router(uploads.router, prefix=API_PREFIX)
app.include_router(contact.router, prefix=API_PREFIX)


@app.get("/__routes")
Expand Down
32 changes: 32 additions & 0 deletions backend/routes/contact.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# routes/contact.py
from fastapi import APIRouter, HTTPException, Request
from pydantic import BaseModel, EmailStr
from datetime import datetime

router = APIRouter()


class ContactForm(BaseModel):
name: str
email: EmailStr
message: str


@router.post("/contact")
async def save_contact(request: Request, form: ContactForm):
db = request.app.database # ← SAME as all other route files

collection = db["contact_messages"]

data = {
"name": form.name,
"email": form.email,
"message": form.message,
"created_at": datetime.utcnow(),
}

result = collection.insert_one(data)
if not result.inserted_id:
raise HTTPException(status_code=500, detail="Failed to save message")

return {"success": True, "id": str(result.inserted_id)}
11 changes: 9 additions & 2 deletions backend/routes/uploads.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import uuid
from pathlib import Path

from fastapi import Request


from fastapi import APIRouter, File, Form, HTTPException, UploadFile

from constants import AUDIO_DIR, IMAGE_DIR
Expand All @@ -14,12 +17,16 @@
AUDIO_DIR.mkdir(parents=True, exist_ok=True)



@router.post("/uploads/tmp_media")
async def upload_tmp_media(
request: Request,
image: UploadFile = File(None),
audio: UploadFile = File(None),
filename: str | None = Form(None), # <-- 👈 accept provided name
):
base_url = str(request.base_url).rstrip("/")

if not image and not audio:
raise HTTPException(
status_code=400,
Expand Down Expand Up @@ -53,7 +60,7 @@ async def upload_tmp_media(
try:
with img_path.open("wb") as out:
shutil.copyfileobj(image.file, out)
saved_image_url = f"http://127.0.0.1:8000/assets/images/{img_name}"
saved_image_url = f"{base_url}/assets/images/{img_name}"
saved_image_path = str(img_path.resolve())
saved_image_name = img_name
except Exception as e:
Expand All @@ -67,7 +74,7 @@ async def upload_tmp_media(
try:
with aud_path.open("wb") as out:
shutil.copyfileobj(audio.file, out)
saved_audio_url = f"http://127.0.0.1:8000/assets/audios/{aud_name}"
saved_audio_url = f"{base_url}/assets/audios/{aud_name}"
saved_audio_name = aud_name
saved_audio_path = str(aud_path.resolve())
except Exception as e:
Expand Down
20 changes: 18 additions & 2 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tz-fabric",
"version": "1.0.2",
"version": "1.1.0",
"type": "module",
"homepage": "https://threadzip.com",
"description": "A AI enabled fabric analysis, chatbot integration with image search",
Expand Down Expand Up @@ -59,6 +59,7 @@
"devDependencies": {
"@biomejs/biome": "^2.0.2",
"@eslint/js": "^9.30.1",
"@types/node": "^24.10.1",
"@types/react": "^19.1.9",
"@types/react-dom": "^19.1.7",
"@vitejs/plugin-react": "^4.6.0",
Expand Down
53 changes: 22 additions & 31 deletions frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
height: 100%;
margin: 0;
font-family: Inter, "Segoe UI", Roboto, system-ui, -apple-system, Arial, sans-serif;
color: var(--text-color);
}

.app-wrapper {
Expand All @@ -37,26 +36,31 @@

.site-header {
width: 100%;
display: flex;
display: grid;
align-items: center;
justify-content: space-between;
padding: 4px 20px;
background: rgba(255, 255, 255, 0.9);
box-shadow: 0 6px 24px rgba(66, 66, 67, 0.767);
grid-template-columns: 20% 1fr 20%;
grid-template-areas: 'left center right';
}





.header-left {
grid-area: left;
display: flex;
align-items: center;
gap: 12px;
}

.header-center {
grid-area: center;
text-transform: capitalize;
justify-self: center;
}


.header-right {
grid-area: right;
}

.logo-mark {
width: 44px;
Expand All @@ -74,26 +78,6 @@
letter-spacing: 0.1px;
}

.site-nav {
display: flex;
gap: 22px;
align-items: center;
}

.site-nav a {
color: var(--text-color);
text-decoration: none;
font-size: 14px;
font-weight: 500;
padding: 6px 8px;
border-radius: 8px;
transition: background .15s ease, transform .08s ease;
}

.site-nav a:hover {
background: rgba(47, 107, 255, 0.08);
transform: translateY(-1px);
}

.main-content {
width: 100%;
Expand All @@ -106,13 +90,20 @@
padding: 12px 14px;
flex-direction: row;
align-items: center;
display: flex;
}

.site-nav {
gap: 12px;
}

.brand-name {
font-size: 15px;
}
}

.container {
height: 80vh;
}

.center {
display: grid;
place-content: center;
}
54 changes: 6 additions & 48 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from "react";
import { NavLink } from "react-router-dom";
import "./App.css";
import "./styles/navbar.css";
import { Routing } from "./Routing";
import Footer from "./components/Footer";
import { NavBar } from './components/NavBar';
import { FaRegMoon } from 'react-icons/fa';

const App: React.FC = () => {
return (
Expand All @@ -24,53 +24,11 @@ const App: React.FC = () => {
<div className="brand-name">FabricAI</div>
</div>
</div>
<div className="mobile-nav-wrapper">
<input type="checkbox" id="nav-toggle" className="nav-toggle" />

<label htmlFor="nav-toggle" className="hamburger">
<span></span>
<span></span>
<span></span>
</label>

<nav className="header-nav">
<ul>
<li>
<NavLink to="/" end className={ ({ isActive }) => isActive ? "active" : "" }>
Home
</NavLink>
</li>
<li>
<NavLink to="/analysis" end className={ ({ isActive }) => isActive ? "active" : "" }>
Analysis
</NavLink>
</li>
<li>
<NavLink to="/upload" end className={ ({ isActive }) => isActive ? "active" : "" }>
Upload
</NavLink>
</li>
<li>
<NavLink to="/view" end className={ ({ isActive }) => isActive ? "active" : "" }>
List
</NavLink>
</li>
<li>
<NavLink to="/search" end className={ ({ isActive }) => isActive ? "active" : "" }>
Search
</NavLink>
</li>
<li>
<NavLink to="/chat" end className={ ({ isActive }) => isActive ? "active" : "" }>
Chat
</NavLink>
</li>
</ul>
</nav>
<div className="header-center">
<NavBar/>
</div>

<div className="action">
{/* <div id="theme"> <FaRegMoon /></div> */}
<div className="header-right action">
<div id="theme"> <FaRegMoon /></div>
</div>
</header>

Expand Down
5 changes: 4 additions & 1 deletion frontend/src/Routing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import Home from "./pages/Home";
import ImageDescription from "./pages/ImageDescriptor";
import Chat from "./pages/FabricChat";
import ComingSoon from "./pages/ComingSoon";
import { NotFound } from './components/NotFound';
import {ContactUs} from './pages/Contact';

export const Routing = () => {
return (
Expand All @@ -20,8 +22,9 @@ export const Routing = () => {
<Route path="/pricing" element={ <ComingSoon /> } />
<Route path="/api" element={ <ComingSoon /> } />
<Route path="/docs" element={ <ComingSoon /> } />
<Route path="/contact" element={ <ComingSoon /> } />
<Route path="/help" element={ <ComingSoon /> } />
<Route path="/contact" element={ <ContactUs /> } />
<Route path="*" element={ <NotFound /> } />
</Routes>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
background: #0c1220;
/* deep navy like screenshot */
color: #d2d8e3;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.06);
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.25);
margin-top: 24px;
}

.footer__inner {
Expand Down
File renamed without changes.
Loading