diff --git a/.env.example b/.env.example index c8385ee..54cb6e2 100644 --- a/.env.example +++ b/.env.example @@ -2,13 +2,13 @@ PUID=1000 PGID=1000 # Used by docker-compose.deploy.yml (pre-built images from GHCR). Defaults to :latest; pin a -# specific build if you want, e.g. ghcr.io/tautvydasderzinskas/printstash-backend:sha-a8fef7d -BACKEND_IMAGE=ghcr.io/tautvydasderzinskas/printstash-backend:latest -FRONTEND_IMAGE=ghcr.io/tautvydasderzinskas/printstash-frontend:latest +# specific build if you want, e.g. ghcr.io/tautvydasderzinskas/thingport-backend:sha-a8fef7d +BACKEND_IMAGE=ghcr.io/tautvydasderzinskas/thingport-backend:latest +FRONTEND_IMAGE=ghcr.io/tautvydasderzinskas/thingport-frontend:latest -POSTGRES_USER=printstash -POSTGRES_PASSWORD=printstash -POSTGRES_DB=printstash +POSTGRES_USER=thingport +POSTGRES_PASSWORD=thingport +POSTGRES_DB=thingport # The only port you publish -- nginx (the frontend container) serves the UI and reverse-proxies # /api/* to the backend container internally, so the backend itself is never exposed to the host. WEB_PORT=80 diff --git a/.github/workflows/backend-image.yml b/.github/workflows/backend-image.yml index 41ae2ba..660d254 100644 --- a/.github/workflows/backend-image.yml +++ b/.github/workflows/backend-image.yml @@ -30,7 +30,7 @@ jobs: uses: ./.github/workflows/build-image.yml with: project_dir: backend - image_name: ghcr.io/${{ github.repository_owner }}/printstash-backend + image_name: ghcr.io/${{ github.repository_owner }}/thingport-backend context: ./backend dockerfile: backend/Dockerfile cache_scope: backend diff --git a/.github/workflows/bridge-release.yml b/.github/workflows/bridge-release.yml index fe79547..1502740 100644 --- a/.github/workflows/bridge-release.yml +++ b/.github/workflows/bridge-release.yml @@ -38,11 +38,11 @@ jobs: CGO_ENABLED: 0 GOOS: windows GOARCH: amd64 - run: go build -o dist/print-stash-bridge-windows-amd64.exe ./cmd/print-stash-bridge + run: go build -o dist/thingport-bridge-windows-amd64.exe ./cmd/thingport-bridge - uses: actions/upload-artifact@v4 with: name: bridge-windows-amd64 - path: bridge/dist/print-stash-bridge-windows-amd64.exe + path: bridge/dist/thingport-bridge-windows-amd64.exe if-no-files-found: error build-linux: @@ -61,15 +61,15 @@ jobs: CGO_ENABLED: 0 GOOS: linux GOARCH: amd64 - run: go build -o dist/print-stash-bridge-linux-amd64 ./cmd/print-stash-bridge + run: go build -o dist/thingport-bridge-linux-amd64 ./cmd/thingport-bridge - uses: actions/upload-artifact@v4 with: name: bridge-linux-amd64 - path: bridge/dist/print-stash-bridge-linux-amd64 + path: bridge/dist/thingport-bridge-linux-amd64 if-no-files-found: error build-macos: - # Custom-URL-scheme handling on macOS goes through Cocoa (see cmd/print-stash-bridge/ + # Custom-URL-scheme handling on macOS goes through Cocoa (see cmd/thingport-bridge/ # urlhandler_darwin.m), so this binary needs cgo + the Xcode toolchain and can only be # built on an actual Mac runner -- unlike Windows/Linux, it can't be cross-compiled. runs-on: macos-latest @@ -86,18 +86,18 @@ jobs: env: CGO_ENABLED: 1 run: | - GOARCH=arm64 go build -o dist/print-stash-bridge-darwin-arm64 ./cmd/print-stash-bridge - GOARCH=amd64 go build -o dist/print-stash-bridge-darwin-amd64 ./cmd/print-stash-bridge + GOARCH=arm64 go build -o dist/thingport-bridge-darwin-arm64 ./cmd/thingport-bridge + GOARCH=amd64 go build -o dist/thingport-bridge-darwin-amd64 ./cmd/thingport-bridge - name: Combine into a universal binary working-directory: bridge - run: lipo -create -output dist/print-stash-bridge-macos dist/print-stash-bridge-darwin-arm64 dist/print-stash-bridge-darwin-amd64 + run: lipo -create -output dist/thingport-bridge-macos dist/thingport-bridge-darwin-arm64 dist/thingport-bridge-darwin-amd64 - name: Re-sign universal binary working-directory: bridge - run: codesign --force -s - dist/print-stash-bridge-macos + run: codesign --force -s - dist/thingport-bridge-macos - uses: actions/upload-artifact@v4 with: name: bridge-macos - path: bridge/dist/print-stash-bridge-macos + path: bridge/dist/thingport-bridge-macos if-no-files-found: error release: @@ -114,10 +114,10 @@ jobs: - name: Flatten downloaded artifacts run: | mkdir -p release - mv dist/bridge-windows-amd64/print-stash-bridge-windows-amd64.exe release/ - mv dist/bridge-linux-amd64/print-stash-bridge-linux-amd64 release/ - mv dist/bridge-macos/print-stash-bridge-macos release/ - chmod +x release/print-stash-bridge-linux-amd64 release/print-stash-bridge-macos + mv dist/bridge-windows-amd64/thingport-bridge-windows-amd64.exe release/ + mv dist/bridge-linux-amd64/thingport-bridge-linux-amd64 release/ + mv dist/bridge-macos/thingport-bridge-macos release/ + chmod +x release/thingport-bridge-linux-amd64 release/thingport-bridge-macos - name: Compute release tag id: tag run: echo "tag=bridge-$(date +%Y%m%d)-${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" @@ -125,16 +125,16 @@ jobs: uses: softprops/action-gh-release@v2 with: tag_name: ${{ steps.tag.outputs.tag }} - name: PrintStash Bridge ${{ steps.tag.outputs.tag }} + name: Thingport Bridge ${{ steps.tag.outputs.tag }} body: | - Automated build of the PrintStash slicer bridge (see `bridge/README.md`) from + Automated build of the Thingport slicer bridge (see `bridge/README.md`) from ${{ github.sha }}. - - **Windows**: `print-stash-bridge-windows-amd64.exe` — run it once (double-click is fine) to install. - - **Linux**: `print-stash-bridge-linux-amd64` — `chmod +x`, then run it once to install. - - **macOS**: `print-stash-bridge-macos` (universal) — `chmod +x`, remove the quarantine flag, then run with `--install`. See the README for the exact commands. + - **Windows**: `thingport-bridge-windows-amd64.exe` — run it once (double-click is fine) to install. + - **Linux**: `thingport-bridge-linux-amd64` — `chmod +x`, then run it once to install. + - **macOS**: `thingport-bridge-macos` (universal) — `chmod +x`, remove the quarantine flag, then run with `--install`. See the README for the exact commands. make_latest: true files: | - release/print-stash-bridge-windows-amd64.exe - release/print-stash-bridge-linux-amd64 - release/print-stash-bridge-macos + release/thingport-bridge-windows-amd64.exe + release/thingport-bridge-linux-amd64 + release/thingport-bridge-macos diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml index b29db55..16ce472 100644 --- a/.github/workflows/build-image.yml +++ b/.github/workflows/build-image.yml @@ -10,7 +10,7 @@ on: required: true type: string image_name: - description: "Fully-qualified image name, e.g. ghcr.io/owner/printstash-backend" + description: "Fully-qualified image name, e.g. ghcr.io/owner/thingport-backend" required: true type: string context: diff --git a/.github/workflows/frontend-image.yml b/.github/workflows/frontend-image.yml index 2d810cb..3fd6898 100644 --- a/.github/workflows/frontend-image.yml +++ b/.github/workflows/frontend-image.yml @@ -30,7 +30,7 @@ jobs: uses: ./.github/workflows/build-image.yml with: project_dir: frontend - image_name: ghcr.io/${{ github.repository_owner }}/printstash-frontend + image_name: ghcr.io/${{ github.repository_owner }}/thingport-frontend context: ./frontend dockerfile: frontend/Dockerfile cache_scope: frontend diff --git a/.github/workflows/manual-image.yml b/.github/workflows/manual-image.yml index f78a792..bc4dacb 100644 --- a/.github/workflows/manual-image.yml +++ b/.github/workflows/manual-image.yml @@ -26,7 +26,7 @@ jobs: uses: ./.github/workflows/build-image.yml with: project_dir: backend - image_name: ghcr.io/${{ github.repository_owner }}/printstash-backend + image_name: ghcr.io/${{ github.repository_owner }}/thingport-backend context: ./backend dockerfile: backend/Dockerfile cache_scope: backend @@ -41,7 +41,7 @@ jobs: uses: ./.github/workflows/build-image.yml with: project_dir: frontend - image_name: ghcr.io/${{ github.repository_owner }}/printstash-frontend + image_name: ghcr.io/${{ github.repository_owner }}/thingport-frontend context: ./frontend dockerfile: frontend/Dockerfile cache_scope: frontend diff --git a/.gitignore b/.gitignore index 51b59d9..f6895ec 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,7 @@ yarn-error.log* # Prisma backend/prisma/dev.db* -# PrintStash runtime content +# Thingport runtime content data/ imports/ backend/storage/ diff --git a/backend/.env.example b/backend/.env.example index f191942..b7a4250 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1,6 +1,6 @@ PUID=1000 PGID=1000 -DATABASE_URL=postgresql://printstash:printstash@db:5432/printstash?schema=public +DATABASE_URL=postgresql://thingport:thingport@db:5432/thingport?schema=public FILE_STORAGE=/app/storage API_PORT=8000 PUBLIC_URL= @@ -18,4 +18,4 @@ SMTP_PORT=587 SMTP_SECURE=false SMTP_USER= SMTP_PASS= -SMTP_FROM=PrintStash +SMTP_FROM=Thingport diff --git a/backend/Dockerfile b/backend/Dockerfile index 4d783a8..b999bdc 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -7,8 +7,8 @@ RUN npm ci --no-audit --no-fund && npx prisma generate FROM dependencies AS test COPY . . -ENV DATABASE_URL="postgresql://printstash:printstash@localhost:5432/printstash_test?schema=public" \ - FILE_STORAGE=/tmp/printstash-storage +ENV DATABASE_URL="postgresql://thingport:thingport@localhost:5432/thingport_test?schema=public" \ + FILE_STORAGE=/tmp/thingport-storage CMD ["npm", "test"] FROM dependencies AS build diff --git a/backend/package-lock.json b/backend/package-lock.json index 40769f4..94fc908 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,11 +1,11 @@ { - "name": "printstash-backend", + "name": "thingport-backend", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "printstash-backend", + "name": "thingport-backend", "version": "0.1.0", "dependencies": { "@prisma/client": "^5.20.0", diff --git a/backend/package.json b/backend/package.json index f195a4b..b02d2b5 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,5 +1,5 @@ { - "name": "printstash-backend", + "name": "thingport-backend", "private": true, "version": "0.1.0", "type": "commonjs", diff --git a/backend/src/config.ts b/backend/src/config.ts index e8cd1c4..cdd2d44 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -80,7 +80,7 @@ export const IMPORT_MAKERWORLD_CALL_DELAY_MS = envInt("IMPORT_MAKERWORLD_CALL_DE // confirmed to share the same anti-abuse bucket as MakerWorld's design/download-resolution API // -- this is a cheap precaution, not a proven-necessary one. export const IMPORT_PREVIEW_IMAGE_DELAY_MS = envInt("IMPORT_PREVIEW_IMAGE_DELAY_MS", 250); -export const IMPORT_USER_AGENT = "PrintStash/1.0"; +export const IMPORT_USER_AGENT = "Thingport/1.0"; export const IMPORT_BROWSER_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"; diff --git a/backend/src/routes/imports.ts b/backend/src/routes/imports.ts index 0030afd..b7bb3b4 100644 --- a/backend/src/routes/imports.ts +++ b/backend/src/routes/imports.ts @@ -116,8 +116,8 @@ router.post( } catch (err) { if (err instanceof MakerworldCaptchaError) throw new HttpError(429, err.message); // 400, not 401: this is MakerWorld's own session rejecting our request, not the caller's - // PrintStash session -- the frontend's generic API client treats any 401 as "your - // PrintStash session expired" and force-logs-out, which would be exactly wrong here. See + // Thingport session -- the frontend's generic API client treats any 401 as "your + // Thingport session expired" and force-logs-out, which would be exactly wrong here. See // the same reasoning at importService.ts's tryMakerworldCloudApi/importThingiverseThing. if (err instanceof MakerworldAuthError) throw new HttpError(400, err.message); throw err; diff --git a/backend/src/routes/prints.ts b/backend/src/routes/prints.ts index 3b8b203..32df2e5 100644 --- a/backend/src/routes/prints.ts +++ b/backend/src/routes/prints.ts @@ -299,7 +299,7 @@ router.post( prints = prints.filter((p) => p.tags.includes(tag)); } - let downloadName = body.filename || "printstash.zip"; + let downloadName = body.filename || "thingport.zip"; if (body.tag) { const safeTag = body.tag.replace(/ /g, "_").slice(0, 50) || "tag"; downloadName = `${safeTag}.zip`; diff --git a/backend/src/server.ts b/backend/src/server.ts index 4e65659..a06b521 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -15,5 +15,5 @@ prisma.importJob .catch((err) => console.error("Failed to recover stale import jobs on startup:", err)); app.listen(API_PORT, () => { - console.log(`PrintStash API listening on port ${API_PORT}`); + console.log(`Thingport API listening on port ${API_PORT}`); }); diff --git a/backend/src/services/dashboardService.ts b/backend/src/services/dashboardService.ts index c204b15..a5d23fb 100644 --- a/backend/src/services/dashboardService.ts +++ b/backend/src/services/dashboardService.ts @@ -109,7 +109,7 @@ async function fetchRecentlyAdded(userId: string, limit: number): Promise { const grouped = await prisma.print.groupBy({ @@ -140,7 +140,7 @@ async function fetchTopAuthors(userId: string, limit: number): Promise { const grouped = await prisma.print.groupBy({ @@ -150,7 +150,7 @@ async function fetchTopProviders(userId: string): Promise { }); const buckets = new Map(); for (const g of grouped) { - const key = g.sourceProvider ?? "printstash"; + const key = g.sourceProvider ?? "thingport"; buckets.set(key, (buckets.get(key) ?? 0) + g._count); } return [...buckets.entries()] diff --git a/backend/src/services/databaseSettingsService.ts b/backend/src/services/databaseSettingsService.ts index 2deb053..c74034a 100644 --- a/backend/src/services/databaseSettingsService.ts +++ b/backend/src/services/databaseSettingsService.ts @@ -68,7 +68,7 @@ function friendlyConnectionError(err: unknown): string { if (/password authentication failed/i.test(message)) return "Authentication failed for that user/password."; if (/database .* does not exist/i.test(message)) return "That database does not exist."; if (/relation .?"?User"?.? does not exist/i.test(message)) { - return "Connected, but that database has no PrintStash tables yet -- run migrations against it first."; + return "Connected, but that database has no Thingport tables yet -- run migrations against it first."; } return `Could not connect: ${message}`; } diff --git a/backend/src/services/downloadZip.ts b/backend/src/services/downloadZip.ts index 34393e0..33304c8 100644 --- a/backend/src/services/downloadZip.ts +++ b/backend/src/services/downloadZip.ts @@ -53,7 +53,7 @@ export async function sendPrintsZip(res: Response, prints: PrintWithPlatesAndFol const entries = await buildZipEntries(prints); if (!entries.length) throw new HttpError(404, "No files available for download"); - const tmpPath = path.join(os.tmpdir(), `printstash-zip-${crypto.randomBytes(8).toString("hex")}.zip`); + const tmpPath = path.join(os.tmpdir(), `thingport-zip-${crypto.randomBytes(8).toString("hex")}.zip`); await writeZip(tmpPath, entries); res.download(tmpPath, downloadName, (err) => { fs.rm(tmpPath, { force: true }, () => undefined); diff --git a/backend/src/services/importJobRunner.ts b/backend/src/services/importJobRunner.ts index 8fef1b1..18b1738 100644 --- a/backend/src/services/importJobRunner.ts +++ b/backend/src/services/importJobRunner.ts @@ -173,7 +173,7 @@ export async function runCollectionImportJob(jobId: string, userId: string, body * official API hasn't shown the same anti-abuse behavior MakerWorld's has), then files every * successful import into `collectionTitle` (created on first use, reused on every later import * that resolves to the same title -- e.g. every Likes import shares one "Thingiverse Likes" - * collection; a named Thingiverse Collection gets/reuses a PrintStash Collection of that same + * collection; a named Thingiverse Collection gets/reuses a Thingport Collection of that same * name). `resolveCollectionTitle` runs after the per-item loop (not before) so a Collection's * real name -- an extra API call -- is only fetched once real work has actually happened. */ async function runThingiverseThingsImportJob( @@ -294,7 +294,7 @@ export async function runThingiverseLikesImportJob(jobId: string, userId: string /** Runs a named Thingiverse Collection's batch import in the background -- see * routes/imports.ts's POST /import/thingiverse-collection. Unlike Likes, a Collection has a real - * user-given name (fetchThingiverseCollectionTitle) -- successful imports land in a PrintStash + * user-given name (fetchThingiverseCollectionTitle) -- successful imports land in a Thingport * Collection of that same name, created on first use and reused if the same Thingiverse * Collection is ever imported again. */ export async function runThingiverseCollectionImportJob( @@ -315,7 +315,7 @@ export async function runThingiverseCollectionImportJob( /** Runs a named Printables Collection's batch import in the background -- see * routes/imports.ts's POST /import/printables-collection. Mirrors * runThingiverseThingsImportJob's shape (own resolver, same sequential pacing, files successful - * imports into a PrintStash Collection named after the real Printables Collection name) but + * imports into a Thingport Collection named after the real Printables Collection name) but * simpler: Printables needs no access token, so there's no equivalent "isn't configured for this * instance" failure mode to handle up front. */ export async function runPrintablesCollectionImportJob(jobId: string, userId: string, body: PrintablesCollectionImportJobBody): Promise { diff --git a/backend/src/services/importService.ts b/backend/src/services/importService.ts index 6fd4fdb..5b09973 100644 --- a/backend/src/services/importService.ts +++ b/backend/src/services/importService.ts @@ -176,8 +176,8 @@ async function tryMakerworldCloudApi(url: string, body: ImportRequestBody): Prom } catch (err) { if (err instanceof MakerworldCaptchaError) throw new HttpError(429, err.message); // 400, not 401: this is MakerWorld's own session rejecting our request, not the caller's - // PrintStash session -- the frontend's generic API client treats any 401 as "your - // PrintStash session expired" and force-logs-out, which would be exactly wrong here. + // Thingport session -- the frontend's generic API client treats any 401 as "your + // Thingport session expired" and force-logs-out, which would be exactly wrong here. if (err instanceof MakerworldAuthError) throw new HttpError(400, err.message); throw err; } @@ -323,7 +323,7 @@ export async function downloadImportToTemp( const filename = buildImportFilename(finalUrl, response.headers, body.filename ?? meta.filename); const mime = mimeFromContentType(response.headers.get("content-type"), filename); const suffix = path.extname(filename) || ""; - const tempPath = path.join(os.tmpdir(), `printstash-import-${crypto.randomBytes(8).toString("hex")}${suffix}`); + const tempPath = path.join(os.tmpdir(), `thingport-import-${crypto.randomBytes(8).toString("hex")}${suffix}`); try { await streamToFileCapped(response, tempPath, IMPORT_MAX_BYTES); } catch (err) { @@ -525,7 +525,7 @@ async function downloadPlainFileToTemp(url: string, suggestedName: string): Prom const filename = sanitizeFilename(suggestedName); const tempFilePath = path.join( os.tmpdir(), - `printstash-thingiverse-${crypto.randomBytes(8).toString("hex")}${path.extname(filename)}`, + `thingport-thingiverse-${crypto.randomBytes(8).toString("hex")}${path.extname(filename)}`, ); await streamToFileCapped(res, tempFilePath, IMPORT_MAX_BYTES); return { input: { filename, mime: guessMimeFromPath(filename), tempFilePath } }; @@ -559,7 +559,7 @@ async function importThingiverseThing( } catch (err) { if (err instanceof ThingiverseRateLimitError) throw new HttpError(429, err.message); // 400, not 401: this is the server's configured Thingiverse Access Token being rejected, not - // the caller's PrintStash session -- see the identical reasoning at tryMakerworldCloudApi + // the caller's Thingport session -- see the identical reasoning at tryMakerworldCloudApi // above for why 401 specifically would mislead the frontend into logging the user out. if (err instanceof ThingiverseAuthError) throw new HttpError(400, err.message); throw err; diff --git a/backend/src/services/mailer.ts b/backend/src/services/mailer.ts index 4991972..fa63aea 100644 --- a/backend/src/services/mailer.ts +++ b/backend/src/services/mailer.ts @@ -22,8 +22,8 @@ export async function sendVerificationEmail(to: string, displayName: string, tok await transporter.sendMail({ from: smtp.from, to, - subject: "Confirm your PrintStash account", - text: `Hi ${displayName},\n\nConfirm your email address to finish creating your PrintStash account:\n${link}\n\nThis link expires in 24 hours.`, - html: `

