Skip to content

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
mainfrom
docs/explore-popup-redesign
Open

Explore: rebuild as a product directory, with a one-screen fit and a cross-platform path fix#186
JG2547 wants to merge 4 commits into
mainfrom
docs/explore-popup-redesign

Conversation

@JG2547

@JG2547 JG2547 commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Closes #185

Verification below was rerun from the exact current head 50584b49c76fdd103c95bc8f62395f365f6b1938. Earlier results in this thread described head 321489f… and e4ab91d… and no longer describe the branch — in particular assets/explore/fixer-hero.png no longer exists, and the assertion count is 883, not 879.

What this is

The Explore panel was a flat link list with an orphaned half-width cell, App page placeholder 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.

Vertical scroll at default size none
Horizontal scroll none, at any size
Destinations visible at once all 8
Last row clearance above the modal border ≥14px
Clipped content none — nothing hidden behind overflow: hidden

Smaller 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 an id, and the id→URL map lives in trusted main-process code.

# Name Description Category URL
1 1132 Fixer Project website featured https://1132-fixer.xyz/
2 Botify Network Network home organizations https://botify-network.com/
3 Prime Hosting Hosting and developer services organizations https://primehosting.dev/
4 GIF Directory Organize and discover GIFs organizations https://gif.directory/
5 BotifyKickBot Moderation bot bots .../apps/botifykickbot
6 BotifyModBot Community management bot bots .../apps/botifymodbot
7 Emoji Generator Create custom emoji creative-tools .../apps/emoji-generator-bot
8 Make It GIF Create and convert GIFs creative-tools .../apps/makeitgif

Prime Hosting is the only URL added, allowlisted as an exact host*.primehosting.dev is 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/more category, no App page copy. The independence line moved inside the hero. Open Source is a status badge, not a control.

Assets — as they exist at 50584b49

Verified with md5sum against the tree and against the packaged app.asar:

Repository path md5 Source
assets/logo-transparent.png c587e6e8… managed brand export, already in .brand-assets.tsv
assets/explore/make-it-gif.png 1d962830… issue #185 attachment ddbe632e… (1254×1254)
assets/explore/gif-directory.png 05c42c94… issue #185 attachment c09edba9… (512×512)
assets/explore/prime-hosting.png c7b6e8c7… issue #185 attachment dfe552b5… (1290×1500)

There is no assets/explore/fixer-hero.png. An earlier revision added one — a 256px downscale of assets/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.tsv exists 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 no overflow: 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 test failed on main before this branch, on dialog MSI path accepted. A real bug, not a stale assertion.

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 test proving this guard works could only pass on Windows, so on Linux CI the guard was effectively unverified.

Pinned to path.win32 with an explicit isAbsolute requirement so resolve() cannot join a relative input onto the process cwd. Windows behaviour unchanged. The original assertion was not relaxed; four were added:

  • a Windows path keeps its win32 form on every host
  • C:\Users\Public\..\Zoom.msi normalises to C:\Users\Zoom.msi
  • a relative path is refused
  • forward slashes are accepted as win32 separators

NTFS-ADS, wrong-extension and control-character rejections all still hold.

Verification — rerun from 50584b49

Command Exit Result
npm test 0 883 assertions, 0 failures (exit 1 on clean main)
npx electron-builder --win dir --x64 --publish never 0 dist/win-unpacked produced
node tools/explore-package-smoke.js 0 all 8 icons byte-identical inside app.asar, case-exact
node tools/explore-capture.js 0 5 viewports, all layout assertions
node tools/explore-capture.js --root <extracted app.asar> 0 packaged files render identically

tools/explore-capture.js asserts 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, no overflow: hidden hiding content, exactly one launch per click, Escape closing, focus returning to the trigger, and a focus ring measured under a genuine Tab (:focus-visible does 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-assets green at 50584b49
  • Code Quality green at 50584b49
  • Support Service green at 50584b49
  • Build & Test green at 50584b49
  • Code-owner approval of the latest push — ruleset requires 1 approving review, code-owner review, and approval of the last push. No reviews submitted.
  • Windows packaged-application acceptance proof — build from this exact head, launch the packaged .exe on Windows, open Explore, capture the real 828×630 modal, and record Windows version, scaling, package filename, artifact SHA-256, source commit and screenshot location.
  • Mergeability remeasured immediately before merge, with the head SHA unchanged since approval

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 extracted app.asar — with only window.electronAPI mocked. That is useful, and it is not the same as launching the shipped executable. The packaged binary is a Windows .exe and cannot run on this Linux build host. Not restating this as out of scope.

Screenshots

artifacts/explore/ (worktree) and artifacts/explore-packaged/ (rendered from the packaged app's own files):
01 default 828×630 · 02 wide 1280×900 · 03 standard 760×600 · 04 125% · 05 150% · 06/07 keyboard focus · 08/09 card-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

…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>
claude added 2 commits August 25, 2026 23:56
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Redesign Explore popup: centered 1132 hero with no clipping or scrolling

3 participants