Explore: rebuild as a product directory, with a one-screen fit and a cross-platform path fix - #186
Open
JG2547 wants to merge 4 commits into
Open
Explore: rebuild as a product directory, with a one-screen fit and a cross-platform path fix#186JG2547 wants to merge 4 commits into
JG2547 wants to merge 4 commits into
Conversation
…s-platform path bug Closes #185 EXPLORE REDESIGN 1132 Fixer is the subject of this panel, so it stops being the first cell of a grid and becomes the panel's headline: full-width featured surface, centred logo and title, the largest product name, and one primary action. Everything below it is the network around it, grouped by purpose. - Destination model consolidated into one catalog (id/name/description/ category/icon/accent/featured) plus one category list. Category order IS render order IS focus order, from a single list, so the three cannot drift apart. URLs deliberately stay out of the renderer's model: it only ever sends an id, and the id->URL map stays in trusted main-process code. - Prime Hosting added (https://primehosting.dev/), allowlisted as an exact host - *.primehosting.dev is not reachable. Every other URL unchanged. - GIF Directory is now an organisation and discovery utility. No "other" or "more" category, and no "App page" placeholder copy remains. - The independence line moved INSIDE the 1132 Fixer hero. As a panel footer it read as a statement about every product listed, including ones this project does not own and cannot speak for. - "Open Source" is a status badge, not a control: there is no separate open-source destination, so it must not look like it goes somewhere. - One reusable card component with three accent variants, replacing the duplicated markup that produced the orphaned half-width cell. ONE-SCREEN CONTRACT The Explore modal gets ~828x630 logical pixels at 100% scaling, and the whole panel now fits it: header, hero, three category rows, all eight destinations, complete bottom padding and border, no scrollbar, nothing clipped, last row clearing the bottom border by >=14px. Smaller windows and 125%/150% scaling scroll the body rather than clipping. Getting there meant the hero becomes a centred HORIZONTAL group on a short viewport - logo beside the name rather than above it. It stays the largest, boldest, centred element; it just stops being dominant by consuming half the panel. Breakpoints are content-driven: 820px is where an organisation column stays wide enough to read. CROSS-PLATFORM PATH BUG (pre-existing, now fixed) isSafeUserSelectedPath validates a WINDOWS path but parsed it with the ambient path module. Under POSIX a backslash is an ordinary filename character, so path.basename('C:\Users\Public\x.msi') returned the whole string, which contains ':' and '\' and was refused as an illegal basename. Every legitimate installer path was rejected off-Windows, and the security smoke test proving this guard works could not pass anywhere except Windows - so on Linux CI the guard was effectively unverified. Parsing is now pinned to path.win32, with an explicit isAbsolute check so resolve() cannot silently join a relative input onto the process cwd. Behaviour on Windows is unchanged. The original assertion was NOT relaxed; four more were added around it. VERIFICATION npm test exit 0, 879 assertions, 0 fail node tools/explore-capture.js exit 0, 5 viewports node tools/explore-capture.js --root <app.asar> exit 0, packaged files render identically npx electron-builder --win dir --x64 exit 0 node tools/explore-package-smoke.js exit 0, 8 icons byte-identical in app.asar The three supplied logos come from issue #185's own attachments; Prime Hosting is byte-identical to the copy published on primehosting.dev. fixer-hero.png exists because assets/1132-fixer-logo-transparent.png is on the build.files EXCLUDE list - referencing it would have shipped a hero with no logo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…atalog id Carried over from #180, which this PR otherwise supersedes. The click wiring resolves whatever is in data-explore, so checking that the SELECTOR looks right proves nothing on its own - an unchecked interpolation behind a checked selector is a guard that reads well and catches nothing. This asserts the property that matters: data-explore is set from a fixed catalog id in both the secondary cards and the hero button, and from nothing else. The main process re-validates the key regardless. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…pping the brand guard The brand-assets check failed on this branch. Two causes, both real. 1. THE HERO WAS A DERIVED COPY. assets/explore/fixer-hero.png was a 256px downscale of assets/1132-fixer-logo-transparent.png, created because that file is on the build.files EXCLUDE list and would not have shipped. But a downscaled duplicate of a managed brand asset packages fine and then silently drifts the day the design system updates the logo - which is precisely the failure .brand-assets.tsv exists to catch. assets/logo-transparent.png is the same 1132 Fixer mark at 256x256, is already listed in .brand-assets.tsv as a managed export, and already ships. The hero now uses it. The derived copy is deleted, so there is no second source of truth to drift, and no packaging exclusion to work around. Guarded: the featured icon must be assets/logo-transparent.png AND that path must appear as a managed shipped path in .brand-assets.tsv, so a future edit cannot quietly reintroduce a derived copy. 2. TWO CAPTURES WERE NAMED LIKE BRAND ARTWORK. 08-logos-organizations.png and 09-logos-creative-tools.png were flagged as unmanaged possible brand assets. They are QA captures of rendered card rows, not artwork - registering them in .brand-assets.tsv would assert something false. They are renamed for the row they show: 08-organizations-row.png and 09-creative-tools-row.png. npm test exit 0, 883 assertions. electron-builder --win dir exit 0. Both capture runs (worktree and packaged app.asar) exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…nder Unreleased Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
patricktobias86
approved these changes
Aug 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #185
What this is
The Explore panel was a flat link list with an orphaned half-width cell,
App pageplaceholder copy, generic globes for two products, and a footer disclaimer that read as a statement about every product listed. It is now a product directory with one hierarchy.1132 Fixer is the subject of this panel — full-width featured surface, centred logo and title, the largest product name, one primary action. Everything below is the network around it, grouped by purpose.
The one-screen contract
The Explore modal gets 828×630 logical pixels at 100% scaling.
overflow: hiddenSmaller windows and 125%/150% scaling scroll the body rather than clipping; header, close control and every destination stay reachable.
On a short viewport the hero becomes a centred horizontal group — logo beside the name rather than above it. It stays the largest, boldest, centred element; it just stops being dominant by consuming half the height. Breakpoints are content-driven: 820px is where an organization column stays wide enough to read.
Destinations
One catalog (
EXPLORE_VIEW) plus one category list. Category order is render order is focus order. URLs stay out of the renderer's model — it sends anid, and the id→URL map lives in trusted main-process code.https://1132-fixer.xyz/https://botify-network.com/https://primehosting.dev/https://gif.directory/.../apps/botifykickbot.../apps/botifymodbot.../apps/emoji-generator-bot.../apps/makeitgifPrime Hosting is the only URL added, allowlisted as an exact host —
*.primehosting.devis not reachable. Every other URL is unchanged and the security smoke test pins the whole table.GIF Directory is an organization and discovery utility. No
other/morecategory, noApp pagecopy. The independence line moved inside the hero.Open Sourceis a status badge, not a control.Assets — as they exist at
50584b49Verified with
md5sumagainst the tree and against the packagedapp.asar:assets/logo-transparent.pngc587e6e8….brand-assets.tsvassets/explore/make-it-gif.png1d962830…ddbe632e…(1254×1254)assets/explore/gif-directory.png05c42c94…c09edba9…(512×512)assets/explore/prime-hosting.pngc7b6e8c7…dfe552b5…(1290×1500)There is no
assets/explore/fixer-hero.png. An earlier revision added one — a 256px downscale ofassets/1132-fixer-logo-transparent.png— and it was removed. A derived copy of a managed brand asset packages fine and then silently drifts the day the design system updates the logo, which is exactly what.brand-assets.tsvexists to catch. The hero now uses the managed export, and a guard pins that so a derived copy cannot return.Transparency and aspect ratio preserved,
object-fit: contain, no mask and nooverflow: hidden— the Make It GIF circle keeps its outer ring and the Prime Hosting hexagon keeps its points.Cross-platform path bug — pre-existing, fixed here
npm testfailed onmainbefore this branch, ondialog MSI path accepted. A real bug, not a stale assertion.isSafeUserSelectedPathvalidates a Windows path but parsed it with the ambientpathmodule. Under POSIX a backslash is an ordinary filename character, sopath.basename('C:\Users\Public\x.msi')returned the whole string — which contains:and\and was refused as an illegal basename. Every legitimate installer path was rejected off-Windows, and the test proving this guard works could only pass on Windows, so on Linux CI the guard was effectively unverified.Pinned to
path.win32with an explicitisAbsoluterequirement soresolve()cannot join a relative input onto the process cwd. Windows behaviour unchanged. The original assertion was not relaxed; four were added:C:\Users\Public\..\Zoom.msinormalises toC:\Users\Zoom.msiNTFS-ADS, wrong-extension and control-character rejections all still hold.
Verification — rerun from
50584b49npm testmain)npx electron-builder --win dir --x64 --publish neverdist/win-unpackedproducednode tools/explore-package-smoke.jsapp.asar, case-exactnode tools/explore-capture.jsnode tools/explore-capture.js --root <extracted app.asar>tools/explore-capture.jsasserts the contract rather than just taking pictures: destination order, hero centring, hero title larger than any card title, equal column widths and heights per row, every card box inside the dialog box, last-row clearance, nooverflow: hiddenhiding content, exactly one launch per click, Escape closing, focus returning to the trigger, and a focus ring measured under a genuineTab(:focus-visibledoes not match a programmatic.focus()).Windows display scaling is emulated by shrinking the CSS viewport, not by raising the device pixel ratio — DPR alone renders the identical layout at higher resolution and proves nothing about clipping.
⛔ Blocked — do not merge yet
Per the durable required-check rule, every required project verification is a blocker, not just the one named status context.
brand-assetsgreen at50584b49Code Qualitygreen at50584b49Support Servicegreen at50584b49Build & Testgreen at50584b49.exeon Windows, open Explore, capture the real 828×630 modal, and record Windows version, scaling, package filename, artifact SHA-256, source commit and screenshot location.The Windows proof is genuinely outstanding. The captures in
artifacts/are headless-Chromium renders of the real page files — from both the worktree and the extractedapp.asar— with onlywindow.electronAPImocked. That is useful, and it is not the same as launching the shipped executable. The packaged binary is a Windows.exeand cannot run on this Linux build host. Not restating this as out of scope.Screenshots
artifacts/explore/(worktree) andartifacts/explore-packaged/(rendered from the packaged app's own files):01default 828×630 ·02wide 1280×900 ·03standard 760×600 ·04125% ·05150% ·06/07keyboard focus ·08/09card-row close-ups.Scope
Explore panel, its destination model, its assets, the tests, and the path-validation fix that was blocking the suite. The Repair wizard and other screens are untouched. The product remains named 1132 Fixer — no rebrand.
🤖 Generated with Claude Code