Hi ${displayName},

Confirm your email address to finish creating your PrintStash account:

${link}

This link expires in 24 hours.

`, + subject: "Confirm your Thingport account", + text: `Hi ${displayName},\n\nConfirm your email address to finish creating your Thingport account:\n${link}\n\nThis link expires in 24 hours.`, + html: `

Hi ${displayName},

Confirm your email address to finish creating your Thingport account:

${link}

This link expires in 24 hours.

`, }); } diff --git a/backend/src/services/modelPreviewCache.ts b/backend/src/services/modelPreviewCache.ts index 61a884b..2e8df60 100644 --- a/backend/src/services/modelPreviewCache.ts +++ b/backend/src/services/modelPreviewCache.ts @@ -10,7 +10,7 @@ import { readZipEntry, walkZipEntries } from "../utils/zipReader"; // extruder-resolution priority, same plate-assignment fallbacks, same component p:path handling // -- but not its parsing mechanism. That file walks the DOM node-by-node; a Bambu-sliced 3MF for // a genuinely large model can have millions of / elements, and DOM attribute -// access at that scale is what causes PrintStash's "3D Preview" to hang indefinitely (root-caused +// access at that scale is what causes Thingport's "3D Preview" to hang indefinitely (root-caused // against a real 224MB/2.66M-triangle repro). This file never builds a DOM for the bulk mesh data // -- it scans the raw XML text with a handful of fixed-shape regexes straight into typed arrays, // which is the actual fix. It only runs once per plate (in the background, off the request path) @@ -510,7 +510,7 @@ async function buildGlbGroup(parsed: ParsedModel): Promise { const data = (await fetchPrintablesGraphql(COLLECTION_TITLE_QUERY, { id: collectionId })) as diff --git a/backend/src/services/settingsService.ts b/backend/src/services/settingsService.ts index d10a5b4..f3edce6 100644 --- a/backend/src/services/settingsService.ts +++ b/backend/src/services/settingsService.ts @@ -55,7 +55,7 @@ const THINGIVERSE_ACCESS_TOKEN_KEY = "thingiverse_access_token"; // Instance-wide, not per-user: it's a credential for api.thingiverse.com (the official // Developer API -- see thingiverseApi.ts), tied to whichever Thingiverse account registered -// the app at thingiverse.com/apps/create, not to any one PrintStash user's own account. Every +// the app at thingiverse.com/apps/create, not to any one Thingport user's own account. Every // user's Thingiverse imports share it, same as the storage template and preview mode above. export async function getThingiverseAccessToken(): Promise { const row = await prisma.setting.findUnique({ where: { key: THINGIVERSE_ACCESS_TOKEN_KEY } }); @@ -86,7 +86,7 @@ export type SmtpSettings = { }; const SMTP_SETTINGS_KEY = "smtp_settings"; -const DEFAULT_SMTP_FROM = "PrintStash "; +const DEFAULT_SMTP_FROM = "Thingport "; function envInt(name: string, fallback: number): number { const parsed = Number.parseInt(process.env[name] || "", 10); diff --git a/backend/src/services/thingiverseApi.ts b/backend/src/services/thingiverseApi.ts index 633b48a..ca5f6d9 100644 --- a/backend/src/services/thingiverseApi.ts +++ b/backend/src/services/thingiverseApi.ts @@ -299,7 +299,7 @@ export async function fetchThingiverseUserLikes( /** A user-curated, named "Collection" -- the site's other bookmark mechanism besides the * automatic per-account "Likes" list (see fetchThingiverseUserLikes above). Unlike Likes, a * Collection has a real user-given name (fetchThingiverseCollectionTitle below), which is what - * lets the import land in a PrintStash Collection named after it instead of a generic bucket. */ + * lets the import land in a Thingport Collection named after it instead of a generic bucket. */ export async function fetchThingiverseCollectionThings( collectionId: string, accessToken: string, diff --git a/backend/src/services/zipService.ts b/backend/src/services/zipService.ts index 9055556..f3d1c91 100644 --- a/backend/src/services/zipService.ts +++ b/backend/src/services/zipService.ts @@ -151,7 +151,7 @@ export async function extractZipEntriesToPrints( const buffer = await readZipEntry(zipPath, entryName, IMPORT_MAX_BYTES); if (!buffer) throw new Error("Extracted file exceeds size limit or could not be read"); - tempPath = path.join(os.tmpdir(), `printstash-zip-${crypto.randomBytes(8).toString("hex")}`); + tempPath = path.join(os.tmpdir(), `thingport-zip-${crypto.randomBytes(8).toString("hex")}`); await fs.writeFile(tempPath, buffer); // A resolved page title (e.g. MakerWorld's design name) is the same for every entry in diff --git a/backend/src/uploadMiddleware.ts b/backend/src/uploadMiddleware.ts index 5ecd1b7..46cb9a1 100644 --- a/backend/src/uploadMiddleware.ts +++ b/backend/src/uploadMiddleware.ts @@ -8,7 +8,7 @@ const diskStorage = multer.diskStorage({ destination: (_req, _file, cb) => cb(null, os.tmpdir()), filename: (_req, file, cb) => { const ext = path.extname(file.originalname || ""); - cb(null, `printstash-upload-${crypto.randomBytes(8).toString("hex")}${ext}`); + cb(null, `thingport-upload-${crypto.randomBytes(8).toString("hex")}${ext}`); }, }); diff --git a/backend/tests/admin.test.ts b/backend/tests/admin.test.ts index 877e473..a9d06cb 100644 --- a/backend/tests/admin.test.ts +++ b/backend/tests/admin.test.ts @@ -12,7 +12,7 @@ let memberToken: string; let memberUserId: string; function tmpFile(name: string, contents: string): string { - const dir = fs.mkdtempSync(path.join(os.tmpdir(), "printstash-test-")); + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "thingport-test-")); const p = path.join(dir, name); fs.writeFileSync(p, contents); return p; diff --git a/backend/tests/api.test.ts b/backend/tests/api.test.ts index bd2c1ea..d9e1804 100644 --- a/backend/tests/api.test.ts +++ b/backend/tests/api.test.ts @@ -16,7 +16,7 @@ const createdFolderIds: string[] = []; function tmpFile(name: string, contents: string): string { // supertest's .attach() uses the path's basename as the uploaded filename, so each file // needs its own directory to keep that basename exactly as given (e.g. "solo.stl"). - const dir = fs.mkdtempSync(path.join(os.tmpdir(), "printstash-test-")); + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "thingport-test-")); const p = path.join(dir, name); fs.writeFileSync(p, contents); return p; diff --git a/backend/tests/collections.test.ts b/backend/tests/collections.test.ts index 9f6568f..09ffbf4 100644 --- a/backend/tests/collections.test.ts +++ b/backend/tests/collections.test.ts @@ -10,7 +10,7 @@ const app = createApp(); let token: string; function tmpFile(name: string, contents: string): string { - const dir = fs.mkdtempSync(path.join(os.tmpdir(), "printstash-test-")); + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "thingport-test-")); const p = path.join(dir, name); fs.writeFileSync(p, contents); return p; diff --git a/backend/tests/importJobRunner.test.ts b/backend/tests/importJobRunner.test.ts index 19b62b1..5ca5c97 100644 --- a/backend/tests/importJobRunner.test.ts +++ b/backend/tests/importJobRunner.test.ts @@ -367,7 +367,7 @@ describe("runThingiverseCollectionImportJob", () => { vi.mocked(fetchThingiverseCollectionTitle).mockReset(); }); - it("files successful imports into a PrintStash Collection named after the real Thingiverse Collection", async () => { + it("files successful imports into a Thingport Collection named after the real Thingiverse Collection", async () => { await setThingiverseAccessToken("test-token"); vi.mocked(fetchThingiverseCollectionTitle).mockResolvedValue("Things to Make"); const mockedImport = vi.mocked(importPrintFromUrl); diff --git a/backend/tests/imports.test.ts b/backend/tests/imports.test.ts index c44e7f5..eab4644 100644 --- a/backend/tests/imports.test.ts +++ b/backend/tests/imports.test.ts @@ -14,7 +14,7 @@ let token: string; let userId: string; function tmpFile(name: string, contents: string): string { - const dir = fs.mkdtempSync(path.join(os.tmpdir(), "printstash-test-")); + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "thingport-test-")); const p = path.join(dir, name); fs.writeFileSync(p, contents); return p; diff --git a/backend/tests/modelPreviewCache.test.ts b/backend/tests/modelPreviewCache.test.ts index 3febb34..2f812c5 100644 --- a/backend/tests/modelPreviewCache.test.ts +++ b/backend/tests/modelPreviewCache.test.ts @@ -74,7 +74,7 @@ const PROJECT_SETTINGS_JSON = JSON.stringify({ }); async function buildFixture3mf(destPath: string): Promise { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "printstash-3mf-fixture-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "thingport-3mf-fixture-")); const modelPath = path.join(dir, "3dmodel.model"); const settingsPath = path.join(dir, "model_settings.config"); const projectPath = path.join(dir, "project_settings.config"); @@ -135,7 +135,7 @@ const WRAPPER_MODEL_SETTINGS_XML = ` `; async function buildWrapperFixture3mf(destPath: string): Promise { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "printstash-3mf-wrapper-fixture-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "thingport-3mf-wrapper-fixture-")); const modelPath = path.join(dir, "3dmodel.model"); const settingsPath = path.join(dir, "model_settings.config"); const projectPath = path.join(dir, "project_settings.config"); @@ -158,7 +158,7 @@ describe("modelPreviewCache", () => { // only needs the model-previews cache directory, which the running app normally gets via // src/db.ts's startup side effect. Recreate that here so the test stays DB-independent. await fs.mkdir(path.dirname(modelPreviewGlbPath("x")), { recursive: true }); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "printstash-3mf-out-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "thingport-3mf-out-")); fixturePath = path.join(dir, "fixture.3mf"); await buildFixture3mf(fixturePath); }); @@ -182,10 +182,10 @@ describe("modelPreviewCache", () => { let root: any = null; gltf.scene.traverse((obj: any) => { - if (obj.userData?.printstashPreview) root = obj; + if (obj.userData?.thingportPreview) root = obj; }); expect(root).toBeTruthy(); - const meta = JSON.parse(root.userData.printstashPreview); + const meta = JSON.parse(root.userData.thingportPreview); expect(meta.plates).toEqual([ { index: 1, name: "First plate", objectCount: 1 }, { index: 2, name: "Second plate", objectCount: 1 }, @@ -229,7 +229,7 @@ describe("modelPreviewCache -- internal references", () => { beforeAll(async () => { await fs.mkdir(path.dirname(modelPreviewGlbPath("x")), { recursive: true }); - const dir = await fs.mkdtemp(path.join(os.tmpdir(), "printstash-3mf-wrapper-out-")); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), "thingport-3mf-wrapper-out-")); wrapperFixturePath = path.join(dir, "wrapper.3mf"); await buildWrapperFixture3mf(wrapperFixturePath); }); @@ -252,10 +252,10 @@ describe("modelPreviewCache -- internal references", () => { let root: any = null; gltf.scene.traverse((obj: any) => { - if (obj.userData?.printstashPreview) root = obj; + if (obj.userData?.thingportPreview) root = obj; }); expect(root).toBeTruthy(); - const meta = JSON.parse(root.userData.printstashPreview); + const meta = JSON.parse(root.userData.thingportPreview); // The wrapper object (id 2) has no of its own -- its single mesh only exists because // the component reference to object 1 was resolved and merged in. expect(meta.plates).toEqual([{ index: 1, name: "Only plate", objectCount: 1 }]); diff --git a/bridge/README.md b/bridge/README.md index 4174cf5..17027da 100644 --- a/bridge/README.md +++ b/bridge/README.md @@ -1,29 +1,29 @@ -# PrintStash Bridge +# Thingport Bridge -This helper registers the custom protocol `print-stash://`, downloads the requested file, and -launches it in the slicer PrintStash asked for. It exists because Bambu Studio's own +This helper registers the custom protocol `thingport://`, downloads the requested file, and +launches it in the slicer Thingport asked for. It exists because Bambu Studio's own `bambustudio://` handler only accepts links from a small allowlist of domains it trusts (Bambu -Lab's own storefronts, mainly) -- a self-hosted PrintStash instance is never on that list, so +Lab's own storefronts, mainly) -- a self-hosted Thingport instance is never on that list, so "Open in Bambu Studio" silently does nothing without this bridge in between. OrcaSlicer and PrusaSlicer's protocol handlers accept any HTTP(S) URL directly, so they're launched straight from the browser and never need it. Protocol format: -`print-stash://open?url=&slicer=&filename=` +`thingport://open?url=&slicer=&filename=` -The `url` parameter should be a direct HTTP(s) download link. PrintStash already includes the +The `url` parameter should be a direct HTTP(s) download link. Thingport already includes the auth token in that URL. ## Quick install (no shell commands) Download the latest Bridge binary for your OS from the -[PrintStash releases](https://github.com/TautvydasDerzinskas/print-stash/releases/latest) page -(also linked from the in-app Download page) and run it once. It registers the `print-stash://` +[Thingport releases](https://github.com/TautvydasDerzinskas/Thingport/releases/latest) page +(also linked from the in-app Download page) and run it once. It registers the `thingport://` protocol handler and copies itself into a stable location: -- Windows: `%LOCALAPPDATA%\PrintStash\Bridge\print-stash-bridge.exe` -- Linux: `~/.local/bin/print-stash-bridge` -- macOS: `~/Applications/PrintStash Bridge.app` +- Windows: `%LOCALAPPDATA%\Thingport\Bridge\thingport-bridge.exe` +- Linux: `~/.local/bin/thingport-bridge` +- macOS: `~/Applications/Thingport Bridge.app` ### Windows / Linux @@ -36,19 +36,19 @@ macOS only recognizes a real `.app` bundle as a protocol handler, so install her step rather than a plain double-click: ```bash -chmod +x ~/Downloads/print-stash-bridge-macos -xattr -d com.apple.quarantine ~/Downloads/print-stash-bridge-macos # downloaded files are quarantined by Gatekeeper -~/Downloads/print-stash-bridge-macos --install +chmod +x ~/Downloads/thingport-bridge-macos +xattr -d com.apple.quarantine ~/Downloads/thingport-bridge-macos # downloaded files are quarantined by Gatekeeper +~/Downloads/thingport-bridge-macos --install ``` -This copies itself into `~/Applications/PrintStash Bridge.app` (a background, Dock-less agent) -and registers the `print-stash://` scheme with Launch Services. If macOS still refuses to run it, +This copies itself into `~/Applications/Thingport Bridge.app` (a background, Dock-less agent) +and registers the `thingport://` scheme with Launch Services. If macOS still refuses to run it, open System Settings -> Privacy & Security and allow it there instead of using `xattr`. If the terminal instead prints `Killed: 9` (or `[1] ... killed`) the moment you run it, that's a stale, invalidly-signed binary rather than a Gatekeeper block -- re-sign it yourself and retry: ```bash -codesign --force -s - ~/Downloads/print-stash-bridge-macos +codesign --force -s - ~/Downloads/thingport-bridge-macos ``` ## Build @@ -60,22 +60,22 @@ on macOS itself. Windows (PowerShell): ```powershell cd bridge -go build -o dist\print-stash-bridge.exe .\cmd\print-stash-bridge +go build -o dist\thingport-bridge.exe .\cmd\thingport-bridge ``` Linux (bash): ```bash cd bridge -go build -o dist/print-stash-bridge ./cmd/print-stash-bridge +go build -o dist/thingport-bridge ./cmd/thingport-bridge ``` macOS (bash), universal binary: ```bash cd bridge -GOARCH=arm64 go build -o dist/print-stash-bridge-arm64 ./cmd/print-stash-bridge -GOARCH=amd64 go build -o dist/print-stash-bridge-amd64 ./cmd/print-stash-bridge -lipo -create -output dist/print-stash-bridge-macos dist/print-stash-bridge-arm64 dist/print-stash-bridge-amd64 -codesign --force -s - dist/print-stash-bridge-macos # lipo invalidates each slice's signature; +GOARCH=arm64 go build -o dist/thingport-bridge-arm64 ./cmd/thingport-bridge +GOARCH=amd64 go build -o dist/thingport-bridge-amd64 ./cmd/thingport-bridge +lipo -create -output dist/thingport-bridge-macos dist/thingport-bridge-arm64 dist/thingport-bridge-amd64 +codesign --force -s - dist/thingport-bridge-macos # lipo invalidates each slice's signature; # without this, arm64 Macs SIGKILL it on launch ``` @@ -84,16 +84,16 @@ codesign --force -s - dist/print-stash-bridge-macos # lipo invalidates each sl Windows (PowerShell): ```powershell cd bridge\scripts -.\install-windows.ps1 -BridgePath "..\dist\print-stash-bridge.exe" +.\install-windows.ps1 -BridgePath "..\dist\thingport-bridge.exe" ``` Linux (bash): ```bash cd bridge/scripts -./install-linux.sh ../dist/print-stash-bridge +./install-linux.sh ../dist/thingport-bridge ``` -You can also run the binary directly: `print-stash-bridge --install` (this is required, not just +You can also run the binary directly: `thingport-bridge --install` (this is required, not just convenient, on macOS -- see above). If your shell blocks scripts, set the execution policy for the current user: @@ -116,9 +116,9 @@ pre-warm). If you still want it, on macOS: **Easiest** -- System Settings -> General -> Login Items & Extensions -> click **+** and add -`PrintStash Bridge` from `~/Applications`. +`Thingport Bridge` from `~/Applications`. -**Or, a LaunchAgent** -- save as `~/Library/LaunchAgents/com.printstash.bridge.plist` (replace +**Or, a LaunchAgent** -- save as `~/Library/LaunchAgents/com.thingport.bridge.plist` (replace `YOUR_USERNAME`): ```xml @@ -126,10 +126,10 @@ If you still want it, on macOS: Label - com.printstash.bridge + com.thingport.bridge ProgramArguments - /Users/YOUR_USERNAME/Applications/PrintStash Bridge.app/Contents/MacOS/print-stash-bridge + /Users/YOUR_USERNAME/Applications/Thingport Bridge.app/Contents/MacOS/thingport-bridge RunAtLoad @@ -139,21 +139,21 @@ If you still want it, on macOS: then: ```bash mkdir -p ~/Library/LaunchAgents -# save the file above as ~/Library/LaunchAgents/com.printstash.bridge.plist -launchctl load ~/Library/LaunchAgents/com.printstash.bridge.plist +# save the file above as ~/Library/LaunchAgents/com.thingport.bridge.plist +launchctl load ~/Library/LaunchAgents/com.thingport.bridge.plist ``` ## Config Create a config file if you want custom slicer paths or arguments: -- Windows: `%APPDATA%\printstash-bridge\config.json` -- Linux: `~/.config/printstash-bridge/config.json` -- macOS: `~/Library/Application Support/printstash-bridge/config.json` +- Windows: `%APPDATA%\thingport-bridge\config.json` +- Linux: `~/.config/thingport-bridge/config.json` +- macOS: `~/Library/Application Support/thingport-bridge/config.json` Use `config.example.json` as a template. -Environment override (per slicer): `PRINTSTASH_SLICER_BAMBUSTUDIO=/path/to/BambuStudio` +Environment override (per slicer): `THINGPORT_SLICER_BAMBUSTUDIO=/path/to/BambuStudio` ## Slicer IDs @@ -165,13 +165,13 @@ Environment override (per slicer): `PRINTSTASH_SLICER_BAMBUSTUDIO=/path/to/Bambu ## Testing After install, paste this into your browser's address bar (replace the URL): -`print-stash://open?url=https://example.com/model.3mf&slicer=bambustudio&filename=model.3mf` +`thingport://open?url=https://example.com/model.3mf&slicer=bambustudio&filename=model.3mf` ## Logs -- Windows: `%APPDATA%\printstash-bridge\bridge.log` -- Linux: `~/.config/printstash-bridge/bridge.log` -- macOS: `~/Library/Application Support/printstash-bridge/bridge.log` +- Windows: `%APPDATA%\thingport-bridge\bridge.log` +- Linux: `~/.config/thingport-bridge/bridge.log` +- macOS: `~/Library/Application Support/thingport-bridge/bridge.log` ## Notes diff --git a/bridge/cmd/print-stash-bridge/install_common.go b/bridge/cmd/thingport-bridge/install_common.go similarity index 100% rename from bridge/cmd/print-stash-bridge/install_common.go rename to bridge/cmd/thingport-bridge/install_common.go diff --git a/bridge/cmd/print-stash-bridge/install_darwin.go b/bridge/cmd/thingport-bridge/install_darwin.go similarity index 66% rename from bridge/cmd/print-stash-bridge/install_darwin.go rename to bridge/cmd/thingport-bridge/install_darwin.go index d84e0c8..8cc14a7 100644 --- a/bridge/cmd/print-stash-bridge/install_darwin.go +++ b/bridge/cmd/thingport-bridge/install_darwin.go @@ -3,6 +3,7 @@ package main import ( + _ "embed" "fmt" "log" "os" @@ -11,16 +12,20 @@ import ( ) const ( - bundleName = "PrintStash Bridge.app" - bundleID = "com.printstash.bridge" - bundleExeName = "print-stash-bridge" - lsregisterBin = "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister" + bundleName = "Thingport Bridge.app" + bundleID = "com.thingport.bridge" + bundleExeName = "thingport-bridge" + bundleIconName = "AppIcon.icns" + lsregisterBin = "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister" ) +//go:embed thingport.icns +var bundleIcon []byte + // macOS has no per-invocation registry entry like Windows/Linux -- a custom URL scheme is only // honored for an actual .app bundle, discovered by LaunchServices from its Info.plist. So install // here means: copy this binary into a real app bundle under ~/Applications, write the -// CFBundleURLTypes declaring the print-stash scheme, and re-register that bundle. +// CFBundleURLTypes declaring the thingport scheme, and re-register that bundle. func installSelf() (string, error) { exePath, err := os.Executable() if err != nil { @@ -39,6 +44,7 @@ func installSelf() (string, error) { appDir := filepath.Join(home, "Applications", bundleName) contentsDir := filepath.Join(appDir, "Contents") macosDir := filepath.Join(contentsDir, "MacOS") + resourcesDir := filepath.Join(contentsDir, "Resources") targetExe := filepath.Join(macosDir, bundleExeName) if !samePath(exePath, targetExe) { @@ -53,7 +59,18 @@ func installSelf() (string, error) { return "", fmt.Errorf("write Info.plist: %w", err) } - // Tell LaunchServices about the (re)written bundle so `print-stash://` resolves to it right + // Without this the bundle shows the generic system app icon -- LSUIElement apps don't fall + // back to anything derived from the executable, only CFBundleIconFile + this file actually + // present in Resources/. Embedded (rather than a sibling asset) so the single downloaded + // binary is still all that's needed to install. + if err := os.MkdirAll(resourcesDir, 0755); err != nil { + return "", fmt.Errorf("create Resources dir: %w", err) + } + if err := os.WriteFile(filepath.Join(resourcesDir, bundleIconName), bundleIcon, 0644); err != nil { + return "", fmt.Errorf("write app icon: %w", err) + } + + // Tell LaunchServices about the (re)written bundle so `thingport://` resolves to it right // away, without waiting for the periodic system rescan. Best-effort: a launch still works // later even if this fails (e.g. lsregister moved in a future macOS release). if _, err := os.Stat(lsregisterBin); err == nil { @@ -69,9 +86,9 @@ func infoPlist() string { CFBundleName - PrintStash Bridge + Thingport Bridge CFBundleDisplayName - PrintStash Bridge + Thingport Bridge CFBundleIdentifier ` + bundleID + ` CFBundleVersion @@ -80,6 +97,8 @@ func infoPlist() string { 1.0 CFBundleExecutable ` + bundleExeName + ` + CFBundleIconFile + ` + bundleIconName + ` CFBundlePackageType APPL LSMinimumSystemVersion @@ -90,10 +109,10 @@ func infoPlist() string { CFBundleURLName - PrintStash Bridge Protocol + Thingport Bridge Protocol CFBundleURLSchemes - print-stash + thingport @@ -103,10 +122,10 @@ func infoPlist() string { } // runDefaultLaunch always means "LaunchServices opened the installed app bundle from a -// print-stash:// click" on macOS -- the URL itself arrives later as an Apple Event, never as +// thingport:// click" on macOS -- the URL itself arrives later as an Apple Event, never as // argv, so there's nothing here to distinguish from any other bare launch. This blocks forever // servicing those events. Installing (or reinstalling, e.g. after an update) is instead always -// explicit here: `print-stash-bridge --install` from Terminal. +// explicit here: `thingport-bridge --install` from Terminal. func runDefaultLaunch() { cfg, cfgDir := loadConfig() setupLogging(cfg, cfgDir) diff --git a/bridge/cmd/print-stash-bridge/install_linux.go b/bridge/cmd/thingport-bridge/install_linux.go similarity index 77% rename from bridge/cmd/print-stash-bridge/install_linux.go rename to bridge/cmd/thingport-bridge/install_linux.go index 1f6a0c1..b44b38c 100644 --- a/bridge/cmd/print-stash-bridge/install_linux.go +++ b/bridge/cmd/thingport-bridge/install_linux.go @@ -24,7 +24,7 @@ func installSelf() (string, error) { return "", fmt.Errorf("resolve home dir: %w", err) } installDir := filepath.Join(home, ".local", "bin") - targetPath := filepath.Join(installDir, "print-stash-bridge") + targetPath := filepath.Join(installDir, "thingport-bridge") if !samePath(exePath, targetPath) { if err := copyFile(exePath, targetPath, 0755); err != nil { return "", fmt.Errorf("copy binary: %w", err) @@ -37,9 +37,9 @@ func installSelf() (string, error) { if err := os.MkdirAll(desktopDir, 0755); err != nil { return "", fmt.Errorf("create desktop dir: %w", err) } - desktopFile := filepath.Join(desktopDir, "print-stash-bridge.desktop") + desktopFile := filepath.Join(desktopDir, "thingport-bridge.desktop") desktop := fmt.Sprintf( - "[Desktop Entry]\nName=PrintStash Bridge\nExec=%s %%u\nType=Application\nTerminal=false\nMimeType=x-scheme-handler/print-stash;\n", + "[Desktop Entry]\nName=Thingport Bridge\nExec=%s %%u\nType=Application\nTerminal=false\nMimeType=x-scheme-handler/thingport;\n", targetPath, ) if err := os.WriteFile(desktopFile, []byte(desktop), 0644); err != nil { @@ -47,7 +47,7 @@ func installSelf() (string, error) { } if xdgMime, err := exec.LookPath("xdg-mime"); err == nil { - _ = exec.Command(xdgMime, "default", "print-stash-bridge.desktop", "x-scheme-handler/print-stash").Run() + _ = exec.Command(xdgMime, "default", "thingport-bridge.desktop", "x-scheme-handler/thingport").Run() } return targetPath, nil diff --git a/bridge/cmd/print-stash-bridge/install_other.go b/bridge/cmd/thingport-bridge/install_other.go similarity index 100% rename from bridge/cmd/print-stash-bridge/install_other.go rename to bridge/cmd/thingport-bridge/install_other.go diff --git a/bridge/cmd/print-stash-bridge/install_windows.go b/bridge/cmd/thingport-bridge/install_windows.go similarity index 89% rename from bridge/cmd/print-stash-bridge/install_windows.go rename to bridge/cmd/thingport-bridge/install_windows.go index 9a38f97..7c5bbc8 100644 --- a/bridge/cmd/print-stash-bridge/install_windows.go +++ b/bridge/cmd/thingport-bridge/install_windows.go @@ -28,15 +28,15 @@ func installSelf() (string, error) { if baseDir == "" { return "", fmt.Errorf("LOCALAPPDATA is not set") } - targetDir := filepath.Join(baseDir, "PrintStash", "Bridge") - targetExe := filepath.Join(targetDir, "print-stash-bridge.exe") + targetDir := filepath.Join(baseDir, "Thingport", "Bridge") + targetExe := filepath.Join(targetDir, "thingport-bridge.exe") if !samePath(exePath, targetExe) { if err := copyFile(exePath, targetExe, 0755); err != nil { return "", fmt.Errorf("copy binary: %w", err) } } - if err := registerProtocol(scheme, "PrintStash Bridge", targetExe); err != nil { + if err := registerProtocol(scheme, "Thingport Bridge", targetExe); err != nil { return "", err } diff --git a/bridge/cmd/print-stash-bridge/main.go b/bridge/cmd/thingport-bridge/main.go similarity index 91% rename from bridge/cmd/print-stash-bridge/main.go rename to bridge/cmd/thingport-bridge/main.go index ed18569..b2fa403 100644 --- a/bridge/cmd/print-stash-bridge/main.go +++ b/bridge/cmd/thingport-bridge/main.go @@ -28,17 +28,17 @@ type Config struct { Slicers map[string]SlicerConfig `json:"slicers,omitempty"` } -// scheme is only for protocols PrintStash can't hand off directly to a slicer's own URL handler +// scheme is only for protocols Thingport can't hand off directly to a slicer's own URL handler // (Bambu Studio's bambustudio:// only accepts links from an allowlist of domains it trusts, which -// print-stash's own download URLs aren't on). OrcaSlicer and PrusaSlicer accept any HTTP(S) URL +// thingport's own download URLs aren't on). OrcaSlicer and PrusaSlicer accept any HTTP(S) URL // through their own protocol, so they're launched straight from the browser and never reach here. -const scheme = "print-stash" +const scheme = "thingport" func main() { if len(os.Args) < 2 { // On Windows/Linux the OS execs a fresh process with the URL as argv[1] every time, so a // bare "no args" launch unambiguously means "run me to install". macOS instead delivers a - // print-stash:// open to an already-running app bundle out-of-band as an Apple Event -- + // thingport:// open to an already-running app bundle out-of-band as an Apple Event -- // there's no argv equivalent -- so a bare launch there must be assumed to be that GUI // case; mac install instead requires the explicit --install flag below (see // runDefaultLaunch's darwin implementation). @@ -66,8 +66,8 @@ func main() { func printUsage() { fmt.Println("Usage:") - fmt.Println(" print-stash-bridge --install") - fmt.Println(" print-stash-bridge ") + fmt.Println(" thingport-bridge --install") + fmt.Println(" thingport-bridge ") } // runInstallAndReport is the shared body of "explicitly asked to install" -- via --install on @@ -78,8 +78,8 @@ func runInstallAndReport() { fmt.Printf("Install failed: %v\n", err) os.Exit(1) } - fmt.Printf("Installed PrintStash Bridge at %s\n", target) - fmt.Println("You can now use \"Open in Bambu Studio\" from PrintStash.") + fmt.Printf("Installed Thingport Bridge at %s\n", target) + fmt.Println("You can now use \"Open in Bambu Studio\" from Thingport.") } func handleProtocol(raw string, cfg Config) error { @@ -182,9 +182,9 @@ func loadConfig() (Config, string) { func configDir() string { dir, err := os.UserConfigDir() if err != nil || dir == "" { - return filepath.Join(os.TempDir(), "printstash-bridge") + return filepath.Join(os.TempDir(), "thingport-bridge") } - return filepath.Join(dir, "printstash-bridge") + return filepath.Join(dir, "thingport-bridge") } func resolveDownloadDir(cfg Config) string { @@ -193,9 +193,9 @@ func resolveDownloadDir(cfg Config) string { } dir, err := os.UserCacheDir() if err != nil || dir == "" { - return filepath.Join(os.TempDir(), "printstash-bridge") + return filepath.Join(os.TempDir(), "thingport-bridge") } - return filepath.Join(dir, "printstash-bridge") + return filepath.Join(dir, "thingport-bridge") } func sanitizeFilename(name string) string { @@ -270,7 +270,7 @@ func resolveSlicerCommand(id string, cfg Config) (string, []string) { } } - envKey := "PRINTSTASH_SLICER_" + strings.ToUpper(strings.ReplaceAll(id, "-", "_")) + envKey := "THINGPORT_SLICER_" + strings.ToUpper(strings.ReplaceAll(id, "-", "_")) if val := strings.TrimSpace(os.Getenv(envKey)); val != "" { return val, nil } diff --git a/bridge/cmd/print-stash-bridge/main_test.go b/bridge/cmd/thingport-bridge/main_test.go similarity index 80% rename from bridge/cmd/print-stash-bridge/main_test.go rename to bridge/cmd/thingport-bridge/main_test.go index 7f0150c..256d340 100644 --- a/bridge/cmd/print-stash-bridge/main_test.go +++ b/bridge/cmd/thingport-bridge/main_test.go @@ -21,7 +21,7 @@ func TestSanitizeFilename(t *testing.T) { } func TestRedactURLHidesTokenQueryValue(t *testing.T) { - redacted := redactURL("https://printstash.example/file?id=asset-1&token=secret-value") + redacted := redactURL("https://thingport.example/file?id=asset-1&token=secret-value") if strings.Contains(redacted, "secret-value") { t.Fatalf("redacted URL still contains the token: %s", redacted) } @@ -32,10 +32,10 @@ func TestRedactURLHidesTokenQueryValue(t *testing.T) { func TestHandleProtocolRejectsUntrustedShapesBeforeDownload(t *testing.T) { tests := []string{ - "https://printstash.example/file", - "print-stash://delete?url=https://printstash.example/file", - "print-stash://open", - "print-stash://open?url=file:///tmp/model.stl", + "https://thingport.example/file", + "thingport://delete?url=https://thingport.example/file", + "thingport://open", + "thingport://open?url=file:///tmp/model.stl", } for _, raw := range tests { diff --git a/bridge/cmd/thingport-bridge/thingport.icns b/bridge/cmd/thingport-bridge/thingport.icns new file mode 100644 index 0000000..693d01f Binary files /dev/null and b/bridge/cmd/thingport-bridge/thingport.icns differ diff --git a/bridge/cmd/print-stash-bridge/urlhandler_darwin.go b/bridge/cmd/thingport-bridge/urlhandler_darwin.go similarity index 89% rename from bridge/cmd/print-stash-bridge/urlhandler_darwin.go rename to bridge/cmd/thingport-bridge/urlhandler_darwin.go index 667ffff..e2cc077 100644 --- a/bridge/cmd/print-stash-bridge/urlhandler_darwin.go +++ b/bridge/cmd/thingport-bridge/urlhandler_darwin.go @@ -13,7 +13,7 @@ import "C" import "log" // onOpenURLCallback is set once before RunURLListener blocks the main thread inside Cocoa's run -// loop -- handleGetURLEvent (urlhandler_darwin.m) calls back into it for every print-stash:// +// loop -- handleGetURLEvent (urlhandler_darwin.m) calls back into it for every thingport:// // link the OS delivers via Apple Events, which is how macOS hands a custom URL scheme to an // already-registered app bundle (there is no argv equivalent, unlike Windows/Linux). var onOpenURLCallback func(raw string) @@ -29,7 +29,7 @@ func goHandleOpenURL(cURL *C.char) { } // listenForAppleEventURLs blocks forever, running as a Dock-less (LSUIElement) background agent -// that hands every print-stash:// open to handle. macOS reuses this running instance for +// that hands every thingport:// open to handle. macOS reuses this running instance for // subsequent link clicks instead of relaunching, so it just keeps servicing callback until the // process is terminated. func listenForAppleEventURLs(handle func(raw string)) { diff --git a/bridge/cmd/print-stash-bridge/urlhandler_darwin.m b/bridge/cmd/thingport-bridge/urlhandler_darwin.m similarity index 84% rename from bridge/cmd/print-stash-bridge/urlhandler_darwin.m rename to bridge/cmd/thingport-bridge/urlhandler_darwin.m index b5c9306..71a60fe 100644 --- a/bridge/cmd/print-stash-bridge/urlhandler_darwin.m +++ b/bridge/cmd/thingport-bridge/urlhandler_darwin.m @@ -1,13 +1,13 @@ #import #include "_cgo_export.h" -@interface PSBridgeAppDelegate : NSObject +@interface TPBridgeAppDelegate : NSObject @end -@implementation PSBridgeAppDelegate +@implementation TPBridgeAppDelegate // Registered in applicationWillFinishLaunching, not applicationDidFinishLaunching: when this -// process is launched *by* a print-stash:// open (the common case -- the app isn't already +// process is launched *by* a thingport:// open (the common case -- the app isn't already // running), the GetURL event carrying that very URL can be dispatched before "did finish" fires, // and would otherwise be silently dropped. "Will finish" runs early enough to catch it. - (void)applicationWillFinishLaunching:(NSNotification *)notification { @@ -35,7 +35,7 @@ void RunURLListener(void) { @autoreleasepool { NSApplication *app = [NSApplication sharedApplication]; [app setActivationPolicy:NSApplicationActivationPolicyAccessory]; - PSBridgeAppDelegate *delegate = [[PSBridgeAppDelegate alloc] init]; + TPBridgeAppDelegate *delegate = [[TPBridgeAppDelegate alloc] init]; [app setDelegate:delegate]; [app run]; } diff --git a/bridge/go.mod b/bridge/go.mod index ee9f20a..7f30c4c 100644 --- a/bridge/go.mod +++ b/bridge/go.mod @@ -1,3 +1,3 @@ -module printstash/bridge +module thingport/bridge go 1.21 diff --git a/bridge/scripts/install-linux.sh b/bridge/scripts/install-linux.sh index fcf5828..fe9174a 100755 --- a/bridge/scripts/install-linux.sh +++ b/bridge/scripts/install-linux.sh @@ -4,7 +4,7 @@ set -e BIN_SOURCE="${1:-}" if [ -z "$BIN_SOURCE" ]; then SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" - BIN_SOURCE="$SCRIPT_DIR/../dist/print-stash-bridge" + BIN_SOURCE="$SCRIPT_DIR/../dist/thingport-bridge" fi if [ ! -f "$BIN_SOURCE" ]; then @@ -14,21 +14,21 @@ fi INSTALL_DIR="$HOME/.local/bin" mkdir -p "$INSTALL_DIR" -BIN_TARGET="$INSTALL_DIR/print-stash-bridge" +BIN_TARGET="$INSTALL_DIR/thingport-bridge" install -m 755 "$BIN_SOURCE" "$BIN_TARGET" DESKTOP_DIR="$HOME/.local/share/applications" mkdir -p "$DESKTOP_DIR" -DESKTOP_FILE="$DESKTOP_DIR/print-stash-bridge.desktop" +DESKTOP_FILE="$DESKTOP_DIR/thingport-bridge.desktop" cat > "$DESKTOP_FILE" </dev/null 2>&1 || true +xdg-mime default thingport-bridge.desktop x-scheme-handler/thingport >/dev/null 2>&1 || true echo "Installed protocol handler at $BIN_TARGET" diff --git a/bridge/scripts/install-windows.ps1 b/bridge/scripts/install-windows.ps1 index a61aac6..0031cbd 100644 --- a/bridge/scripts/install-windows.ps1 +++ b/bridge/scripts/install-windows.ps1 @@ -6,12 +6,12 @@ $ErrorActionPreference = "Stop" if (-not $BridgePath) { $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path - $BridgePath = Join-Path $scriptDir "..\dist\print-stash-bridge.exe" + $BridgePath = Join-Path $scriptDir "..\dist\thingport-bridge.exe" } $BridgePath = (Resolve-Path $BridgePath).Path -$targetDir = Join-Path $env:LOCALAPPDATA "PrintStash\Bridge" -$targetExe = Join-Path $targetDir "print-stash-bridge.exe" +$targetDir = Join-Path $env:LOCALAPPDATA "Thingport\Bridge" +$targetExe = Join-Path $targetDir "thingport-bridge.exe" New-Item -ItemType Directory -Path $targetDir -Force | Out-Null Copy-Item -Path $BridgePath -Destination $targetExe -Force @@ -31,6 +31,6 @@ function Register-Protocol { Set-ItemProperty -Path $commandKey -Name "(Default)" -Value "`"$TargetExe`" `"%1`"" -Force } -Register-Protocol -Protocol "print-stash" -Label "PrintStash Bridge" -TargetExe $targetExe +Register-Protocol -Protocol "thingport" -Label "Thingport Bridge" -TargetExe $targetExe Write-Host "Installed protocol handler at $targetExe" diff --git a/docker-compose.deploy.yml b/docker-compose.deploy.yml index fb863e1..19ff506 100644 --- a/docker-compose.deploy.yml +++ b/docker-compose.deploy.yml @@ -3,15 +3,15 @@ services: image: postgres:16-alpine restart: unless-stopped environment: - - POSTGRES_USER=${POSTGRES_USER:-printstash} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-printstash} - - POSTGRES_DB=${POSTGRES_DB:-printstash} + - POSTGRES_USER=${POSTGRES_USER:-thingport} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-thingport} + - POSTGRES_DB=${POSTGRES_DB:-thingport} volumes: - - printstash_db:/var/lib/postgresql/data + - thingport_db:/var/lib/postgresql/data networks: - app-net healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-printstash}"] + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-thingport}"] interval: 5s timeout: 5s retries: 10 @@ -27,8 +27,8 @@ services: backend: # Pin to a specific build instead of :latest, e.g.: - # BACKEND_IMAGE=ghcr.io/tautvydasderzinskas/printstash-backend:sha-a8fef7d - image: ${BACKEND_IMAGE:-ghcr.io/tautvydasderzinskas/printstash-backend:latest} + # BACKEND_IMAGE=ghcr.io/tautvydasderzinskas/thingport-backend:sha-a8fef7d + image: ${BACKEND_IMAGE:-ghcr.io/tautvydasderzinskas/thingport-backend:latest} restart: unless-stopped environment: - PUID=${PUID:-1000} @@ -42,9 +42,9 @@ services: - SMTP_SECURE=${SMTP_SECURE:-false} - SMTP_USER=${SMTP_USER:-} - SMTP_PASS=${SMTP_PASS:-} - - SMTP_FROM=${SMTP_FROM:-PrintStash } + - SMTP_FROM=${SMTP_FROM:-Thingport } - FILE_STORAGE=/app/storage - - DATABASE_URL=postgresql://${POSTGRES_USER:-printstash}:${POSTGRES_PASSWORD:-printstash}@db:5432/${POSTGRES_DB:-printstash}?schema=public + - DATABASE_URL=postgresql://${POSTGRES_USER:-thingport}:${POSTGRES_PASSWORD:-thingport}@db:5432/${POSTGRES_DB:-thingport}?schema=public - CORS_ORIGINS=${CORS_ORIGINS:-} - FLARESOLVERR_URL=${FLARESOLVERR_URL:-http://flaresolverr:8191/v1} depends_on: @@ -53,7 +53,7 @@ services: flaresolverr: condition: service_started volumes: - - printstash_storage:/app/storage + - thingport_storage:/app/storage networks: - app-net @@ -62,8 +62,8 @@ services: # pattern as docker-compose.yml, just built from a published image instead of local source. frontend: # Pin to a specific build instead of :latest, e.g.: - # FRONTEND_IMAGE=ghcr.io/tautvydasderzinskas/printstash-frontend:sha-a8fef7d - image: ${FRONTEND_IMAGE:-ghcr.io/tautvydasderzinskas/printstash-frontend:latest} + # FRONTEND_IMAGE=ghcr.io/tautvydasderzinskas/thingport-frontend:sha-a8fef7d + image: ${FRONTEND_IMAGE:-ghcr.io/tautvydasderzinskas/thingport-frontend:latest} restart: unless-stopped ports: - "${WEB_PORT:-80}:80" @@ -73,8 +73,8 @@ services: - app-net volumes: - printstash_storage: - printstash_db: + thingport_storage: + thingport_db: networks: app-net: diff --git a/docker-compose.yml b/docker-compose.yml index cdab850..863db80 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,15 +3,15 @@ services: image: postgres:16-alpine restart: unless-stopped environment: - - POSTGRES_USER=${POSTGRES_USER:-printstash} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-printstash} - - POSTGRES_DB=${POSTGRES_DB:-printstash} + - POSTGRES_USER=${POSTGRES_USER:-thingport} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-thingport} + - POSTGRES_DB=${POSTGRES_DB:-thingport} volumes: - ./data/postgres:/var/lib/postgresql/data networks: - app-net healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-printstash}"] + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-thingport}"] interval: 5s timeout: 5s retries: 10 @@ -34,7 +34,7 @@ services: - PUID=${PUID:-1000} - PGID=${PGID:-1000} - FILE_STORAGE=/app/storage - - DATABASE_URL=postgresql://${POSTGRES_USER:-printstash}:${POSTGRES_PASSWORD:-printstash}@db:5432/${POSTGRES_DB:-printstash}?schema=public + - DATABASE_URL=postgresql://${POSTGRES_USER:-thingport}:${POSTGRES_PASSWORD:-thingport}@db:5432/${POSTGRES_DB:-thingport}?schema=public - CORS_ORIGINS=${CORS_ORIGINS:-} - INITIAL_ADMIN_EMAIL=${INITIAL_ADMIN_EMAIL:-} - AUTH_SECRET=${AUTH_SECRET:-changeme-secret} @@ -45,7 +45,7 @@ services: - SMTP_SECURE=${SMTP_SECURE:-false} - SMTP_USER=${SMTP_USER:-} - SMTP_PASS=${SMTP_PASS:-} - - SMTP_FROM=${SMTP_FROM:-PrintStash } + - SMTP_FROM=${SMTP_FROM:-Thingport } - FLARESOLVERR_URL=${FLARESOLVERR_URL:-http://flaresolverr:8191/v1} depends_on: db: diff --git a/docs/API_CONTRACT.md b/docs/API_CONTRACT.md index a758d96..747436b 100644 --- a/docs/API_CONTRACT.md +++ b/docs/API_CONTRACT.md @@ -1,4 +1,4 @@ -# PrintStash API contract +# Thingport API contract Node.js + Express + Prisma (Postgres) backend, ported from MakersVault's FastAPI/SQLModel/SQLite backend, with one structural change: a **Print** is a set of one or more **Plates** (multi-part diff --git a/frontend/index.html b/frontend/index.html index 8f3768f..2857929 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -3,7 +3,7 @@ - PrintStash + Thingport diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 18c6bca..6632cfc 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,11 +1,11 @@ { - "name": "printstash-frontend", + "name": "thingport-frontend", "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "printstash-frontend", + "name": "thingport-frontend", "version": "0.0.1", "dependencies": { "@emotion/react": "^11.13.0", diff --git a/frontend/package.json b/frontend/package.json index 4b70eea..e973e85 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,5 +1,5 @@ { - "name": "printstash-frontend", + "name": "thingport-frontend", "private": true, "version": "0.0.1", "type": "module", diff --git a/frontend/public/apple-touch-icon.png b/frontend/public/apple-touch-icon.png index 786fa64..7e1f53c 100644 Binary files a/frontend/public/apple-touch-icon.png and b/frontend/public/apple-touch-icon.png differ diff --git a/frontend/public/favicon-16x16.png b/frontend/public/favicon-16x16.png index f883071..9940946 100644 Binary files a/frontend/public/favicon-16x16.png and b/frontend/public/favicon-16x16.png differ diff --git a/frontend/public/favicon-32x32.png b/frontend/public/favicon-32x32.png index 9b0881e..ff997bf 100644 Binary files a/frontend/public/favicon-32x32.png and b/frontend/public/favicon-32x32.png differ diff --git a/frontend/public/favicon.svg b/frontend/public/favicon.svg index 36623d4..06e1089 100644 --- a/frontend/public/favicon.svg +++ b/frontend/public/favicon.svg @@ -1,37 +1,8 @@ - - - - - - - + + + Thingport icon — Color + + + + diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 467ad55..458c495 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -265,7 +265,7 @@ export default function App() { theme.printstash.pageBackground, + background: (theme) => theme.thingport.pageBackground, minHeight: "100vh", display: "flex", alignItems: "center", diff --git a/frontend/src/api/imports.ts b/frontend/src/api/imports.ts index 37e8d89..b8085ad 100644 --- a/frontend/src/api/imports.ts +++ b/frontend/src/api/imports.ts @@ -219,7 +219,7 @@ export const importsApi = { /** Registers a background job for the selected Things and returns immediately -- see * ImportJobContext.startThingiverseCollectionImport, which follows up with the actual - * polling. Every successful import lands in a PrintStash Collection named after the real + * polling. Every successful import lands in a Thingport Collection named after the real * Thingiverse Collection name. */ fromThingiverseCollection: async (payload: ImportLinkPayload & { thing_ids: string[] }): Promise<{ job_id: string }> => { const res = await fetch(`${apiBase()}/import/thingiverse-collection`, { @@ -255,7 +255,7 @@ export const importsApi = { /** Registers a background job for the selected models and returns immediately -- see * ImportJobContext.startPrintablesCollectionImport, which follows up with the actual polling. - * Every successful import lands in a PrintStash Collection named after the real Printables + * Every successful import lands in a Thingport Collection named after the real Printables * Collection name. */ fromPrintablesCollection: async (payload: ImportLinkPayload & { model_ids: string[] }): Promise<{ job_id: string }> => { const res = await fetch(`${apiBase()}/import/printables-collection`, { diff --git a/frontend/src/assets/fonts/PrintStash-Black.ttf b/frontend/src/assets/fonts/PrintStash-Black.ttf deleted file mode 100644 index ed42287..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Black.ttf and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Black.woff b/frontend/src/assets/fonts/PrintStash-Black.woff deleted file mode 100644 index 104b7f2..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Black.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Black.woff2 b/frontend/src/assets/fonts/PrintStash-Black.woff2 deleted file mode 100644 index c5fe9f9..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Black.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Bold.ttf b/frontend/src/assets/fonts/PrintStash-Bold.ttf deleted file mode 100644 index 26f7b69..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Bold.ttf and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Bold.woff b/frontend/src/assets/fonts/PrintStash-Bold.woff deleted file mode 100644 index cc31de1..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Bold.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Bold.woff2 b/frontend/src/assets/fonts/PrintStash-Bold.woff2 deleted file mode 100644 index ac0190f..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Bold.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-ExtraBold.ttf b/frontend/src/assets/fonts/PrintStash-ExtraBold.ttf deleted file mode 100644 index 9a16675..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-ExtraBold.ttf and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-ExtraBold.woff b/frontend/src/assets/fonts/PrintStash-ExtraBold.woff deleted file mode 100644 index 89c595a..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-ExtraBold.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-ExtraBold.woff2 b/frontend/src/assets/fonts/PrintStash-ExtraBold.woff2 deleted file mode 100644 index ccbfd4e..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-ExtraBold.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-ExtraLight.ttf b/frontend/src/assets/fonts/PrintStash-ExtraLight.ttf deleted file mode 100644 index add4636..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-ExtraLight.ttf and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-ExtraLight.woff b/frontend/src/assets/fonts/PrintStash-ExtraLight.woff deleted file mode 100644 index a1d48a3..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-ExtraLight.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-ExtraLight.woff2 b/frontend/src/assets/fonts/PrintStash-ExtraLight.woff2 deleted file mode 100644 index 8ae3633..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-ExtraLight.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Light.ttf b/frontend/src/assets/fonts/PrintStash-Light.ttf deleted file mode 100644 index c82c196..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Light.ttf and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Light.woff b/frontend/src/assets/fonts/PrintStash-Light.woff deleted file mode 100644 index 8ab0f11..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Light.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Light.woff2 b/frontend/src/assets/fonts/PrintStash-Light.woff2 deleted file mode 100644 index 809f705..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Light.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Medium.ttf b/frontend/src/assets/fonts/PrintStash-Medium.ttf deleted file mode 100644 index 1892d13..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Medium.ttf and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Medium.woff b/frontend/src/assets/fonts/PrintStash-Medium.woff deleted file mode 100644 index 336f3a7..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Medium.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Medium.woff2 b/frontend/src/assets/fonts/PrintStash-Medium.woff2 deleted file mode 100644 index 1161e02..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Medium.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Regular.ttf b/frontend/src/assets/fonts/PrintStash-Regular.ttf deleted file mode 100644 index 5e0fc64..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Regular.ttf and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Regular.woff b/frontend/src/assets/fonts/PrintStash-Regular.woff deleted file mode 100644 index a3a319a..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Regular.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Regular.woff2 b/frontend/src/assets/fonts/PrintStash-Regular.woff2 deleted file mode 100644 index 5979527..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Regular.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Thin.ttf b/frontend/src/assets/fonts/PrintStash-Thin.ttf deleted file mode 100644 index f3e4788..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Thin.ttf and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Thin.woff b/frontend/src/assets/fonts/PrintStash-Thin.woff deleted file mode 100644 index e0a63e2..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Thin.woff and /dev/null differ diff --git a/frontend/src/assets/fonts/PrintStash-Thin.woff2 b/frontend/src/assets/fonts/PrintStash-Thin.woff2 deleted file mode 100644 index ebfecb8..0000000 Binary files a/frontend/src/assets/fonts/PrintStash-Thin.woff2 and /dev/null differ diff --git a/frontend/src/assets/fonts/thingport-400.woff b/frontend/src/assets/fonts/thingport-400.woff new file mode 100644 index 0000000..48b5613 Binary files /dev/null and b/frontend/src/assets/fonts/thingport-400.woff differ diff --git a/frontend/src/assets/fonts/thingport-500.woff b/frontend/src/assets/fonts/thingport-500.woff new file mode 100644 index 0000000..5ae8ea9 Binary files /dev/null and b/frontend/src/assets/fonts/thingport-500.woff differ diff --git a/frontend/src/assets/fonts/thingport-700.woff b/frontend/src/assets/fonts/thingport-700.woff new file mode 100644 index 0000000..134d64b Binary files /dev/null and b/frontend/src/assets/fonts/thingport-700.woff differ diff --git a/frontend/src/assets/logos/thingport-icon-color.svg b/frontend/src/assets/logos/thingport-icon-color.svg new file mode 100644 index 0000000..06e1089 --- /dev/null +++ b/frontend/src/assets/logos/thingport-icon-color.svg @@ -0,0 +1,8 @@ + + + Thingport icon — Color + + + + + diff --git a/frontend/src/assets/logos/thingport-icon-dark.svg b/frontend/src/assets/logos/thingport-icon-dark.svg new file mode 100644 index 0000000..21301a4 --- /dev/null +++ b/frontend/src/assets/logos/thingport-icon-dark.svg @@ -0,0 +1,8 @@ + + + Thingport icon — Dark + + + + + diff --git a/frontend/src/assets/logos/thingport-icon-green.svg b/frontend/src/assets/logos/thingport-icon-green.svg new file mode 100644 index 0000000..e01356c --- /dev/null +++ b/frontend/src/assets/logos/thingport-icon-green.svg @@ -0,0 +1,8 @@ + + + Thingport icon — Green + + + + + diff --git a/frontend/src/assets/logos/thingport-icon-on-dark.svg b/frontend/src/assets/logos/thingport-icon-on-dark.svg new file mode 100644 index 0000000..78fd804 --- /dev/null +++ b/frontend/src/assets/logos/thingport-icon-on-dark.svg @@ -0,0 +1,8 @@ + + + Thingport icon — On dark + + + + + diff --git a/frontend/src/assets/logos/thingport-icon-white.svg b/frontend/src/assets/logos/thingport-icon-white.svg new file mode 100644 index 0000000..cb0d85f --- /dev/null +++ b/frontend/src/assets/logos/thingport-icon-white.svg @@ -0,0 +1,8 @@ + + + Thingport icon — White + + + + + diff --git a/frontend/src/assets/logos/thingport-icon.svg b/frontend/src/assets/logos/thingport-icon.svg new file mode 100644 index 0000000..06e1089 --- /dev/null +++ b/frontend/src/assets/logos/thingport-icon.svg @@ -0,0 +1,8 @@ + + + Thingport icon — Color + + + + + diff --git a/frontend/src/assets/logos/thingport-lockup-compact-color.svg b/frontend/src/assets/logos/thingport-lockup-compact-color.svg new file mode 100644 index 0000000..81b0fec --- /dev/null +++ b/frontend/src/assets/logos/thingport-lockup-compact-color.svg @@ -0,0 +1,13 @@ + + + Thingport — Color + + + + + + + + + + diff --git a/frontend/src/assets/logos/thingport-lockup-compact-dark.svg b/frontend/src/assets/logos/thingport-lockup-compact-dark.svg new file mode 100644 index 0000000..cfd21d9 --- /dev/null +++ b/frontend/src/assets/logos/thingport-lockup-compact-dark.svg @@ -0,0 +1,13 @@ + + + Thingport — Dark + + + + + + + + + + diff --git a/frontend/src/assets/logos/thingport-lockup-compact-green.svg b/frontend/src/assets/logos/thingport-lockup-compact-green.svg new file mode 100644 index 0000000..061f671 --- /dev/null +++ b/frontend/src/assets/logos/thingport-lockup-compact-green.svg @@ -0,0 +1,13 @@ + + + Thingport — Green + + + + + + + + + + diff --git a/frontend/src/assets/logos/thingport-lockup-compact-on-dark.svg b/frontend/src/assets/logos/thingport-lockup-compact-on-dark.svg new file mode 100644 index 0000000..8d532bd --- /dev/null +++ b/frontend/src/assets/logos/thingport-lockup-compact-on-dark.svg @@ -0,0 +1,13 @@ + + + Thingport — On dark + + + + + + + + + + diff --git a/frontend/src/assets/logos/thingport-lockup-compact-white.svg b/frontend/src/assets/logos/thingport-lockup-compact-white.svg new file mode 100644 index 0000000..69785f1 --- /dev/null +++ b/frontend/src/assets/logos/thingport-lockup-compact-white.svg @@ -0,0 +1,13 @@ + + + Thingport — White + + + + + + + + + + diff --git a/frontend/src/assets/logos/thingport-lockup-stacked-color.svg b/frontend/src/assets/logos/thingport-lockup-stacked-color.svg new file mode 100644 index 0000000..5897cf4 --- /dev/null +++ b/frontend/src/assets/logos/thingport-lockup-stacked-color.svg @@ -0,0 +1,13 @@ + + + Thingport Projects stacked — Color + + + + + + + + + + diff --git a/frontend/src/assets/logos/thingport-lockup-stacked-dark.svg b/frontend/src/assets/logos/thingport-lockup-stacked-dark.svg new file mode 100644 index 0000000..647be15 --- /dev/null +++ b/frontend/src/assets/logos/thingport-lockup-stacked-dark.svg @@ -0,0 +1,13 @@ + + + Thingport Projects stacked — Dark + + + + + + + + + + diff --git a/frontend/src/assets/logos/thingport-lockup-stacked-green.svg b/frontend/src/assets/logos/thingport-lockup-stacked-green.svg new file mode 100644 index 0000000..91c1c86 --- /dev/null +++ b/frontend/src/assets/logos/thingport-lockup-stacked-green.svg @@ -0,0 +1,13 @@ + + + Thingport Projects stacked — Green + + + + + + + + + + diff --git a/frontend/src/assets/logos/thingport-lockup-stacked-on-dark.svg b/frontend/src/assets/logos/thingport-lockup-stacked-on-dark.svg new file mode 100644 index 0000000..0352b53 --- /dev/null +++ b/frontend/src/assets/logos/thingport-lockup-stacked-on-dark.svg @@ -0,0 +1,13 @@ + + + Thingport Projects stacked — On dark + + + + + + + + + + diff --git a/frontend/src/assets/logos/thingport-lockup-stacked-white.svg b/frontend/src/assets/logos/thingport-lockup-stacked-white.svg new file mode 100644 index 0000000..0c4a88c --- /dev/null +++ b/frontend/src/assets/logos/thingport-lockup-stacked-white.svg @@ -0,0 +1,13 @@ + + + Thingport Projects stacked — White + + + + + + + + + + diff --git a/frontend/src/assets/logos/thingport-lockup.svg b/frontend/src/assets/logos/thingport-lockup.svg new file mode 100644 index 0000000..ce55b6b --- /dev/null +++ b/frontend/src/assets/logos/thingport-lockup.svg @@ -0,0 +1,14 @@ + + + Thingport Projects — Color + + + + + + + + + + + diff --git a/frontend/src/assets/logos/thingport-mark-color.svg b/frontend/src/assets/logos/thingport-mark-color.svg new file mode 100644 index 0000000..f361ba2 --- /dev/null +++ b/frontend/src/assets/logos/thingport-mark-color.svg @@ -0,0 +1,7 @@ + + + Thingport mark — Color + + + + diff --git a/frontend/src/assets/logos/thingport-mark-dark.svg b/frontend/src/assets/logos/thingport-mark-dark.svg new file mode 100644 index 0000000..652bcd7 --- /dev/null +++ b/frontend/src/assets/logos/thingport-mark-dark.svg @@ -0,0 +1,7 @@ + + + Thingport mark — Dark + + + + diff --git a/frontend/src/assets/logos/thingport-mark-green.svg b/frontend/src/assets/logos/thingport-mark-green.svg new file mode 100644 index 0000000..2c70bff --- /dev/null +++ b/frontend/src/assets/logos/thingport-mark-green.svg @@ -0,0 +1,7 @@ + + + Thingport mark — Green + + + + diff --git a/frontend/src/assets/logos/thingport-mark-on-dark.svg b/frontend/src/assets/logos/thingport-mark-on-dark.svg new file mode 100644 index 0000000..8b9c0ed --- /dev/null +++ b/frontend/src/assets/logos/thingport-mark-on-dark.svg @@ -0,0 +1,7 @@ + + + Thingport mark — On dark + + + + diff --git a/frontend/src/assets/logos/thingport-mark-white.svg b/frontend/src/assets/logos/thingport-mark-white.svg new file mode 100644 index 0000000..26f03d6 --- /dev/null +++ b/frontend/src/assets/logos/thingport-mark-white.svg @@ -0,0 +1,7 @@ + + + Thingport mark — White + + + + diff --git a/frontend/src/assets/logos/thingport-mark.svg b/frontend/src/assets/logos/thingport-mark.svg new file mode 100644 index 0000000..f361ba2 --- /dev/null +++ b/frontend/src/assets/logos/thingport-mark.svg @@ -0,0 +1,7 @@ + + + Thingport mark — Color + + + + diff --git a/frontend/src/assets/logos/thingport-wordmark-color.svg b/frontend/src/assets/logos/thingport-wordmark-color.svg new file mode 100644 index 0000000..6b0ecca --- /dev/null +++ b/frontend/src/assets/logos/thingport-wordmark-color.svg @@ -0,0 +1,5 @@ + + + Thingport wordmark — Color + + diff --git a/frontend/src/assets/logos/thingport-wordmark-dark.svg b/frontend/src/assets/logos/thingport-wordmark-dark.svg new file mode 100644 index 0000000..7493d6d --- /dev/null +++ b/frontend/src/assets/logos/thingport-wordmark-dark.svg @@ -0,0 +1,5 @@ + + + Thingport wordmark — Dark + + diff --git a/frontend/src/assets/logos/thingport-wordmark-green.svg b/frontend/src/assets/logos/thingport-wordmark-green.svg new file mode 100644 index 0000000..e50f274 --- /dev/null +++ b/frontend/src/assets/logos/thingport-wordmark-green.svg @@ -0,0 +1,5 @@ + + + Thingport wordmark — Green + + diff --git a/frontend/src/assets/logos/thingport-wordmark-on-dark.svg b/frontend/src/assets/logos/thingport-wordmark-on-dark.svg new file mode 100644 index 0000000..0a5c3dd --- /dev/null +++ b/frontend/src/assets/logos/thingport-wordmark-on-dark.svg @@ -0,0 +1,5 @@ + + + Thingport wordmark — On dark + + diff --git a/frontend/src/assets/logos/thingport-wordmark-white.svg b/frontend/src/assets/logos/thingport-wordmark-white.svg new file mode 100644 index 0000000..3ff6f89 --- /dev/null +++ b/frontend/src/assets/logos/thingport-wordmark-white.svg @@ -0,0 +1,5 @@ + + + Thingport wordmark — White + + diff --git a/frontend/src/components/BrandMark.tsx b/frontend/src/components/BrandMark.tsx new file mode 100644 index 0000000..fa943ae --- /dev/null +++ b/frontend/src/components/BrandMark.tsx @@ -0,0 +1,30 @@ +import Box from "@mui/material/Box"; +import type { ResolvedTheme } from "../constants/settingsOptions"; +import markColor from "../assets/logos/thingport-mark-color.svg"; +import markOnDark from "../assets/logos/thingport-mark-on-dark.svg"; + +type Props = { + theme: ResolvedTheme; + size?: "lg" | "md" | "sm"; +}; + +const HEIGHTS: Record, string> = { + lg: "2.25rem", + md: "1.5rem", + sm: "1.125rem", +}; + +/** The Thingport icon-only mark (no wordmark) -- used where the viewer's own theme prop, not the + * surrounding MUI theme, decides which variant to show (e.g. ModelViewer's fixed-theme preview + * canvas). */ +export default function BrandMark({ theme, size = "md" }: Props) { + const src = theme === "dark" ? markOnDark : markColor; + return ( + + ); +} diff --git a/frontend/src/components/Layout/AppLayout.tsx b/frontend/src/components/Layout/AppLayout.tsx index aba0a43..36031c1 100644 --- a/frontend/src/components/Layout/AppLayout.tsx +++ b/frontend/src/components/Layout/AppLayout.tsx @@ -132,7 +132,7 @@ function AppLayoutShell({ theme.printstash.pageBackground, + background: (theme) => theme.thingport.pageBackground, minHeight: "100vh", display: "flex", }} diff --git a/frontend/src/components/Layout/Sidebar/index.tsx b/frontend/src/components/Layout/Sidebar/index.tsx index dd5156f..97ef376 100644 --- a/frontend/src/components/Layout/Sidebar/index.tsx +++ b/frontend/src/components/Layout/Sidebar/index.tsx @@ -29,7 +29,7 @@ import Wordmark from "../../Wordmark"; const SIDEBAR_WIDTH = 240; const SIDEBAR_COLLAPSED_WIDTH = 72; -const SIDEBAR_COLLAPSED_STORAGE_KEY = "printstash_sidebar_collapsed"; +const SIDEBAR_COLLAPSED_STORAGE_KEY = "thingport_sidebar_collapsed"; /** Icon-only rail row used for every nav item once the sidebar is collapsed -- a tooltip stands * in for the label. */ diff --git a/frontend/src/components/Wordmark.tsx b/frontend/src/components/Wordmark.tsx index 669c7b9..ea533e5 100644 --- a/frontend/src/components/Wordmark.tsx +++ b/frontend/src/components/Wordmark.tsx @@ -1,83 +1,29 @@ -import React from "react"; import Box from "@mui/material/Box"; -import { DISPLAY_FONT_STACK } from "../theme"; +import { useTheme } from "@mui/material/styles"; +import lockupColor from "../assets/logos/thingport-lockup-compact-color.svg"; +import lockupOnDark from "../assets/logos/thingport-lockup-compact-on-dark.svg"; type Props = { size?: "lg" | "md" | "sm"; }; -/** The brand mark: a 3D-printing nozzle laying down a triangulated mesh layer. */ -function PrinterMark() { - return ( - - ); -} - -const FONT_SIZES: Record, string> = { +const HEIGHTS: Record, string> = { lg: "2.25rem", md: "1.5rem", sm: "1.125rem", }; +/** The Thingport logo lockup (icon + wordmark combined into one image) -- swaps between the + * light- and dark-theme variants based on the active MUI palette mode. */ export default function Wordmark({ size = "md" }: Props) { - const fontSize = FONT_SIZES[size]; + const theme = useTheme(); + const src = theme.palette.mode === "dark" ? lockupOnDark : lockupColor; return ( - - - - - - PrintStash - - + ); } diff --git a/frontend/src/components/media/ModelViewer/index.tsx b/frontend/src/components/media/ModelViewer/index.tsx index c2b66bf..91fe030 100644 --- a/frontend/src/components/media/ModelViewer/index.tsx +++ b/frontend/src/components/media/ModelViewer/index.tsx @@ -16,11 +16,11 @@ import { } from "../../../utils/modelLoaders"; import { buildBambuModelGroup, loadCachedBambuGlb, type Parsed3MFData, type PlateSummary } from "../../../utils/bambuThreeMf"; import { createOrientationGizmo } from "./orientationGizmo"; -import Wordmark from "../../Wordmark"; +import BrandMark from "../../BrandMark"; // This viewer's lighting/tone-mapping setup, build-plate + grid + shadow-catcher rendering, and // fitCameraToBox below are ported from maziggy/bambuddy (https://github.com/maziggy/bambuddy, -// frontend/src/components/ModelViewer.tsx, AGPL-3.0-only). PrintStash uses this file under the +// frontend/src/components/ModelViewer.tsx, AGPL-3.0-only). Thingport uses this file under the // same license -- see LICENSE at the repo root. Multi-plate parsing itself lives in // ../../../utils/bambuThreeMf.ts, ported from the same source. @@ -514,7 +514,7 @@ export default function ModelViewer({ url, ext, viewKey, theme, colorOverride, s }} > - + diff --git a/frontend/src/constants/bridge.ts b/frontend/src/constants/bridge.ts index a15f308..112099b 100644 --- a/frontend/src/constants/bridge.ts +++ b/frontend/src/constants/bridge.ts @@ -1,16 +1,16 @@ -// PrintStash Bridge is a small helper app (source in /bridge, built by +// Thingport Bridge is a small helper app (source in /bridge, built by // .github/workflows/bridge-release.yml) that "Open in Bambu Studio" hands off to instead of // Bambu Studio's own bambustudio:// link -- see bridge/README.md for why. These are stable URLs: // GitHub always resolves /releases/latest/download/ to that asset on the most recent // release, so they don't need updating when a new Bridge build ships. -const BRIDGE_RELEASES_BASE = "https://github.com/TautvydasDerzinskas/print-stash/releases/latest/download"; +const BRIDGE_RELEASES_BASE = "https://github.com/TautvydasDerzinskas/Thingport/releases/latest/download"; export type BridgeDownload = { os: "windows" | "macos" | "linux"; label: string; asset: string }; export const BRIDGE_DOWNLOADS: BridgeDownload[] = [ - { os: "windows", label: "Windows", asset: "print-stash-bridge-windows-amd64.exe" }, - { os: "macos", label: "macOS", asset: "print-stash-bridge-macos" }, - { os: "linux", label: "Linux", asset: "print-stash-bridge-linux-amd64" }, + { os: "windows", label: "Windows", asset: "thingport-bridge-windows-amd64.exe" }, + { os: "macos", label: "macOS", asset: "thingport-bridge-macos" }, + { os: "linux", label: "Linux", asset: "thingport-bridge-linux-amd64" }, ]; export function bridgeDownloadUrl(asset: string): string { diff --git a/frontend/src/constants/languages.ts b/frontend/src/constants/languages.ts index 6db8de7..48dea30 100644 --- a/frontend/src/constants/languages.ts +++ b/frontend/src/constants/languages.ts @@ -5,4 +5,4 @@ export const SUPPORTED_LANGUAGES = [ export type LanguageCode = (typeof SUPPORTED_LANGUAGES)[number]["code"]; -export const LANGUAGE_STORAGE_KEY = "printstash_language"; +export const LANGUAGE_STORAGE_KEY = "thingport_language"; diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 48390c3..7827e50 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -174,7 +174,7 @@ "backToProfile": "Back to Profile", "language": { "heading": "Language", - "subtitle": "Choose the language used throughout PrintStash." + "subtitle": "Choose the language used throughout Thingport." }, "makerworld": { "heading": "MakerWorld", @@ -190,7 +190,7 @@ "description": "Your preferred slicer, used by a model's \"Open in Slicer\" action to launch it directly via that slicer's own link (e.g. bambustudio://).", "label": "Slicer", "failed": "Failed to save -- try again.", - "bridgeRequiredPrefix": "Bambu Studio needs the PrintStash Bridge helper app installed to open files from here --", + "bridgeRequiredPrefix": "Bambu Studio needs the Thingport Bridge helper app installed to open files from here --", "bridgeRequiredLink": "get it from the Download page." } }, @@ -268,7 +268,7 @@ "heading": "Storage Structure", "subtitle": "Choose how managed model files are organized on disk.", "templateHeading": "Path template", - "templateDesc": "The model name is unique inside its PrintStash folder. Renaming a model also renames its file while preserving the extension.", + "templateDesc": "The model name is unique inside its Thingport folder. Renaming a model also renames its file while preserving the extension.", "templateLabel": "Template", "templatePlaceholder": "{folder}/{model}/{filename}", "examplePathsHeading": "Example paths (two plates of one print)", @@ -347,7 +347,7 @@ "passwordLabel": "Password", "passwordPlaceholder": "Leave blank to keep the current password", "fromLabel": "From address", - "fromPlaceholder": "PrintStash ", + "fromPlaceholder": "Thingport ", "save": "Save", "saving": "Saving…", "saved": "Saved.", @@ -417,7 +417,7 @@ } }, "download": { - "pageTitle": "PrintStash Bridge", + "pageTitle": "Thingport Bridge", "intro": "A small helper app that runs on your computer so \"Open in Slicer\" can hand a model straight to your slicer.", "downloadHeading": "Download", "modal": { @@ -435,7 +435,7 @@ "heading": "Install on macOS", "step1": "Make it executable.", "step2": "Remove the Gatekeeper quarantine flag -- downloaded files are quarantined automatically.", - "step3": "Install it. This copies the app into ~/Applications and registers the print-stash:// link.", + "step3": "Install it. This copies the app into ~/Applications and registers the thingport:// link.", "note": "If macOS still refuses to run it, open System Settings -> Privacy & Security and allow it there instead." } } diff --git a/frontend/src/i18n/locales/lt.json b/frontend/src/i18n/locales/lt.json index d748916..3bf76de 100644 --- a/frontend/src/i18n/locales/lt.json +++ b/frontend/src/i18n/locales/lt.json @@ -174,7 +174,7 @@ "backToProfile": "Grįžti į profilį", "language": { "heading": "Kalba", - "subtitle": "Pasirinkite kalbą, naudojamą visame PrintStash." + "subtitle": "Pasirinkite kalbą, naudojamą visame Thingport." }, "makerworld": { "heading": "MakerWorld", @@ -190,7 +190,7 @@ "description": "Jūsų pageidaujama pjaustyklė, naudojama modelio veiksmo „Atverti pjaustyklėje“, kad modelis būtų atidarytas tiesiogiai per tos pjaustyklės nuorodą (pvz. bambustudio://).", "label": "Pjaustyklė", "failed": "Nepavyko išsaugoti -- bandykite dar kartą.", - "bridgeRequiredPrefix": "Bambu Studio failams atverti iš čia reikalinga įdiegta PrintStash Bridge pagalbinė programa --", + "bridgeRequiredPrefix": "Bambu Studio failams atverti iš čia reikalinga įdiegta Thingport Bridge pagalbinė programa --", "bridgeRequiredLink": "atsisiųskite ją atsisiuntimo puslapyje." } }, @@ -268,7 +268,7 @@ "heading": "Saugojimo struktūra", "subtitle": "Pasirinkite, kaip valdomi modelių failai tvarkomi diske.", "templateHeading": "Kelio šablonas", - "templateDesc": "Modelio pavadinimas yra unikalus jo PrintStash aplanke. Modelio pervadinimas taip pat pervadina jo failą, išsaugant plėtinį.", + "templateDesc": "Modelio pavadinimas yra unikalus jo Thingport aplanke. Modelio pervadinimas taip pat pervadina jo failą, išsaugant plėtinį.", "templateLabel": "Šablonas", "templatePlaceholder": "{folder}/{model}/{filename}", "examplePathsHeading": "Kelių pavyzdžiai (dvi vieno modelio plokštės)", @@ -347,7 +347,7 @@ "passwordLabel": "Slaptažodis", "passwordPlaceholder": "Palikite tuščią, kad išsaugotumėte dabartinį slaptažodį", "fromLabel": "Siuntėjo adresas", - "fromPlaceholder": "PrintStash ", + "fromPlaceholder": "Thingport ", "save": "Išsaugoti", "saving": "Saugoma…", "saved": "Išsaugota.", @@ -417,7 +417,7 @@ } }, "download": { - "pageTitle": "PrintStash Bridge", + "pageTitle": "Thingport Bridge", "intro": "Nedidelė pagalbinė programa, veikianti jūsų kompiuteryje, kad „Atverti pjaustyklėje“ galėtų perduoti modelį tiesiai jūsų pjaustyklei.", "downloadHeading": "Atsisiųsti", "modal": { @@ -435,7 +435,7 @@ "heading": "Diegimas „macOS“", "step1": "Suteikite leidimą vykdyti.", "step2": "Pašalinkite Gatekeeper karantino žymą -- atsisiųsti failai automatiškai pažymimi karantinu.", - "step3": "Įdiekite jį. Tai nukopijuos programą į ~/Applications ir užregistruos print-stash:// nuorodą.", + "step3": "Įdiekite jį. Tai nukopijuos programą į ~/Applications ir užregistruos thingport:// nuorodą.", "note": "Jei „macOS“ vis tiek atsisako jį paleisti, atidarykite System Settings -> Privacy & Security ir leiskite jį ten." } } diff --git a/frontend/src/index.css b/frontend/src/index.css index fd06476..8bc2beb 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1,91 +1,27 @@ @font-face { - font-family: "PrintStash Display"; - src: - url("./assets/fonts/PrintStash-Thin.woff2") format("woff2"), - url("./assets/fonts/PrintStash-Thin.woff") format("woff"), - url("./assets/fonts/PrintStash-Thin.ttf") format("truetype"); - font-weight: 100; - font-style: normal; - font-display: swap; -} - -@font-face { - font-family: "PrintStash Display"; - src: - url("./assets/fonts/PrintStash-ExtraLight.woff2") format("woff2"), - url("./assets/fonts/PrintStash-ExtraLight.woff") format("woff"), - url("./assets/fonts/PrintStash-ExtraLight.ttf") format("truetype"); - font-weight: 200; - font-style: normal; - font-display: swap; -} - -@font-face { - font-family: "PrintStash Display"; - src: - url("./assets/fonts/PrintStash-Light.woff2") format("woff2"), - url("./assets/fonts/PrintStash-Light.woff") format("woff"), - url("./assets/fonts/PrintStash-Light.ttf") format("truetype"); - font-weight: 300; - font-style: normal; - font-display: swap; -} - -@font-face { - font-family: "PrintStash Display"; - src: - url("./assets/fonts/PrintStash-Regular.woff2") format("woff2"), - url("./assets/fonts/PrintStash-Regular.woff") format("woff"), - url("./assets/fonts/PrintStash-Regular.ttf") format("truetype"); + font-family: "Thingport"; + src: url("./assets/fonts/thingport-400.woff") format("woff"); font-weight: 400; font-style: normal; font-display: swap; } @font-face { - font-family: "PrintStash Display"; - src: - url("./assets/fonts/PrintStash-Medium.woff2") format("woff2"), - url("./assets/fonts/PrintStash-Medium.woff") format("woff"), - url("./assets/fonts/PrintStash-Medium.ttf") format("truetype"); + font-family: "Thingport"; + src: url("./assets/fonts/thingport-500.woff") format("woff"); font-weight: 500; font-style: normal; font-display: swap; } @font-face { - font-family: "PrintStash Display"; - src: - url("./assets/fonts/PrintStash-Bold.woff2") format("woff2"), - url("./assets/fonts/PrintStash-Bold.woff") format("woff"), - url("./assets/fonts/PrintStash-Bold.ttf") format("truetype"); + font-family: "Thingport"; + src: url("./assets/fonts/thingport-700.woff") format("woff"); font-weight: 700; font-style: normal; font-display: swap; } -@font-face { - font-family: "PrintStash Display"; - src: - url("./assets/fonts/PrintStash-ExtraBold.woff2") format("woff2"), - url("./assets/fonts/PrintStash-ExtraBold.woff") format("woff"), - url("./assets/fonts/PrintStash-ExtraBold.ttf") format("truetype"); - font-weight: 800; - font-style: normal; - font-display: swap; -} - -@font-face { - font-family: "PrintStash Display"; - src: - url("./assets/fonts/PrintStash-Black.woff2") format("woff2"), - url("./assets/fonts/PrintStash-Black.woff") format("woff"), - url("./assets/fonts/PrintStash-Black.ttf") format("truetype"); - font-weight: 900; - font-style: normal; - font-display: swap; -} - html, body, #root { diff --git a/frontend/src/pages/DashboardPage/ProviderListCard.tsx b/frontend/src/pages/DashboardPage/ProviderListCard.tsx index db7434f..57718d9 100644 --- a/frontend/src/pages/DashboardPage/ProviderListCard.tsx +++ b/frontend/src/pages/DashboardPage/ProviderListCard.tsx @@ -14,7 +14,7 @@ type Props = { providers: DashboardProvider[]; }; -const OWN_UPLOAD_LABEL = "PrintStash"; +const OWN_UPLOAD_LABEL = "Thingport"; // Reuses the exact same brand colors as the provider badge shown on a model's card thumbnail // (see constants/importProviders.ts) -- a direct upload/zip import has no import-source badge @@ -27,7 +27,7 @@ function chipSx(provider: string): { label: string; sx: object } { } /** Top Providers -- how many of this user's models came from each source (MakerWorld, - * Thingiverse, or a direct PrintStash upload). A fixed, small set in practice, so unlike the + * Thingiverse, or a direct Thingport upload). A fixed, small set in practice, so unlike the * other list cards this one has no "see more" dialog and its rows aren't clickable -- there's * no per-provider filtered view to link to yet. */ export default function ProviderListCard({ providers }: Props) { diff --git a/frontend/src/pages/DownloadPage/index.tsx b/frontend/src/pages/DownloadPage/index.tsx index 3257079..9e057da 100644 --- a/frontend/src/pages/DownloadPage/index.tsx +++ b/frontend/src/pages/DownloadPage/index.tsx @@ -82,16 +82,16 @@ export default function DownloadPage() { const installSteps: Record = { windows: [{ text: t("download.modal.windows.step1") }], linux: [ - { text: t("download.modal.linux.step1"), code: "chmod +x print-stash-bridge-linux-amd64" }, - { text: t("download.modal.linux.step2"), code: "./print-stash-bridge-linux-amd64" }, + { text: t("download.modal.linux.step1"), code: "chmod +x thingport-bridge-linux-amd64" }, + { text: t("download.modal.linux.step2"), code: "./thingport-bridge-linux-amd64" }, ], macos: [ - { text: t("download.modal.macos.step1"), code: "chmod +x ~/Downloads/print-stash-bridge-macos" }, + { text: t("download.modal.macos.step1"), code: "chmod +x ~/Downloads/thingport-bridge-macos" }, { text: t("download.modal.macos.step2"), - code: "xattr -d com.apple.quarantine ~/Downloads/print-stash-bridge-macos", + code: "xattr -d com.apple.quarantine ~/Downloads/thingport-bridge-macos", }, - { text: t("download.modal.macos.step3"), code: "~/Downloads/print-stash-bridge-macos --install" }, + { text: t("download.modal.macos.step3"), code: "~/Downloads/thingport-bridge-macos --install" }, ], }; diff --git a/frontend/src/pages/ModelDetailPage/Model3DPreviewModal.tsx b/frontend/src/pages/ModelDetailPage/Model3DPreviewModal.tsx index e833803..33d0e71 100644 --- a/frontend/src/pages/ModelDetailPage/Model3DPreviewModal.tsx +++ b/frontend/src/pages/ModelDetailPage/Model3DPreviewModal.tsx @@ -21,7 +21,7 @@ import type { PlateSummary } from "../../utils/bambuThreeMf"; // A neutral, theme-independent canvas -- this is a fixed "product shot" style preview, not part // of the app's light/dark chrome, so it stays the same regardless of the viewer's theme. const PREVIEW_BG = "#e7e7ea"; -// Matches the reference preview's solid red plate color; unrelated to theme.printstash.modelColor. +// Matches the reference preview's solid red plate color; unrelated to theme.thingport.modelColor. const PREVIEW_MODEL_COLOR = "#d32f2f"; type Props = { diff --git a/frontend/src/theme.ts b/frontend/src/theme.ts index 4083b43..ee9d18c 100644 --- a/frontend/src/theme.ts +++ b/frontend/src/theme.ts @@ -7,9 +7,9 @@ export const THEME_IDS: ResolvedTheme[] = ["light", "dark"]; const BODY_FONT_STACK = '"Open Sans", "system-ui", "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif'; -/** The brand/display face used for h5/h6 (page and section titles) and the Wordmark -- kept as - * one exported constant so both stay in sync. */ -export const DISPLAY_FONT_STACK = '"PrintStash Display", sans-serif'; +/** The brand/display face used for h5/h6 (page and section titles) -- kept as one exported + * constant so every usage stays in sync. */ +export const DISPLAY_FONT_STACK = '"Thingport", sans-serif'; /** * Extra design tokens MUI's Theme doesn't model natively: the page background (a plain color @@ -18,7 +18,7 @@ export const DISPLAY_FONT_STACK = '"PrintStash Display", sans-serif'; */ declare module "@mui/material/styles" { interface Theme { - printstash: { + thingport: { pageBackground: string; modelColor: string; modelEmissive: string; @@ -29,7 +29,7 @@ declare module "@mui/material/styles" { }; } interface ThemeOptions { - printstash: { + thingport: { pageBackground: string; modelColor: string; modelEmissive: string; @@ -131,7 +131,7 @@ export function buildTheme(id: ResolvedTheme): Theme { MuiChip: { styleOverrides: { root: { borderRadius: 6 } } }, MuiTooltip: { styleOverrides: { tooltip: { backgroundColor: d.panelStrong, color: d.text } } }, }, - printstash: { + thingport: { pageBackground: d.pageBackground, modelColor: d.modelColor, modelEmissive: d.modelEmissive, diff --git a/frontend/src/utils/auth.ts b/frontend/src/utils/auth.ts index 7b9c00c..27b3f3e 100644 --- a/frontend/src/utils/auth.ts +++ b/frontend/src/utils/auth.ts @@ -1,7 +1,7 @@ import type { AuthUser } from "../api/auth"; -const TOKEN_KEY = "printstash_auth_token"; -const USER_KEY = "printstash_auth_user"; +const TOKEN_KEY = "thingport_auth_token"; +const USER_KEY = "thingport_auth_user"; function getStorage(): Storage | null { if (typeof window === "undefined") return null; diff --git a/frontend/src/utils/bambuThreeMf.ts b/frontend/src/utils/bambuThreeMf.ts index a45fb9e..b2e767b 100644 --- a/frontend/src/utils/bambuThreeMf.ts +++ b/frontend/src/utils/bambuThreeMf.ts @@ -1,12 +1,12 @@ // A Bambu Studio project .3mf is a zip: 3D/3dmodel.model holds elements (either an // inline or references to per-object files under 3D/Objects/) // and a section placing objects on the bed; Metadata/model_settings.config assigns each -// object to a "plate" (one page of the Bambu Studio build-plate UI, not a PrintStash Plate row -- +// object to a "plate" (one page of the Bambu Studio build-plate UI, not a Thingport Plate row -- // a single imported/uploaded 3MF here always stays one Plate, its internal plates are a purely // client-side rendering/browsing concept) and to a filament/extruder index; Metadata/ // project_settings.config carries the filament_colour palette. The coordinate swap in // createGeometryFromMesh below is kept identical to the original (a Y/Z swap with no sign flip) -- -// PrintStash's own STL/OBJ/STEP loaders use a rotateX(-90deg) instead, which is not the same +// Thingport's own STL/OBJ/STEP loaders use a rotateX(-90deg) instead, which is not the same // transform (it negates one axis), so callers must not apply that rotation to this loader's output. import * as THREE from "three"; import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js"; @@ -475,11 +475,11 @@ export async function loadCachedBambuGlb(url: string): Promise { - if (!root && typeof obj.userData?.printstashPreview === "string") root = obj; + if (!root && typeof obj.userData?.thingportPreview === "string") root = obj; }); if (!root) return null; - const meta = JSON.parse((root as THREE.Object3D).userData.printstashPreview) as { + const meta = JSON.parse((root as THREE.Object3D).userData.thingportPreview) as { plates: PlateSummary[]; plateThumbnails: Record; filamentColors: string[]; diff --git a/frontend/src/utils/modelLoaders.ts b/frontend/src/utils/modelLoaders.ts index 3402cb1..57b6b09 100644 --- a/frontend/src/utils/modelLoaders.ts +++ b/frontend/src/utils/modelLoaders.ts @@ -21,14 +21,14 @@ export type ModelPalette = { // and from generateModelSnapshot(), which runs off the React tree entirely) so it reads its // colors straight from theme.ts's buildTheme() rather than via useTheme() -- there's no guarantee // a component-level ThemeProvider is mounted above every caller, and threading the resolved -// theme.printstash values through as extra params would ripple through every call site for no +// theme.thingport values through as extra params would ripple through every call site for no // benefit since ResolvedTheme -> Theme is already a pure, cheap lookup. function toFloat32(data: ArrayLike): Float32Array { return Float32Array.from(data); } export function paletteForTheme(theme: ResolvedTheme): ModelPalette { - const { modelColor, modelEmissive } = buildTheme(theme).printstash; + const { modelColor, modelEmissive } = buildTheme(theme).thingport; return { color: new THREE.Color(modelColor), emissive: new THREE.Color(modelEmissive), diff --git a/frontend/src/utils/settings.ts b/frontend/src/utils/settings.ts index 839c63c..3397885 100644 --- a/frontend/src/utils/settings.ts +++ b/frontend/src/utils/settings.ts @@ -13,7 +13,7 @@ export type AppSettings = { makerworld: MakerWorldSettings; }; -const STORAGE_KEY = "printstash_settings"; +const STORAGE_KEY = "thingport_settings"; const DEFAULT_SETTINGS: AppSettings = { theme: { diff --git a/frontend/src/utils/slicerLaunch.ts b/frontend/src/utils/slicerLaunch.ts index 62ac798..8204f92 100644 --- a/frontend/src/utils/slicerLaunch.ts +++ b/frontend/src/utils/slicerLaunch.ts @@ -1,16 +1,16 @@ -// The PrintStash Bridge helper app's own protocol (see bridge/README.md) -- it downloads the +// The Thingport Bridge helper app's own protocol (see bridge/README.md) -- it downloads the // file itself and hands it to the local slicer, for slicers whose own URL handler won't take it // directly. -const BRIDGE_SCHEME = "print-stash"; +const BRIDGE_SCHEME = "thingport"; // Bambu Studio's bambustudio:// handler only opens files served from an allowlist of domains it -// trusts (Bambu Lab's own storefronts) -- a self-hosted PrintStash instance is never on it, so +// trusts (Bambu Lab's own storefronts) -- a self-hosted Thingport instance is never on it, so // the direct protocol silently no-ops. Routed through the Bridge instead. OrcaSlicer and // PrusaSlicer accept any HTTP(S) URL through their own handler, so they bypass the Bridge. const BRIDGED_SLICERS = new Set(["bambustudio"]); // Builds the URL that "Open in {Slicer}" navigates to: either the slicer's own registered -// protocol handler (e.g. orcaslicer://), or -- for a BRIDGED_SLICERS id -- the PrintStash Bridge +// protocol handler (e.g. orcaslicer://), or -- for a BRIDGED_SLICERS id -- the Thingport Bridge // protocol, which downloads fileUrl locally before handing it to the slicer. Only meaningful for // the SLICER_OPTIONS ids that register a protocol; never call this for "other". export function slicerLaunchUrl(slicerId: string, fileUrl: string, filename?: string): string { diff --git a/package-lock.json b/package-lock.json index 901ac7b..cd5b040 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,10 +1,10 @@ { - "name": "printstash", + "name": "thingport", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "printstash", + "name": "thingport", "devDependencies": { "husky": "^9.1.7", "lint-staged": "^15.2.10" diff --git a/package.json b/package.json index ffd7adc..6d6a3e5 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "printstash", + "name": "thingport", "private": true, "devDependencies": { "husky": "^9.1.7",