feat: Multi-platform link support (App Store / Google Play) + layout fixes#6
feat: Multi-platform link support (App Store / Google Play) + layout fixes#6
Conversation
There was a problem hiding this comment.
Pull request overview
Adds support for apps that provide multiple platform/download links by introducing a “Get” dropdown on the app detail page and a modal-based link picker elsewhere, alongside layout adjustments intended to reduce viewport-width overflow issues.
Changes:
- Add platform-aware link rendering (dropdown on detail page; modal for list/other contexts) and supporting event handlers.
- Update “Get/View” button labeling logic to treat apps with
links(and some categories) as “Get”. - Adjust CSS viewport sizing (
100vw→100%), tweak mobile alignment, and add new styles for dropdown + modal link lists.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| style.css | Reworks width/overflow constraints and adds styles for platform link UI (dropdown + modal link list), plus small mobile alignment tweaks. |
| app.js | Adds platform icon rendering, link dropdown/modal UI, and click/keyboard behaviors for opening/closing platform link pickers. |
Comments suppressed due to low confidence (1)
style.css:105
- Removing
overflow: hiddenfrombodycan introduce a second page-level scrollbar (especially on mobile, where.mobile-topbar+.content-scroll { height: 100vh; }exceed the viewport). If the intent is to fix horizontal overflow from100vw, consider restoringoverflow: hidden(or at leastoverflow-x: hidden) and/or adjusting the scroll container height (e.g.,calc(100vh - var(--mobile-topbar-height))) so scrolling remains confined to.content-scroll.
body {
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Helvetica Neue", Arial, sans-serif;
background: var(--bg-primary);
color: var(--text-primary);
height: 100vh;
width: 100%;
user-select: none;
transition: background 0.3s ease, color 0.3s ease;
overflow-wrap: break-word;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
This PR adds support for apps that have multiple platform-specific outbound links (e.g., iOS/Android/Web) by introducing a “Get” dropdown on the app detail page and a links modal for other contexts, along with layout/CSS tweaks to reduce horizontal overflow.
Changes:
- Add HTML escaping and URL sanitization helpers, plus platform icon rendering, and wire them into new links UI.
- Introduce a “Get” dropdown on the app detail page when
app.linksis present, and a modal to show platform links elsewhere. - Update CSS to prefer
100%widths over100vwand add styling for the new dropdown and modal link list.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| style.css | Adjusts width/overflow behavior and adds styles for the platform links modal and detail-page Get dropdown. |
| app.js | Adds sanitization helpers and implements the multi-link Get dropdown + links modal behavior and event handling. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Adds support for multi-platform “Get” links (dropdown on detail view + modal elsewhere) and adjusts layout styles to reduce viewport-based overflow issues.
Changes:
- Introduces HTML escaping + URL sanitization helpers and applies them to newly-rendered link UI.
- Adds platform link dropdown (detail page) and a modal listing platform links (non-detail contexts).
- Replaces several
100vw/overflow: hiddenlayout constraints with100%sizing and adds a small mobile alignment tweak.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| style.css | Updates viewport sizing/overflow rules and adds styles for the new platform-links modal and detail-page Get dropdown. |
| app.js | Adds escaping/sanitization helpers, platform icon rendering, and link dropdown/modal behavior wired into the existing Get button flow. |
Comments suppressed due to low confidence (1)
app.js:754
- Now that
sanitizeUrl()exists and is used forapp.links, the remaining URL usages in this click handler still callwindow.open()with raw values fromapps.json(app.homepage/app.github). For defense-in-depth (and consistency), route these throughsanitizeUrl()as well (and consider skippingwindow.openif sanitization fails, rather than navigating to#).
} else if (app.brew || app.installCommand) {
showBrewModal(app);
} else if (app.homepage) {
window.open(app.homepage, "_blank");
} else {
window.open(app.github, "_blank");
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…-haspopup attribute
|
@f can you review? Thanks. |
Multi-platform link support (App Store / Google Play) + layout fixes
Closes #5
Summary
Adds optional
linksarray support to app entries, enabling mobile apps to expose multiple store links (App Store, Google Play, or any external URL) without duplicating app records. All changes are fully backward-compatible — existing app entries withoutlinksare unaffected.Changes
app.jsNew:
platformIcon(platform)Returns an SVG icon for
"ios"(Apple),"android"(robot), or a generic external-link icon for anything else.New:
escapeHtml(str)/sanitizeUrl(url)/sanitizeIconContainerStyle(attrStr)Security helpers added at module scope.
escapeHtmlHTML-encodes user-controlled strings before injection intoinnerHTML.sanitizeUrlvalidates that a URL useshttp:orhttps:before rendering it as anhref, blockingjavascript:and other unsafe schemes.sanitizeIconContainerStyle(local toshowLinksModal) strips",',<,>from inline style attribute values to prevent attribute injection.Updated:
getButtonLabel(app)Returns
"Get"whenapp.linksis present, or when the app's category includesgames/entertainment. Previous logic (brew / downloadUrl / installCommand) is preserved.New:
showLinksModal(app)Opens a platform-selection modal when a "Get" button is clicked on an app row or featured banner. Uses the existing
#modalOverlay/closeModal()infrastructure. Displays the app icon, name, and a list of platform links with icons and a chevron.Updated:
renderAppDetail(app)When
app.linksis present and the app is not paid, wraps the "Get" button in aget-dropdown-wrapperand appends an animatedget-dropdownpanel listing each platform link (withescapeHtml/sanitizeUrlapplied). The toggle button includesaria-expandedandaria-controlsfor accessibility.app.nameandapp.subtitleare also passed throughescapeHtml. Paid apps withlinksfall through to the normal buy-button flow. Falls back to the original single button whenlinksis absent.Updated:
bindEvents()Get-button click priority order:
showBuyModal(unchanged)app.links(non-paid) + detail page → toggle dropdownapp.links(non-paid) + list / featured →showLinksModalshowBrewModal(unchanged)Updated:
bindKeyboard()/ outside-click handlerEscapekey now also closes any open dropdown and resetsaria-expandedtofalse. Added adocument.clicklistener that closes open dropdowns and resetsaria-expandedwhen clicking outside.get-dropdown-wrapper.style.cssLayout fixes
body { overflow: hidden; width: 100vw }overflowremoved,width: 100%.app-store { overflow: hidden; max-width: 100vw }max-width: 100%@600pxsection group hadoverflow: hidden@600px .content-scroll { max-width: 100vw }max-width: 100%@600px .app-detail-actionsjustify-content: centerNew CSS classes
.modal-platform-links.modal-platform-link.modal-platform-icon/.modal-platform-label/.modal-platform-chevron.get-dropdown-wrapper.get-dropdown.get-dropdown.open.get-dropdown-item.get-dropdown-icon/.get-dropdown-label/.get-dropdown-arrowapps.jsonusageNo existing fields are modified. Add the optional
linksarray to any app entry:Supported
platformvalues:"ios","android", or any string (falls back to external-link icon).Behavior overview
linksabsentlinkspresent