From 9ff36a6aa622460a5da446c07c3ff56f795b570c Mon Sep 17 00:00:00 2001 From: chodeus Date: Wed, 1 Jul 2026 14:16:05 +0800 Subject: [PATCH 1/2] feat(posters): unified, readable CL2K/MM2K provenance stamp The unmatched-assets stamp used low-contrast brand tints (light text on a translucent same-hue background) that were unreadable over bright posters. Replace it with a shared StyleStamp: a dark solid chip with brand-coloured text (CL2K lavender, MM2K gold, white otherwise), used by the unmatched reel and the asset-search grid so the stamp is identical and legible everywhere. --- frontend/src/components/ui/StyleStamp.jsx | 32 +++++++++++++++++++ .../pages/poster/PosterAssetsSearchPage.jsx | 11 +++---- .../src/pages/poster/UnmatchedAssetsPage.jsx | 26 +++++++-------- 3 files changed, 48 insertions(+), 21 deletions(-) create mode 100644 frontend/src/components/ui/StyleStamp.jsx diff --git a/frontend/src/components/ui/StyleStamp.jsx b/frontend/src/components/ui/StyleStamp.jsx new file mode 100644 index 00000000..3751a2ac --- /dev/null +++ b/frontend/src/components/ui/StyleStamp.jsx @@ -0,0 +1,32 @@ +import React from 'react'; + +// Provenance stamp for a poster's build style, overlaid on the poster corner. +// A dark solid chip so it reads over any artwork, with brand-coloured text so +// CL2K / MM2K / other styles stay distinguishable. Shared by the Unmatched, +// Asset Search, and CL2K Maker grids so the stamp is identical everywhere. +// The caller supplies position + text size via `className`. +const STYLE_COLOR = { + CL2K: { text: '#c9bcff', border: 'rgba(135,103,247,0.55)' }, + MM2K: { text: '#ffd257', border: 'rgba(255,201,68,0.5)' }, +}; +const DEFAULT_COLOR = { text: '#ffffff', border: 'rgba(255,255,255,0.25)' }; + +export const StyleStamp = ({ style, className = '' }) => { + if (!style) return null; + const color = STYLE_COLOR[String(style).toUpperCase()] || DEFAULT_COLOR; + return ( + + {style} + + ); +}; + +export default StyleStamp; diff --git a/frontend/src/pages/poster/PosterAssetsSearchPage.jsx b/frontend/src/pages/poster/PosterAssetsSearchPage.jsx index 31622271..dd12e057 100644 --- a/frontend/src/pages/poster/PosterAssetsSearchPage.jsx +++ b/frontend/src/pages/poster/PosterAssetsSearchPage.jsx @@ -10,6 +10,7 @@ import { postersAPI } from '../../utils/api/posters.js'; import { Modal } from '../../components/modals/Modal'; import { Button, LoadingButton, IconButton, Pagination } from '../../components/ui/index.js'; import Spinner from '../../components/ui/Spinner.jsx'; +import { StyleStamp } from '../../components/ui/StyleStamp.jsx'; // Compact "5d ago" relative time for the GDrive last-sync stat. const relTime = ts => { @@ -713,12 +714,10 @@ const PosterAssetsSearchPage = () => { )} {item.style && ( - - {item.style} - + )}
{ to, title, ariaLabel, icon } | null. // Renders an extra per-row action link (e.g. a poster-maker shortcut) when an @@ -46,19 +47,16 @@ const REEL_FILTERS = [ ]; const REEL_PAGE_SIZE = 10; -// CL2K / MM2K are the *built* poster styles whose provenance matters — they -// carry a real author. Other styles (GDrive / local fetches) get no tag. -const BUILT_STYLE_TAG = { - CL2K: ['#a99eff', 'rgba(135,103,247,.32)'], - MM2K: ['#ffc944', 'rgba(255,201,68,.22)'], -}; +// CL2K / MM2K are the *built* poster styles whose provenance matters (they +// carry a real author); other styles (GDrive / local fetches) get no tag. +const BUILT_STYLES = new Set(['CL2K', 'MM2K']); /** A single poster in the reel: thumbnail + (for CL2K/MM2K) a source tag and * the builder it came from. */ const ReelPosterCard = ({ poster }) => { const [failed, setFailed] = useState(false); - const styleTag = BUILT_STYLE_TAG[poster.style]; - const builtBy = styleTag ? poster.folder : null; + const isBuilt = BUILT_STYLES.has(poster.style); + const builtBy = isBuilt ? poster.folder : null; return (
{ onError={() => setFailed(true)} /> )} - {styleTag && ( - - {poster.style} - + {isBuilt && ( + )}

From 28967b8129c6b4a7183c5b8d205a575453e13f4f Mon Sep 17 00:00:00 2001 From: chodeus Date: Wed, 1 Jul 2026 14:16:05 +0800 Subject: [PATCH 2/2] fix(jobs): humanize the job-type label A scheduled profile job showed its raw type 'scheduled:upgradinatorr_profiles'. Drop the trigger prefix (already shown as its own pill) and title-case the rest -> 'Upgradinatorr Profiles'. --- frontend/src/pages/settings/JobsPage.jsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/settings/JobsPage.jsx b/frontend/src/pages/settings/JobsPage.jsx index 58b61498..177c9302 100644 --- a/frontend/src/pages/settings/JobsPage.jsx +++ b/frontend/src/pages/settings/JobsPage.jsx @@ -26,6 +26,15 @@ const TRIGGER_STYLE = { const triggerOf = job => job.trigger || (job.type === 'webhook' || job.job_type === 'webhook' ? 'webhook' : 'manual'); +// A job type can carry a trigger prefix (e.g. "scheduled:upgradinatorr_profiles"). +// The trigger is already shown as its own pill, so drop the prefix and humanize. +const prettyType = raw => { + if (!raw) return '-'; + const s = String(raw); + const name = s.includes(':') ? s.split(':').pop() : s; + return name.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()); +}; + // Status-dot colour for the table's STATUS cell. const STATUS_DOT = { pending: 'bg-warning', @@ -421,7 +430,7 @@ export const JobsPage = () => {

{jobs.map(job => { const isOpen = expandedJobId === job.id; - const typeLabel = job.module_name || job.job_type || job.type || '-'; + const typeLabel = prettyType(job.module_name || job.job_type || job.type); return (
{ #{job.id} - {job.module_name || job.job_type || job.type || '-'} + {prettyType( + job.module_name || job.job_type || job.type + )}