Search-first profile library: tiers, native games, derived descriptions#18
Merged
Conversation
.secondary-action is redefined with width: 100%, so in the library entry's flex row the Install button claimed the full width and, being flex-shrink: 0, could not give any back. The copy column has min-width: 0, so it collapsed to roughly one character and the description rendered one letter per line. Override the button to width: auto so it sizes to its content. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The library rendered every profile as a flat list with no way to find a game, no way to say a game needs no profile, and free-text descriptions that could claim effects a profile did not have. Search filters the list in place. Each row now carries a status: Verified, Community, or Native. Native games come from a new native.json published beside the index -- native support is a property of the game, not a profile tier, so it does not live on the profile. Descriptions are split in two: the author writes one sentence of intent, and the capability line is derived from the profile itself by describeCapabilities(), a pure shared function. build-index.mjs bakes that line into index.json using the same code the app uses, so the line cannot drift from the profile, and the app describes a profile without downloading it. When weapon variants land in the schema, ported mods advertise them with no change here. An absent or malformed tier coerces to community: an unlabelled profile must never present itself as maintainer-verified. A malformed origin is dropped rather than dropping the entry, and a failed native.json degrades to no native tags rather than failing the library. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Every native row headlined "Native support", so the bold text carried no information while the game name sat in a small eyebrow above it. The library is browsed by game, so the game is now the heading on both row kinds and the profile name moves beside the author. Drops the eyebrow and its now-unused rule. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Installing recorded nothing about where a profile came from, so the library could not tell an installed profile from an uninstalled one, and there was no way back to the published version after editing. Record meta.libraryFile on install. The library then shows "Installed" instead of an Install button, and the editor offers Reset for profiles that came from the library. Reset overwrites the profile in place via resetToLibrary(), keeping its id and name. Routing it through importProfile() would have taken the uniqueName path and left the edited profile untouched beside a new "Name (2)" -- a reinstall, not a reset. It is behind a confirm dialog because it discards local edits. libraryFile is validated against the library's own file-name pattern: it is interpolated into the fetch URL on reset, so a saved profile must not be able to smuggle a path through it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Import sat in the profile strip while Export sat above the editor, so the two halves of the same operation were in different places. Move Import beside Export. Both now carry .trigger-profiles-transfer-button. .secondary-action sizes buttons full-width at --action-height for the large test-card actions, which is why Export towered over the toolbar controls; these are toolbar-scale, so they match the strip buttons (32px, 12px) instead. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
.feature-card-title is a three-column grid. Adding Import as a sixth loose child pushed the row past the template, so Export wrapped out of sight. Group the match source and all three buttons into a single grid cell. Save then wrapped to its own line as a full-width bar: .primary-action, like .secondary-action, is width: 100% for the large test-card actions. Size it to its content in this row. Import and Export also had their icons the wrong way round -- Import showed the outbound arrow and Export the inbound one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces the 14 titles I picked from memory with the wiki's own data, queried from the Cargo table behind the DualSense list. Filtered on DualSense_adaptive_trigger_support, not the page's general Playstation_controller_support column: the latter marks 965 games as supporting the controller in some way, most of which do nothing with the triggers. Tagging those Native would tell users no profile is needed for games whose triggers are inert. The trigger-specific field yields 136. Kept true (native) and limited (limited native); dropped hackable, which the wiki renders as "requires manual fix". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Why
The profile library rendered every profile as a flat list. It had three problems:
.secondary-actionis redefined withwidth: 100%; in the entry's flex row the Install button claimed the whole width and, beingflex-shrink: 0, gave none back — collapsing the copy column to roughly one character, so descriptions rendered one letter per line.What changed
Search-first library. A search box filters the list in place (option B of four mockups). With an empty query it shows profiles only — listing the 136-game native list would reintroduce the scrolling the search exists to remove.
Status tiers. Each row carries
Verified,Community, orNative. Native support is a property of the game, not a profile tier, so it lives in a newnative.jsonpublished beside the index — 136 games sourced from PCGamingWiki'sDualSense_adaptive_trigger_supportfield (native + limited-native; "requires manual fix" excluded).Derived descriptions. The author writes one sentence of intent; the capability line (
L2 multi-zone · R2 slope · 2 modifiers) is derived from the profile bydescribeCapabilities(), a pure shared function.build-index.mjsbakes it intoindex.jsonusing the same code the app runs, so it cannot drift from the profile — and the app describes a profile without downloading it. When weapon variants land in the schema, ported mods will advertise them with no change here.Installed / Reset. Installs now record
meta.libraryFile. The library shows "Installed" instead of an Install button, and the editor offers Reset, which overwrites the profile in place. Routing a reset throughimportProfile()would take theuniqueNamepath and leave the edited profile beside a new "Name (2)" — a reinstall, not a reset.Editor header. Import moved beside Export at matching size, and both icons were the wrong way round.
.feature-card-titleis a three-column grid, so the header's actions now share one cell; loose buttons overflowed onto an implicit row and pushed Export out of sight.Safety
tiercoerces tocommunity— an unlabelled profile must never present itself as maintainer-verified.originis dropped rather than dropping the entry.native.jsondegrades to no native tags rather than failing the library.meta.libraryFileis validated against the library's file-name pattern: it is interpolated into the fetch URL on reset, so a saved profile must not be able to smuggle a path through it.Verification
index.jsonand all 136 native games.🤖 Generated with Claude Code